Skip to content

Commit

Permalink
Add a way to fetch the functions for a given event on a router (#134)
Browse files Browse the repository at this point in the history
  • Loading branch information
dhruvmanila committed Nov 20, 2020
1 parent 27c104d commit 63250a5
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 12 deletions.
2 changes: 1 addition & 1 deletion docs/abc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ experimental APIs without issue.
For this situation, you can pass ``data=b""``.


.. versionchanged:: 4.12
.. versionchanged:: 4.2.0
Added *content_type*.


Expand Down
13 changes: 12 additions & 1 deletion docs/changelog.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
Changelog
=========

5.0.0
-----

- Add :meth:`gidgethub.routing.Router.fetch` for obtaining a frozenset of functions
registered to the router that the event would be called on.
(`Issue #74 <https://github.com/brettcannon/gidgethub/issues/74>`_).
- Make router callback execution order non-deterministic to avoid relying on
registration order.
(`Issue #74 <https://github.com/brettcannon/gidgethub/issues/74>`_).
- Fix mypy errors in ``gidgethub.httpx.GitHubAPI._request``
(`Issue #133 <https://github.com/brettcannon/gidgethub/issues/133>`_).

4.2.0
-----

Expand All @@ -10,7 +22,6 @@ Changelog
by default the data will be parsed as JSON, and the "application/json" content
type will be used. (`Issue #115 <https://github.com/brettcannon/gidgethub/issues/115>`_).


4.1.1
-----

Expand Down
12 changes: 12 additions & 0 deletions docs/routing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,15 @@ in user code.
...
.. method:: fetch(event)

Return a frozenset of asynchronous callbacks registered
to the router that the *event* would be called on. The *event*
argument corresponds to :class:`gidgethub.sansio.Event`.

.. versionadded:: 5.0.0


.. coroutine:: dispatch(event, *args, **kwargs)

Call the appropriate asynchronous callbacks for the *event*.
Expand All @@ -81,3 +90,6 @@ in user code.

.. versionchanged:: 2.4
Added ``*args`` and ``**kwargs``.

.. versionchanged:: 5.0.0
Execution order is non-deterministic.
2 changes: 1 addition & 1 deletion gidgethub/httpx.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ async def _request(
) -> Tuple[int, Mapping[str, str], bytes]:
"""Make an HTTP request."""
response = await self._client.request(
method, url, headers=dict(headers), data=body
method, url, headers=dict(headers), content=body
)
return response.status_code, response.headers, response.content

Expand Down
21 changes: 13 additions & 8 deletions gidgethub/routing.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Any, Awaitable, Callable, Dict, List, Optional
from typing import Any, Awaitable, Callable, Dict, List, FrozenSet

from . import sansio

Expand Down Expand Up @@ -35,7 +35,6 @@ def add(self, func: AsyncCallback, event_type: str, **data_detail: Any) -> None:
key of the data in the event being dispatched.
"""
if len(data_detail) > 1:
msg = ()
raise TypeError(
"dispatching based on data details is only "
"supported up to one level deep; "
Expand All @@ -62,12 +61,12 @@ def decorator(func: AsyncCallback) -> AsyncCallback:

return decorator

async def dispatch(self, event: sansio.Event, *args: Any, **kwargs: Any) -> None:
"""Dispatch an event to all registered function(s)."""

found_callbacks = []
def fetch(self, event: sansio.Event) -> FrozenSet[AsyncCallback]:
"""Return a set of function(s) registered to the router that the event would
be called on."""
found_callbacks = set()
try:
found_callbacks.extend(self._shallow_routes[event.event])
found_callbacks.update(self._shallow_routes[event.event])
except KeyError:
pass
try:
Expand All @@ -79,6 +78,12 @@ async def dispatch(self, event: sansio.Event, *args: Any, **kwargs: Any) -> None
if data_key in event.data:
event_value = event.data[data_key]
if event_value in data_values:
found_callbacks.extend(data_values[event_value])
found_callbacks.update(data_values[event_value])
return frozenset(found_callbacks)

async def dispatch(self, event: sansio.Event, *args: Any, **kwargs: Any) -> None:
"""Dispatch an event to all registered function(s)."""

found_callbacks = self.fetch(event)
for callback in found_callbacks:
await callback(event, *args, **kwargs)
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ dev = ["aiohttp", "black", "coverage[toml]>=5.0.3", "httpx", "mypy", "pytest-cov
"pytest-xdist", "tornado"]
aiohttp = ["aiohttp"]
tornado = ["tornado"]
httpx = ["httpx>=0.11.0"]
httpx = ["httpx>=0.16.1"]

[tool.flit.metadata.urls]
Documentation = "https://gidgethub.readthedocs.io"
Expand Down
43 changes: 43 additions & 0 deletions tests/test_routing.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,46 @@ async def test_router_copy():
await other_router.dispatch(event)
assert deep_callback.called
assert shallow_callback.called


def test_fetch_callbacks():
router = routing.Router()
event = sansio.Event(
{"action": "opened", "count": 42, "status": "completed"},
event="yeah",
delivery_id="1234",
)
callbacks = router.fetch(event)
assert not callbacks # No callbacks registered.

never_called = Callback()
# Wrong event.
router.add(never_called.meth, "nope")
# Wrong event and data detail.
router.add(never_called.meth, "nope", action="new")
# Wrong data detail key.
router.add(never_called.meth, "yeah", never=42)
# Wrong data detail value.
router.add(never_called.meth, "yeah", count=-13)
callbacks = router.fetch(event)
assert not callbacks # No callbacks found.
assert not never_called.called

shallow_registration_1 = Callback()
shallow_registration_2 = Callback()
deep_registration_1 = Callback()
deep_registration_2 = Callback()
router = routing.Router()
router.add(shallow_registration_1.meth, "yeah")
router.add(shallow_registration_2.meth, "nope")
router.add(deep_registration_1.meth, "nope", status="completed")
router.add(deep_registration_2.meth, "yeah", count=42)
callbacks = router.fetch(event)
assert shallow_registration_1.meth in callbacks
assert shallow_registration_2.meth not in callbacks
assert deep_registration_1.meth not in callbacks
assert deep_registration_2.meth in callbacks
assert not shallow_registration_1.called
assert not shallow_registration_2.called
assert not deep_registration_1.called
assert not deep_registration_2.called

0 comments on commit 63250a5

Please sign in to comment.