summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjason kirtland <jek@discorporate.us>2016-08-22 14:53:57 -0700
committerjason kirtland <jek@discorporate.us>2016-08-22 14:53:57 -0700
commitf4c1037f3c361b5fa904d3acec7c74f4172c9b30 (patch)
treeeee7774c9b5aecb45ab4ddca1ba9da688016d206
parent7303d4bf1ab8a339a194d0d1935770bef43c3cca (diff)
downloadblinker-feature/receiver-adapter.tar.gz
Exploratory commit for feedback, adds an async adapter, "send_robust" adapter, and positional call signature adapter.feature/receiver-adapter
-rw-r--r--blinker/_async.py24
-rw-r--r--blinker/playground.py20
-rw-r--r--tests/test_async.py44
3 files changed, 88 insertions, 0 deletions
diff --git a/blinker/_async.py b/blinker/_async.py
new file mode 100644
index 0000000..3bf87d3
--- /dev/null
+++ b/blinker/_async.py
@@ -0,0 +1,24 @@
+import asyncio
+
+from blinker.base import Signal
+
+
+try:
+ schedule = asyncio.ensure_future
+except AttributeError:
+ schedule = asyncio.async
+
+
+@asyncio.coroutine
+def _wrap_plain_value(value):
+ """Pass through a coroutine *value* or wrap a plain value."""
+ if asyncio.iscoroutine(value):
+ value = yield from value
+ return value
+
+
+def send_async(scheduler=schedule):
+ def adapter(receiver, sender, kwargs):
+ result = receiver(sender, **kwargs)
+ return scheduler(_wrap_plain_value(result))
+ return adapter
diff --git a/blinker/playground.py b/blinker/playground.py
new file mode 100644
index 0000000..8ed30fb
--- /dev/null
+++ b/blinker/playground.py
@@ -0,0 +1,20 @@
+import blinker
+
+
+def quash_exceptions(fn, sender, kwargs):
+ """Always call all receivers, collecting values or exceptions."""
+ try:
+ return fn(sender, **kwargs), None
+ except Exception as exc:
+ return None, exc
+
+
+def _adapt_xyz(fn, sender, kwargs):
+ return fn(sender, kwargs['x'], kwargs['y'], kwargs['z'])
+
+class PositionalSignal(blinker.Signal):
+ """Positional send and receive (x, y, z)"""
+ receiver_adapter = staticmethod(_adapt_xyz)
+
+ def send(self, sender, x, y, z):
+ return blinker.Signal.send(self, sender, x=x, y=y, z=z)
diff --git a/tests/test_async.py b/tests/test_async.py
new file mode 100644
index 0000000..fc01838
--- /dev/null
+++ b/tests/test_async.py
@@ -0,0 +1,44 @@
+import asyncio
+
+import blinker
+from blinker._async import send_async
+
+
+def test_send_async():
+ calls = []
+
+ @asyncio.coroutine
+ def receiver_a(sender):
+ calls.append(receiver_a)
+ return 'value a'
+
+ @asyncio.coroutine
+ def receiver_b(sender):
+ calls.append(receiver_b)
+ return 'value b'
+
+ def receiver_c(sender):
+ calls.append(receiver_c)
+ return 'value c'
+
+ sig = blinker.Signal(None, send_async())
+ sig.connect(receiver_a)
+ sig.connect(receiver_b)
+ sig.connect(receiver_c)
+
+ @asyncio.coroutine
+ def collect():
+ return sig.send()
+
+ loop = asyncio.get_event_loop()
+ results = loop.run_until_complete(collect())
+
+ expected = {
+ receiver_a: 'value a',
+ receiver_b: 'value b',
+ receiver_c: 'value c',
+ }
+
+ assert set(calls) == set(expected.keys())
+ collected_results = {v.result() for r, v in results}
+ assert collected_results == set(expected.values())