blinker-1.3/000775 000765 000024 00000000000 12164774263 012735 5ustar00jekstaff000000 000000 blinker-1.3/AUTHORS000664 000765 000024 00000000317 11652154310 013770 0ustar00jekstaff000000 000000 Blinker was originally written by Jason Kirtland. Contributors are: - Jason Kirtland Blinker includes code from Louie, by Patrick K. O'Brien, Mike C. Fletcher, and Matthew R. Scott. blinker-1.3/blinker/000775 000765 000024 00000000000 12164774263 014363 5ustar00jekstaff000000 000000 blinker-1.3/CHANGES000664 000765 000024 00000003050 12164774103 013717 0ustar00jekstaff000000 000000 Blinker Changelog ================= Version 1.3 ----------- Released July 3, 2013 - The global signal stash behind blinker.signal() is now backed by a regular name-to-Signal dictionary. Previously, weak references were held in the mapping and ephermal usage in code like ``signal('foo').connect(...)`` could have surprising program behavior depending on import order of modules. - blinker.Namespace is now built on a regular dict. Use blinker.WeakNamespace for the older, weak-referencing behavior. - Signal.connect('text-sender') uses an alterate hashing strategy to avoid sharp edges in text identity. Version 1.2 ----------- Released October 26, 2011 - Added Signal.receiver_connected and Signal.receiver_disconnected per-Signal signals. - Deprecated the global 'receiver_connected' signal. - Verified Python 3.2 support (no changes needed!) Version 1.1 ----------- Released July 21, 2010 - Added ``@signal.connect_via(sender)`` decorator - Added ``signal.connected_to`` shorthand name for the ``temporarily_connected_to`` context manager. Version 1.0 ----------- Released March 28, 2010 - Python 3.0 and 3.1 compatibility Version 0.9 ----------- Released February 26, 2010 - Added ``Signal.temporarily_connected_to`` context manager - Docs! Sphinx docs, project web site. Version 0.8 ----------- Released February 14, 2010 - Initial release - Extracted from flatland.util.signals - Added Python 2.4 compatibility - Added nearly functional Python 3.1 compatibility (everything except connecting to instance methods seems to work.) blinker-1.3/docs/000775 000765 000024 00000000000 12164774263 013665 5ustar00jekstaff000000 000000 blinker-1.3/LICENSE000664 000765 000024 00000002106 11652154310 013723 0ustar00jekstaff000000 000000 Copyright (c) The Blinker authors and contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. blinker-1.3/PKG-INFO000664 000765 000024 00000007007 12164774263 014036 0ustar00jekstaff000000 000000 Metadata-Version: 1.0 Name: blinker Version: 1.3 Summary: Fast, simple object-to-object and broadcast signaling Home-page: http://discorporate.us/projects/Blinker/ Author: Jason Kirtland Author-email: jek@discorporate.us License: MIT License Description: Blinker ======= Blinker provides a fast dispatching system that allows any number of interested parties to subscribe to events, or "signals". Signal receivers can subscribe to specific senders or receive signals sent by any sender. >>> from blinker import signal >>> started = signal('round-started') >>> def each(round): ... print "Round %s!" % round ... >>> started.connect(each) >>> def round_two(round): ... print "This is round two." ... >>> started.connect(round_two, sender=2) >>> for round in range(1, 4): ... started.send(round) ... Round 1! Round 2! This is round two. Round 3! Requirements ------------ Blinker requires Python 2.4 or higher, Python 3.0 or higher, or Jython 2.5 or higher. Changelog Summary ----------------- 1.3 (July 3, 2013) - The global signal stash behind blinker.signal() is now backed by a regular name-to-Signal dictionary. Previously, weak references were held in the mapping and ephemeral usage in code like ``signal('foo').connect(...)`` could have surprising program behavior depending on import order of modules. - blinker.Namespace is now built on a regular dict. Use blinker.WeakNamespace for the older, weak-referencing behavior. - Signal.connect('text-sender') uses an alternate hashing strategy to avoid sharp edges in text identity. 1.2 (October 26, 2011) - Added Signal.receiver_connected and Signal.receiver_disconnected per-Signal signals. - Deprecated the global 'receiver_connected' signal. - Verified Python 3.2 support (no changes needed!) 1.1 (July 21, 2010) - Added ``@signal.connect_via(sender)`` decorator - Added ``signal.connected_to`` shorthand name for the ``temporarily_connected_to`` context manager. 1.0 (March 28, 2010) - Python 3.x compatibility 0.9 (February 26, 2010) - Sphinx docs, project website - Added ``with a_signal.temporarily_connected_to(receiver): ...`` support Keywords: signal emit events broadcast Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.4 Classifier: Programming Language :: Python :: 2.5 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.0 Classifier: Programming Language :: Python :: 3.1 Classifier: Programming Language :: Python :: 3.2 Classifier: Programming Language :: Python :: 3.3 Classifier: Topic :: Software Development :: Libraries Classifier: Topic :: Utilities blinker-1.3/README000664 000765 000024 00000003617 12164774103 013615 0ustar00jekstaff000000 000000 Blinker ======= Blinker provides a fast dispatching system that allows any number of interested parties to subscribe to events, or "signals". Signal receivers can subscribe to specific senders or receive signals sent by any sender. >>> from blinker import signal >>> started = signal('round-started') >>> def each(round): ... print "Round %s!" % round ... >>> started.connect(each) >>> def round_two(round): ... print "This is round two." ... >>> started.connect(round_two, sender=2) >>> for round in range(1, 4): ... started.send(round) ... Round 1! Round 2! This is round two. Round 3! Requirements ------------ Blinker requires Python 2.4 or higher, Python 3.0 or higher, or Jython 2.5 or higher. Changelog Summary ----------------- 1.3 (July 3, 2013) - The global signal stash behind blinker.signal() is now backed by a regular name-to-Signal dictionary. Previously, weak references were held in the mapping and ephemeral usage in code like ``signal('foo').connect(...)`` could have surprising program behavior depending on import order of modules. - blinker.Namespace is now built on a regular dict. Use blinker.WeakNamespace for the older, weak-referencing behavior. - Signal.connect('text-sender') uses an alternate hashing strategy to avoid sharp edges in text identity. 1.2 (October 26, 2011) - Added Signal.receiver_connected and Signal.receiver_disconnected per-Signal signals. - Deprecated the global 'receiver_connected' signal. - Verified Python 3.2 support (no changes needed!) 1.1 (July 21, 2010) - Added ``@signal.connect_via(sender)`` decorator - Added ``signal.connected_to`` shorthand name for the ``temporarily_connected_to`` context manager. 1.0 (March 28, 2010) - Python 3.x compatibility 0.9 (February 26, 2010) - Sphinx docs, project website - Added ``with a_signal.temporarily_connected_to(receiver): ...`` support blinker-1.3/setup.py000664 000765 000024 00000002530 12164774103 014440 0ustar00jekstaff000000 000000 from distutils.core import setup readme = open('README').read() import blinker version = blinker.__version__ setup(name="blinker", version=version, packages=['blinker'], author='Jason Kirtland', author_email='jek@discorporate.us', description='Fast, simple object-to-object and broadcast signaling', keywords='signal emit events broadcast', long_description=readme, license='MIT License', url='http://discorporate.us/projects/Blinker/', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.4', 'Programming Language :: Python :: 2.5', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.0', 'Programming Language :: Python :: 3.1', 'Programming Language :: Python :: 3.2', 'Programming Language :: Python :: 3.3', 'Topic :: Software Development :: Libraries', 'Topic :: Utilities', ], ) blinker-1.3/tests/000775 000765 000024 00000000000 12164774263 014077 5ustar00jekstaff000000 000000 blinker-1.3/tests/test_context.py000664 000765 000024 00000002065 11652154310 017161 0ustar00jekstaff000000 000000 from __future__ import with_statement from blinker import Signal def test_temp_connection(): sig = Signal() canary = [] receiver = lambda sender: canary.append(sender) sig.send(1) with sig.connected_to(receiver): sig.send(2) sig.send(3) assert canary == [2] assert not sig.receivers def test_temp_connection_for_sender(): sig = Signal() canary = [] receiver = lambda sender: canary.append(sender) with sig.connected_to(receiver, sender=2): sig.send(1) sig.send(2) assert canary == [2] assert not sig.receivers def test_temp_connection_failure(): sig = Signal() canary = [] receiver = lambda sender: canary.append(sender) class Failure(Exception): pass try: sig.send(1) with sig.connected_to(receiver): sig.send(2) raise Failure sig.send(3) except Failure: pass else: raise AssertionError("Context manager did not propagate.") assert canary == [2] assert not sig.receivers blinker-1.3/tests/test_saferef.py000664 000765 000024 00000007263 11652154310 017115 0ustar00jekstaff000000 000000 # extracted from Louie, http://pylouie.org/ # updated for Python 3 # # Copyright (c) 2006 Patrick K. O'Brien, Mike C. Fletcher, # Matthew R. Scott # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # * Neither the name of the nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # import unittest from blinker._saferef import safe_ref class _Sample1(object): def x(self): pass def _sample2(obj): pass class _Sample3(object): def __call__(self, obj): pass class TestSaferef(unittest.TestCase): # XXX: The original tests had a test for closure, and it had an # off-by-one problem, perhaps due to scope issues. It has been # removed from this test suite. def setUp(self): ts = [] ss = [] for x in range(100): t = _Sample1() ts.append(t) s = safe_ref(t.x, self._closure) ss.append(s) ts.append(_sample2) ss.append(safe_ref(_sample2, self._closure)) for x in range(30): t = _Sample3() ts.append(t) s = safe_ref(t, self._closure) ss.append(s) self.ts = ts self.ss = ss self.closure_count = 0 def tearDown(self): if hasattr(self, 'ts'): del self.ts if hasattr(self, 'ss'): del self.ss def test_In(self): """Test the `in` operator for safe references (cmp)""" for t in self.ts[:50]: assert safe_ref(t.x) in self.ss def test_Valid(self): """Test that the references are valid (return instance methods)""" for s in self.ss: assert s() def test_ShortCircuit(self): """Test that creation short-circuits to reuse existing references""" sd = {} for s in self.ss: sd[s] = 1 for t in self.ts: if hasattr(t, 'x'): assert safe_ref(t.x) in sd else: assert safe_ref(t) in sd def test_Representation(self): """Test that the reference object's representation works XXX Doesn't currently check the results, just that no error is raised """ repr(self.ss[-1]) def _closure(self, ref): """Dumb utility mechanism to increment deletion counter""" self.closure_count += 1 blinker-1.3/tests/test_signals.py000664 000765 000024 00000025550 12164774103 017150 0ustar00jekstaff000000 000000 import gc import sys import time import blinker from nose.tools import assert_raises jython = sys.platform.startswith('java') pypy = hasattr(sys, 'pypy_version_info') def collect_acyclic_refs(): # cpython releases these immediately without a collection if jython or pypy: gc.collect() if jython: time.sleep(0.1) class Sentinel(list): """A signal receipt accumulator.""" def make_receiver(self, key): """Return a generic signal receiver function logging as *key* When connected to a signal, appends (key, sender, kw) to the Sentinel. """ def receiver(*sentby, **kw): self.append((key, sentby[0], kw)) receiver.func_name = 'receiver_%s' % key return receiver def test_meta_connect(): sentinel = [] def meta_received(sender, **kw): sentinel.append(dict(kw, sender=sender)) assert not blinker.receiver_connected.receivers blinker.receiver_connected.connect(meta_received) assert not sentinel def receiver(sender, **kw): pass sig = blinker.Signal() sig.connect(receiver) assert sentinel == [dict(sender=sig, receiver_arg=receiver, sender_arg=blinker.ANY, weak_arg=True)] blinker.receiver_connected._clear_state() def _test_signal_signals(sender): sentinel = Sentinel() sig = blinker.Signal() connected = sentinel.make_receiver('receiver_connected') disconnected = sentinel.make_receiver('receiver_disconnected') receiver1 = sentinel.make_receiver('receiver1') receiver2 = sentinel.make_receiver('receiver2') assert not sig.receiver_connected.receivers assert not sig.receiver_disconnected.receivers sig.receiver_connected.connect(connected) sig.receiver_disconnected.connect(disconnected) assert sig.receiver_connected.receivers assert not sentinel for receiver, weak in [(receiver1, True), (receiver2, False)]: sig.connect(receiver, sender=sender, weak=weak) expected = ('receiver_connected', sig, dict(receiver=receiver, sender=sender, weak=weak)) assert sentinel[-1] == expected # disconnect from explicit sender sig.disconnect(receiver1, sender=sender) expected = ('receiver_disconnected', sig, dict(receiver=receiver1, sender=sender)) assert sentinel[-1] == expected # disconnect from ANY and all senders (implicit disconnect signature) sig.disconnect(receiver2) assert sentinel[-1] == ('receiver_disconnected', sig, dict(receiver=receiver2, sender=blinker.ANY)) def test_signal_signals_any_sender(): _test_signal_signals(blinker.ANY) def test_signal_signals_strong_sender(): _test_signal_signals("squiznart") def test_signal_weak_receiver_vanishes(): # non-edge-case path for weak receivers is exercised in the ANY sender # test above. sentinel = Sentinel() sig = blinker.Signal() connected = sentinel.make_receiver('receiver_connected') disconnected = sentinel.make_receiver('receiver_disconnected') receiver1 = sentinel.make_receiver('receiver1') receiver2 = sentinel.make_receiver('receiver2') sig.receiver_connected.connect(connected) sig.receiver_disconnected.connect(disconnected) # explicit disconnect on a weak does emit the signal sig.connect(receiver1, weak=True) sig.disconnect(receiver1) assert len(sentinel) == 2 assert sentinel[-1][2]['receiver'] is receiver1 del sentinel[:] sig.connect(receiver2, weak=True) assert len(sentinel) == 1 del sentinel[:] # holds a ref to receiver2 del receiver2 collect_acyclic_refs() # no disconnect signal is fired assert len(sentinel) == 0 # and everything really is disconnected sig.send('abc') assert len(sentinel) == 0 def test_signal_signals_weak_sender(): sentinel = Sentinel() sig = blinker.Signal() connected = sentinel.make_receiver('receiver_connected') disconnected = sentinel.make_receiver('receiver_disconnected') receiver1 = sentinel.make_receiver('receiver1') receiver2 = sentinel.make_receiver('receiver2') class Sender(object): """A weakref-able object.""" sig.receiver_connected.connect(connected) sig.receiver_disconnected.connect(disconnected) sender1 = Sender() sig.connect(receiver1, sender=sender1, weak=False) # regular disconnect of weak-able sender works fine sig.disconnect(receiver1, sender=sender1) assert len(sentinel) == 2 del sentinel[:] sender2 = Sender() sig.connect(receiver2, sender=sender2, weak=False) # force sender2 to go out of scope del sender2 collect_acyclic_refs() # no disconnect signal is fired assert len(sentinel) == 1 # and everything really is disconnected sig.send('abc') assert len(sentinel) == 1 def test_meta_connect_failure(): def meta_received(sender, **kw): raise TypeError('boom') assert not blinker.receiver_connected.receivers blinker.receiver_connected.connect(meta_received) def receiver(sender, **kw): pass sig = blinker.Signal() assert_raises(TypeError, sig.connect, receiver) assert not sig.receivers assert not sig._by_receiver assert sig._by_sender == {blinker.base.ANY_ID: set()} blinker.receiver_connected._clear_state() def test_weak_namespace(): ns = blinker.WeakNamespace() assert not ns s1 = ns.signal('abc') assert s1 is ns.signal('abc') assert s1 is not ns.signal('def') assert 'abc' in ns collect_acyclic_refs() # weak by default, already out of scope assert 'def' not in ns del s1 collect_acyclic_refs() assert 'abc' not in ns def test_namespace(): ns = blinker.Namespace() assert not ns s1 = ns.signal('abc') assert s1 is ns.signal('abc') assert s1 is not ns.signal('def') assert 'abc' in ns del s1 collect_acyclic_refs() assert 'def' in ns assert 'abc' in ns def test_weak_receiver(): sentinel = [] def received(sender, **kw): sentinel.append(kw) sig = blinker.Signal() # XXX: weirdly, under jython an explicit weak=True causes this test # to fail, leaking a strong ref to the receiver somewhere. # http://bugs.jython.org/issue1586 if jython: sig.connect(received) # weak=True by default. else: sig.connect(received, weak=True) del received collect_acyclic_refs() assert not sentinel sig.send() assert not sentinel assert not sig.receivers values_are_empty_sets_(sig._by_receiver) values_are_empty_sets_(sig._by_sender) def test_strong_receiver(): sentinel = [] def received(sender): sentinel.append(sender) fn_id = id(received) sig = blinker.Signal() sig.connect(received, weak=False) del received collect_acyclic_refs() assert not sentinel sig.send() assert sentinel assert [id(fn) for fn in sig.receivers.values()] == [fn_id] def test_instancemethod_receiver(): sentinel = [] class Receiver(object): def __init__(self, bucket): self.bucket = bucket def received(self, sender): self.bucket.append(sender) receiver = Receiver(sentinel) sig = blinker.Signal() sig.connect(receiver.received) assert not sentinel sig.send() assert sentinel del receiver collect_acyclic_refs() sig.send() assert len(sentinel) == 1 def test_filtered_receiver(): sentinel = [] def received(sender): sentinel.append(sender) sig = blinker.Signal() sig.connect(received, 123) assert not sentinel sig.send() assert not sentinel sig.send(123) assert sentinel == [123] sig.send() assert sentinel == [123] sig.disconnect(received, 123) sig.send(123) assert sentinel == [123] sig.connect(received, 123) sig.send(123) assert sentinel == [123, 123] sig.disconnect(received) sig.send(123) assert sentinel == [123, 123] def test_filtered_receiver_weakref(): sentinel = [] def received(sender): sentinel.append(sender) class Object(object): pass obj = Object() sig = blinker.Signal() sig.connect(received, obj) assert not sentinel sig.send(obj) assert sentinel == [obj] del sentinel[:] del obj collect_acyclic_refs() # general index isn't cleaned up assert sig.receivers # but receiver/sender pairs are values_are_empty_sets_(sig._by_receiver) values_are_empty_sets_(sig._by_sender) def test_decorated_receiver(): sentinel = [] class Object(object): pass obj = Object() sig = blinker.Signal() @sig.connect_via(obj) def receiver(sender, **kw): sentinel.append(kw) assert not sentinel sig.send() assert not sentinel sig.send(1) assert not sentinel sig.send(obj) assert sig.receivers del receiver collect_acyclic_refs() assert sig.receivers def test_no_double_send(): sentinel = [] def received(sender): sentinel.append(sender) sig = blinker.Signal() sig.connect(received, 123) sig.connect(received) assert not sentinel sig.send() assert sentinel == [None] sig.send(123) assert sentinel == [None, 123] sig.send() assert sentinel == [None, 123, None] def test_has_receivers(): received = lambda sender: None sig = blinker.Signal() assert not sig.has_receivers_for(None) assert not sig.has_receivers_for(blinker.ANY) sig.connect(received, 'xyz') assert not sig.has_receivers_for(None) assert not sig.has_receivers_for(blinker.ANY) assert sig.has_receivers_for('xyz') class Object(object): pass o = Object() sig.connect(received, o) assert sig.has_receivers_for(o) del received collect_acyclic_refs() assert not sig.has_receivers_for('xyz') assert list(sig.receivers_for('xyz')) == [] assert list(sig.receivers_for(o)) == [] sig.connect(lambda sender: None, weak=False) assert sig.has_receivers_for('xyz') assert sig.has_receivers_for(o) assert sig.has_receivers_for(None) assert sig.has_receivers_for(blinker.ANY) assert sig.has_receivers_for('xyz') def test_instance_doc(): sig = blinker.Signal(doc='x') assert sig.__doc__ == 'x' sig = blinker.Signal('x') assert sig.__doc__ == 'x' def test_named_blinker(): sig = blinker.NamedSignal('squiznart') assert 'squiznart' in repr(sig) def values_are_empty_sets_(dictionary): for val in dictionary.values(): assert val == set() if sys.version_info < (2, 5): def test_context_manager_warning(): sig = blinker.Signal() receiver = lambda sender: None assert_raises(RuntimeError, sig.connected_to, receiver) blinker-1.3/tests/test_utilities.py000664 000765 000024 00000000712 11652154310 017505 0ustar00jekstaff000000 000000 import pickle from blinker._utilities import symbol def test_symbols(): foo = symbol('foo') assert foo.name == 'foo' assert foo is symbol('foo') bar = symbol('bar') assert foo is not bar assert foo != bar assert not foo == bar assert repr(foo) == 'foo' def test_pickled_symbols(): foo = symbol('foo') for protocol in 0, 1, 2: roundtrip = pickle.loads(pickle.dumps(foo)) assert roundtrip is foo blinker-1.3/docs/html/000775 000765 000024 00000000000 12164774263 014631 5ustar00jekstaff000000 000000 blinker-1.3/docs/source/000775 000765 000024 00000000000 12164774263 015165 5ustar00jekstaff000000 000000 blinker-1.3/docs/text/000775 000765 000024 00000000000 12164774263 014651 5ustar00jekstaff000000 000000 blinker-1.3/docs/text/api.txt000664 000765 000024 00000014604 12164774171 016166 0ustar00jekstaff000000 000000 API Documentation ***************** All public API members can (and should) be imported from "blinker": from blinker import ANY, signal Basic Signals ============= base.ANY = ANY base.receiver_connected = class class blinker.base.Signal(doc=None) A notification emitter. Parameters: **doc** -- optional. If provided, will be assigned to the signal's __doc__ attribute. ANY = ANY An "ANY" convenience synonym, allows "Signal.ANY" without an additional import. receiver_connected Emitted after each "connect()". The signal sender is the signal instance, and the "connect()" arguments are passed through: *receiver*, *sender*, and *weak*. New in version 1.2. receiver_disconnected Emitted after "disconnect()". The sender is the signal instance, and the "disconnect()" arguments are passed through: *receiver* and *sender*. Note, this signal is emitted **only** when "disconnect()" is called explicitly. The disconnect signal can not be emitted by an automatic disconnect (due to a weakly referenced receiver or sender going out of scope), as the receiver and/or sender instances are no longer available for use at the time this signal would be emitted. An alternative approach is available by subscribing to "receiver_connected" and setting up a custom weakref cleanup callback on weak receivers and senders. New in version 1.2. receivers = None A mapping of connected receivers. The values of this mapping are not meaningful outside of the internal "Signal" implementation, however the boolean value of the mapping is useful as an extremely efficient check to see if any receivers are connected to the signal. connect(receiver, sender=ANY, weak=True) Connect *receiver* to signal events sent by *sender*. Parameters: * **receiver** -- A callable. Will be invoked by "send()" with *sender=* as a single positional argument and any **kwargs that were provided to a call to "send()". * **sender** -- Any object or "ANY", defaults to "ANY". Restricts notifications delivered to *receiver* to only those "send()" emissions sent by *sender*. If "ANY", the receiver will always be notified. A *receiver* may be connected to multiple *sender* values on the same Signal through multiple calls to "connect()". * **weak** -- If true, the Signal will hold a weakref to *receiver* and automatically disconnect when *receiver* goes out of scope or is garbage collected. Defaults to True. connect_via(sender, weak=False) Connect the decorated function as a receiver for *sender*. Parameters: * **sender** -- Any object or "ANY". The decorated function will only receive "send()" emissions sent by *sender*. If "ANY", the receiver will always be notified. A function may be decorated multiple times with differing *sender* values. * **weak** -- If true, the Signal will hold a weakref to the decorated function and automatically disconnect when *receiver* goes out of scope or is garbage collected. Unlike "connect()", this defaults to False. The decorated function will be invoked by "send()" with *sender=* as a single positional argument and any **kwargs that were provided to the call to "send()". New in version 1.1. connected_to(*args, **kwds) Execute a block with the signal temporarily connected to *receiver*. Parameters: * **receiver** -- a receiver callable * **sender** -- optional, a sender to filter on This is a context manager for use in the "with" statement. It can be useful in unit tests. *receiver* is connected to the signal for the duration of the "with" block, and will be disconnected automatically when exiting the block: with on_ready.connected_to(receiver): # do stuff on_ready.send(123) New in version 1.1. disconnect(receiver, sender=ANY) Disconnect *receiver* from this signal's events. Parameters: * **receiver** -- a previously "connected" callable * **sender** -- a specific sender to disconnect from, or "ANY" to disconnect from all senders. Defaults to "ANY". has_receivers_for(sender) True if there is probably a receiver for *sender*. Performs an optimistic check only. Does not guarantee that all weakly referenced receivers are still alive. See "receivers_for()" for a stronger search. receivers_for(sender) Iterate all live receivers listening for *sender*. send(*sender, **kwargs) Emit this signal on behalf of *sender*, passing on **kwargs. Returns a list of 2-tuples, pairing receivers with their return value. The ordering of receiver notification is undefined. Parameters: * ***sender** -- Any object or "None". If omitted, synonymous with "None". Only accepts one positional argument. * ****kwargs** -- Data to be sent to receivers. temporarily_connected_to(receiver, sender=ANY) An alias for "connected_to()". Parameters: * **receiver** -- a receiver callable * **sender** -- optional, a sender to filter on New in version 0.9. Changed in version 1.1: Renamed to "connected_to()". "temporarily_connected_to" was deprecated in 1.2 and removed in a subsequent version. Named Signals ============= blinker.base.signal(name, doc=None) Return the "NamedSignal" *name*, creating it if required. Repeated calls to this function will return the same signal object. Signals are created in a global "Namespace". class class blinker.base.NamedSignal(name, doc=None) Bases: "blinker.base.Signal" A named generic notification emitter. name = None The name of this signal. class class blinker.base.Namespace(*args, **kw) Bases: "weakref.WeakValueDictionary" A mapping of signal names to signals. signal(name, doc=None) Return the "NamedSignal" *name*, creating it if required. Repeated calls to this function will return the same signal object. blinker-1.3/docs/text/index.txt000664 000765 000024 00000002046 12164774171 016521 0ustar00jekstaff000000 000000 Blinker Documentation ********************* Blinker provides fast & simple object-to-object and broadcast signaling for Python objects. The core of Blinker is quite small but provides powerful features: * a global registry of named signals * anonymous signals * custom name registries * permanently or temporarily connected receivers * automatically disconnected receivers via weak referencing * sending arbitrary data payloads * collecting return values from signal receivers Requirements ============ Python 2.4 or later; Python 3.0 or later; or Jython 2.5 or later. No other modules are required. License ======= Blinker is provided under the MIT License. Contents ======== * Signals * Decoupling With Named Signals * Subscribing to Signals * Emitting Signals * Subscribing to Specific Senders * Sending and Receiving Data Through Signals * Anonymous Signals * "connect" as a Decorator * Optimizing Signal Sending * Documenting Signals * More * API Documentation * Basic Signals * Named Signalsblinker-1.3/docs/text/signals.txt000664 000765 000024 00000014456 12164774171 017062 0ustar00jekstaff000000 000000 Signals ******* Decoupling With Named Signals ============================= Named signals are created with "signal()": >>> from blinker import signal >>> initialized = signal('initialized') >>> initialized is signal('initialized') True Every call to "signal('name')" returns the same signal object, allowing unconnected parts of code (different modules, plugins, anything) to all use the same signal without requiring any code sharing or special imports. Subscribing to Signals ====================== "Signal.connect()" registers a function to be invoked each time the signal is emitted. Connected functions are always passed the object that caused the signal to be emitted. >>> def subscriber(sender): ... print("Got a signal sent by %r" % sender) ... >>> ready = signal('ready') >>> ready.connect(subscriber) Emitting Signals ================ Code producing events of interest can "Signal.send()" notifications to all connected receivers. Below, a simple "Processor" class emits a "ready" signal when it's about to process something, and "complete" when it is done. It passes "self" to the "send()" method, signifying that that particular instance was responsible for emitting the signal. >>> class Processor: ... def __init__(self, name): ... self.name = name ... ... def go(self): ... ready = signal('ready') ... ready.send(self) ... print("Processing.") ... complete = signal('complete') ... complete.send(self) ... ... def __repr__(self): ... return '' % self.name ... >>> processor_a = Processor('a') >>> processor_a.go() Got a signal sent by Processing. Notice the "complete" signal in "go()"? No receivers have connected to "complete" yet, and that's a-ok. Calling "send()" on a signal with no receivers will result in no notifications being sent, and these no- op sends are optimized to be as inexpensive as possible. Subscribing to Specific Senders =============================== The default connection to a signal invokes the receiver function when any sender emits it. The "Signal.connect()" function accepts an optional argument to restrict the subscription to one specific sending object: >>> def b_subscriber(sender): ... print("Caught signal from processor_b.") ... assert sender.name == 'b' ... >>> processor_b = Processor('b') >>> ready.connect(b_subscriber, sender=processor_b) This function has been subscribed to "ready" but only when sent by "processor_b": >>> processor_a.go() Got a signal sent by Processing. >>> processor_b.go() Got a signal sent by Caught signal from processor_b. Processing. Sending and Receiving Data Through Signals ========================================== Additional keyword arguments can be passed to "send()". These will in turn be passed to the connected functions: >>> send_data = signal('send-data') >>> @send_data.connect ... def receive_data(sender, **kw): ... print("Caught signal from %r, data %r" % (sender, kw)) ... return 'received!' ... >>> result = send_data.send('anonymous', abc=123) Caught signal from 'anonymous', data {'abc': 123} The return value of "send()" collects the return values of each connected function as a list of ("receiver function", "return value") pairs: >>> result [(, 'received!')] Anonymous Signals ================= Signals need not be named. The "Signal" constructor creates a unique signal each time it is invoked. For example, an alternative implementation of the Processor from above might provide the processing signals as class attributes: >>> from blinker import Signal >>> class AltProcessor: ... on_ready = Signal() ... on_complete = Signal() ... ... def __init__(self, name): ... self.name = name ... ... def go(self): ... self.on_ready.send(self) ... print("Alternate processing.") ... self.on_complete.send(self) ... ... def __repr__(self): ... return '' % self.name ... "connect" as a Decorator ======================== You may have noticed the return value of "connect()" in the console output in the sections above. This allows "connect" to be used as a decorator on functions: >>> apc = AltProcessor('c') >>> @apc.on_complete.connect ... def completed(sender): ... print "AltProcessor %s completed!" % sender.name ... >>> apc.go() Alternate processing. AltProcessor c completed! While convenient, this form unfortunately does not allow the "sender" or "weak" arguments to be customized for the connected function. For this, "connect_via()" can be used: >>> dice_roll = signal('dice_roll') >>> @dice_roll.connect_via(1) ... @dice_roll.connect_via(3) ... @dice_roll.connect_via(5) ... def odd_subscriber(sender): ... print("Observed dice roll %r." % sender) ... >>> result = dice_roll.send(3) Observed dice roll 3. Optimizing Signal Sending ========================= Signals are optimized to send very quickly, whether receivers are connected or not. If the data to be sent down a signal is very expensive, it can be more efficient to check to see if any receivers are connected first by testing the "receivers" property: >>> bool(signal('ready').receivers) True >>> bool(signal('complete').receivers) False >>> bool(AltProcessor.on_complete.receivers) True Checking for a receiver listening for a particular sender is also possible: >>> signal('ready').has_receivers_for(processor_a) True Documenting Signals =================== Both named and anonymous signals can be passed a "doc" argument at construction to set the pydoc help text for the signal. This documentation will be picked up by most documentation generators (such as sphinx) and is nice for documenting any additional data parameters that will be sent down with the signal. See the documentation of the "receiver_connected" built-in signal for an example. More ==== Disconnecting receivers from signals, introspection of connected receivers, private namespaces for named signals and more are discussed in the *API Documentation*. blinker-1.3/docs/source/api.rst000664 000765 000024 00000001356 11652154310 016457 0ustar00jekstaff000000 000000 .. _api: API Documentation ================= All public API members can (and should) be imported from ``blinker``:: from blinker import ANY, signal .. currentmodule:: blinker.base Basic Signals ------------- .. autoattribute:: blinker.base.ANY .. autoattribute:: blinker.base.receiver_connected .. autoclass:: Signal :members: :undoc-members: Named Signals ------------- .. function:: signal(name, doc=None) Return the :class:`NamedSignal` *name*, creating it if required. Repeated calls to this function will return the same signal object. Signals are created in a global :class:`Namespace`. .. autoclass:: NamedSignal :show-inheritance: :members: .. autoclass:: Namespace :show-inheritance: :members: signal blinker-1.3/docs/source/conf.py000664 000765 000024 00000015254 11652154310 016455 0ustar00jekstaff000000 000000 # -*- coding: utf-8 -*- # # Blinker documentation build configuration file, created by # sphinx-quickstart on Mon Feb 15 10:54:13 2010. # # This file is execfile()d with the current directory set to its containing # dir. import os from os import path import sys # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.append(os.path.abspath('../../')) # -- General configuration ----------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.coverage'] html_theme_path = ['.'] try: import dbuilder except ImportError: pass else: extensions.append('dbuilder') html_theme_path.append(path.join(dbuilder.__path__[0], 'theme')) # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'Blinker' copyright = u'2010, Jason Kirtland' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = 'tip' # The full version, including alpha/beta/rc tags. release = 'tip' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of documents that shouldn't be included in the build. #unused_docs = [] # List of directories, relative to source directory, that shouldn't be searched # for source files. exclude_trees = [] autoclass_content = "both" autodoc_member_order = "groupwise" import sphinx.ext.autodoc sphinx.ext.autodoc.AttributeDocumenter.member_order = 25 sphinx.ext.autodoc.InstanceAttributeDocumenter.member_order = 26 # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. Major themes that come with # Sphinx are currently 'default' and 'sphinxdoc'. html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_use_modindex = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = '' # Output file base name for HTML help builder. htmlhelp_basename = 'Blinkerdoc' # -- Options for LaTeX output -------------------------------------------------- # The paper size ('letter' or 'a4'). #latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). #latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'Blinker.tex', u'Blinker Documentation', u'Jason Kirtland', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # Additional stuff for the LaTeX preamble. #latex_preamble = '' # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_use_modindex = True blinker-1.3/docs/source/index.rst000664 000765 000024 00000001353 11652154310 017012 0ustar00jekstaff000000 000000 Blinker Documentation ===================== Blinker provides fast & simple object-to-object and broadcast signaling for Python objects. The core of Blinker is quite small but provides powerful features: - a global registry of named signals - anonymous signals - custom name registries - permanently or temporarily connected receivers - automatically disconnected receivers via weak referencing - sending arbitrary data payloads - collecting return values from signal receivers Requirements ------------ Python 2.4 or later; Python 3.0 or later; or Jython 2.5 or later. No other modules are required. License ------- Blinker is provided under the MIT License. Contents -------- .. toctree:: :maxdepth: 2 signals api blinker-1.3/docs/source/signals.rst000664 000765 000024 00000015052 11652154310 017344 0ustar00jekstaff000000 000000 ======= Signals ======= .. currentmodule:: blinker.base Decoupling With Named Signals ----------------------------- Named signals are created with :func:`signal`: .. doctest:: >>> from blinker import signal >>> initialized = signal('initialized') >>> initialized is signal('initialized') True Every call to ``signal('name')`` returns the same signal object, allowing unconnected parts of code (different modules, plugins, anything) to all use the same signal without requiring any code sharing or special imports. Subscribing to Signals ---------------------- :meth:`Signal.connect` registers a function to be invoked each time the signal is emitted. Connected functions are always passed the object that caused the signal to be emitted. .. doctest:: >>> def subscriber(sender): ... print("Got a signal sent by %r" % sender) ... >>> ready = signal('ready') >>> ready.connect(subscriber) Emitting Signals ---------------- Code producing events of interest can :meth:`Signal.send` notifications to all connected receivers. Below, a simple ``Processor`` class emits a ``ready`` signal when it's about to process something, and ``complete`` when it is done. It passes ``self`` to the :meth:`~Signal.send` method, signifying that that particular instance was responsible for emitting the signal. .. doctest:: >>> class Processor: ... def __init__(self, name): ... self.name = name ... ... def go(self): ... ready = signal('ready') ... ready.send(self) ... print("Processing.") ... complete = signal('complete') ... complete.send(self) ... ... def __repr__(self): ... return '' % self.name ... >>> processor_a = Processor('a') >>> processor_a.go() Got a signal sent by Processing. Notice the ``complete`` signal in ``go()``? No receivers have connected to ``complete`` yet, and that's a-ok. Calling :meth:`~Signal.send` on a signal with no receivers will result in no notifications being sent, and these no-op sends are optimized to be as inexpensive as possible. Subscribing to Specific Senders ------------------------------- The default connection to a signal invokes the receiver function when any sender emits it. The :meth:`Signal.connect` function accepts an optional argument to restrict the subscription to one specific sending object: .. doctest:: >>> def b_subscriber(sender): ... print("Caught signal from processor_b.") ... assert sender.name == 'b' ... >>> processor_b = Processor('b') >>> ready.connect(b_subscriber, sender=processor_b) This function has been subscribed to ``ready`` but only when sent by ``processor_b``: .. doctest:: >>> processor_a.go() Got a signal sent by Processing. >>> processor_b.go() Got a signal sent by Caught signal from processor_b. Processing. Sending and Receiving Data Through Signals ------------------------------------------ Additional keyword arguments can be passed to :meth:`~Signal.send`. These will in turn be passed to the connected functions: .. doctest:: >>> send_data = signal('send-data') >>> @send_data.connect ... def receive_data(sender, **kw): ... print("Caught signal from %r, data %r" % (sender, kw)) ... return 'received!' ... >>> result = send_data.send('anonymous', abc=123) Caught signal from 'anonymous', data {'abc': 123} The return value of :meth:`~Signal.send` collects the return values of each connected function as a list of (``receiver function``, ``return value``) pairs: .. doctest:: >>> result [(, 'received!')] Anonymous Signals ----------------- Signals need not be named. The :class:`Signal` constructor creates a unique signal each time it is invoked. For example, an alternative implementation of the Processor from above might provide the processing signals as class attributes: .. doctest:: >>> from blinker import Signal >>> class AltProcessor: ... on_ready = Signal() ... on_complete = Signal() ... ... def __init__(self, name): ... self.name = name ... ... def go(self): ... self.on_ready.send(self) ... print("Alternate processing.") ... self.on_complete.send(self) ... ... def __repr__(self): ... return '' % self.name ... ``connect`` as a Decorator -------------------------- You may have noticed the return value of :meth:`~Signal.connect` in the console output in the sections above. This allows ``connect`` to be used as a decorator on functions: .. doctest:: >>> apc = AltProcessor('c') >>> @apc.on_complete.connect ... def completed(sender): ... print "AltProcessor %s completed!" % sender.name ... >>> apc.go() Alternate processing. AltProcessor c completed! While convenient, this form unfortunately does not allow the ``sender`` or ``weak`` arguments to be customized for the connected function. For this, :meth:`~Signal.connect_via` can be used: .. doctest:: >>> dice_roll = signal('dice_roll') >>> @dice_roll.connect_via(1) ... @dice_roll.connect_via(3) ... @dice_roll.connect_via(5) ... def odd_subscriber(sender): ... print("Observed dice roll %r." % sender) ... >>> result = dice_roll.send(3) Observed dice roll 3. Optimizing Signal Sending ------------------------- Signals are optimized to send very quickly, whether receivers are connected or not. If the data to be sent down a signal is very expensive, it can be more efficient to check to see if any receivers are connected first by testing the :attr:`~Signal.receivers` property: .. doctest:: >>> bool(signal('ready').receivers) True >>> bool(signal('complete').receivers) False >>> bool(AltProcessor.on_complete.receivers) True Checking for a receiver listening for a particular sender is also possible: .. doctest:: >>> signal('ready').has_receivers_for(processor_a) True Documenting Signals ------------------- Both named and anonymous signals can be passed a ``doc`` argument at construction to set the pydoc help text for the signal. This documentation will be picked up by most documentation generators (such as sphinx) and is nice for documenting any additional data parameters that will be sent down with the signal. See the documentation of the :obj:`receiver_connected` built-in signal for an example. More ---- Disconnecting receivers from signals, introspection of connected receivers, private namespaces for named signals and more are discussed in the :ref:`api`. blinker-1.3/docs/html/_sources/000775 000765 000024 00000000000 12164774263 016453 5ustar00jekstaff000000 000000 blinker-1.3/docs/html/_static/000775 000765 000024 00000000000 12164774263 016257 5ustar00jekstaff000000 000000 blinker-1.3/docs/html/api.html000664 000765 000024 00000056547 12164774166 016313 0ustar00jekstaff000000 000000 API Documentation — Blinker tip documentation

API Documentation

All public API members can (and should) be imported from blinker:

from blinker import ANY, signal

Basic Signals

base.ANY = ANY
base.receiver_connected = <blinker.base.Signal object at 0x1021758d0>
class blinker.base.Signal(doc=None)

A notification emitter.

Parameters:doc – optional. If provided, will be assigned to the signal’s __doc__ attribute.
ANY = ANY

An ANY convenience synonym, allows Signal.ANY without an additional import.

receiver_connected

Emitted after each connect().

The signal sender is the signal instance, and the connect() arguments are passed through: receiver, sender, and weak.

New in version 1.2.

receiver_disconnected

Emitted after disconnect().

The sender is the signal instance, and the disconnect() arguments are passed through: receiver and sender.

Note, this signal is emitted only when disconnect() is called explicitly.

The disconnect signal can not be emitted by an automatic disconnect (due to a weakly referenced receiver or sender going out of scope), as the receiver and/or sender instances are no longer available for use at the time this signal would be emitted.

An alternative approach is available by subscribing to receiver_connected and setting up a custom weakref cleanup callback on weak receivers and senders.

New in version 1.2.

receivers = None

A mapping of connected receivers.

The values of this mapping are not meaningful outside of the internal Signal implementation, however the boolean value of the mapping is useful as an extremely efficient check to see if any receivers are connected to the signal.

connect(receiver, sender=ANY, weak=True)

Connect receiver to signal events sent by sender.

Parameters:
  • receiver – A callable. Will be invoked by send() with sender= as a single positional argument and any **kwargs that were provided to a call to send().
  • sender – Any object or ANY, defaults to ANY. Restricts notifications delivered to receiver to only those send() emissions sent by sender. If ANY, the receiver will always be notified. A receiver may be connected to multiple sender values on the same Signal through multiple calls to connect().
  • weak – If true, the Signal will hold a weakref to receiver and automatically disconnect when receiver goes out of scope or is garbage collected. Defaults to True.
connect_via(sender, weak=False)

Connect the decorated function as a receiver for sender.

Parameters:
  • sender – Any object or ANY. The decorated function will only receive send() emissions sent by sender. If ANY, the receiver will always be notified. A function may be decorated multiple times with differing sender values.
  • weak – If true, the Signal will hold a weakref to the decorated function and automatically disconnect when receiver goes out of scope or is garbage collected. Unlike connect(), this defaults to False.
The decorated function will be invoked by send() with
sender= as a single positional argument and any **kwargs that were provided to the call to send().

New in version 1.1.

connected_to(*args, **kwds)

Execute a block with the signal temporarily connected to receiver.

Parameters:
  • receiver – a receiver callable
  • sender – optional, a sender to filter on

This is a context manager for use in the with statement. It can be useful in unit tests. receiver is connected to the signal for the duration of the with block, and will be disconnected automatically when exiting the block:

with on_ready.connected_to(receiver):
   # do stuff
   on_ready.send(123)

New in version 1.1.

disconnect(receiver, sender=ANY)

Disconnect receiver from this signal’s events.

Parameters:
  • receiver – a previously connected callable
  • sender – a specific sender to disconnect from, or ANY to disconnect from all senders. Defaults to ANY.
has_receivers_for(sender)

True if there is probably a receiver for sender.

Performs an optimistic check only. Does not guarantee that all weakly referenced receivers are still alive. See receivers_for() for a stronger search.

receivers_for(sender)

Iterate all live receivers listening for sender.

send(*sender, **kwargs)

Emit this signal on behalf of sender, passing on **kwargs.

Returns a list of 2-tuples, pairing receivers with their return value. The ordering of receiver notification is undefined.

Parameters:
  • *sender – Any object or None. If omitted, synonymous with None. Only accepts one positional argument.
  • **kwargs – Data to be sent to receivers.
temporarily_connected_to(receiver, sender=ANY)

An alias for connected_to().

Parameters:
  • receiver – a receiver callable
  • sender – optional, a sender to filter on

New in version 0.9.

Changed in version 1.1: Renamed to connected_to(). temporarily_connected_to was deprecated in 1.2 and removed in a subsequent version.

Named Signals

blinker.base.signal(name, doc=None)

Return the NamedSignal name, creating it if required.

Repeated calls to this function will return the same signal object. Signals are created in a global Namespace.

class blinker.base.NamedSignal(name, doc=None)

Bases: blinker.base.Signal

A named generic notification emitter.

name = None

The name of this signal.

class blinker.base.Namespace(*args, **kw)

Bases: weakref.WeakValueDictionary

A mapping of signal names to signals.

signal(name, doc=None)

Return the NamedSignal name, creating it if required.

Repeated calls to this function will return the same signal object.

Table Of Contents

Previous topic

Signals

This Page

blinker-1.3/docs/html/genindex.html000664 000765 000024 00000015353 12164774167 017332 0ustar00jekstaff000000 000000 Index — Blinker tip documentation blinker-1.3/docs/html/index.html000664 000765 000024 00000015150 12164774166 016632 0ustar00jekstaff000000 000000 Blinker Documentation — Blinker tip documentation

Blinker Documentation

Blinker provides fast & simple object-to-object and broadcast signaling for Python objects.

The core of Blinker is quite small but provides powerful features:

  • a global registry of named signals
  • anonymous signals
  • custom name registries
  • permanently or temporarily connected receivers
  • automatically disconnected receivers via weak referencing
  • sending arbitrary data payloads
  • collecting return values from signal receivers

Requirements

Python 2.4 or later; Python 3.0 or later; or Jython 2.5 or later.

No other modules are required.

License

Blinker is provided under the MIT License.

Table Of Contents

Next topic

Signals

This Page

blinker-1.3/docs/html/objects.inv000664 000765 000024 00000000622 12164774167 017003 0ustar00jekstaff000000 000000 # Sphinx inventory version 2 # Project: Blinker # Version: tip # The remainder of this file is compressed using zlib. xڥ=o0w~vkH]24): Xg!Am#L6tϽe&?Z(ЈC?*X&j MJJ?[t z)zj]wdc(a/)dž^hFm" }% 0W[$0!x]4H,ʩ9tD(:?:pMh)O`g[{ blinker-1.3/docs/html/search.html000664 000765 000024 00000006033 12164774167 016771 0ustar00jekstaff000000 000000 Search — Blinker tip documentation

Search

Please activate JavaScript to enable the search functionality.

From here you can search these documents. Enter your search words into the box below and click "search". Note that the search function will automatically search for all of the words. Pages containing fewer words won't appear in the result list.

blinker-1.3/docs/html/searchindex.js000664 000765 000024 00000007602 12164774167 017474 0ustar00jekstaff000000 000000 Search.setIndex({objects:{"blinker.base.Namespace":{signal:[2,2,1,""]},"blinker.base":{receiver_connected:[2,1,1,""],NamedSignal:[2,0,1,""],signal:[2,3,1,""],Namespace:[2,0,1,""],ANY:[2,1,1,""],Signal:[2,0,1,""]},"blinker.base.NamedSignal":{name:[2,1,1,""]},"blinker.base.Signal":{connect_via:[2,2,1,""],disconnect:[2,2,1,""],receiver_connected:[2,1,1,""],receiver_disconnected:[2,1,1,""],receivers:[2,1,1,""],has_receivers_for:[2,2,1,""],connected_to:[2,2,1,""],send:[2,2,1,""],receivers_for:[2,2,1,""],connect:[2,2,1,""],temporarily_connected_to:[2,2,1,""],ANY:[2,1,1,""]}},terms:{"default":[0,2],all:[0,2],code:0,help:0,execut:2,"0x1021758d0":2,"boolean":2,text:0,global:[1,2],python:1,through:[0,1,2],has_receivers_for:[0,2],still:2,callabl:2,yet:0,paramet:[0,2],note:2,onli:[0,2],explicitli:2,disconnect:[0,1,2],dice:0,"true":[0,2],receiver_connect:[0,2],send:[0,1,2],should:2,other:1,those:2,under:1,on_complet:0,subsequ:2,might:0,sent:[0,2],jython:1,"return":[0,1,2],without:[0,2],fals:[0,2],constructor:0,initi:0,"import":[0,2],veri:0,part:0,on_readi:[0,2],discuss:0,requir:[0,1,2],restrict:[0,2],document:[0,1,2],name:[0,1,2],specif:[0,1,2],arbitrari:1,signal:[0,1,2],anyth:0,list:[0,2],iter:2,"public":2,pydoc:0,collect:[0,1,2],stuff:2,each:[0,2],small:1,output:0,receiver_disconnect:2,manag:2,set:[0,2],namedsign:2,mai:[0,2],complet:0,send_data:0,intern:2,temporarili:[1,2],signifi:0,connect:[0,1,2],pass:[0,2],guarante:2,event:[0,2],special:0,out:2,synonym:2,abc:0,referenc:[1,2],connected_to:2,goe:2,someth:0,introspect:0,invok:[0,2],weakli:2,content:1,version:2,exit:2,print:0,got:0,subscript:0,previous:2,approach:2,method:0,attribut:[0,2],altern:[0,2],core:1,more:[0,1],blinker:[0,1,2],power:1,garbag:2,were:2,weak:[0,1,2],privat:0,thi:[0,2],base:2,emitt:2,valu:[0,1,2],addit:[0,2],both:0,search:2,produc:0,sender:[0,1,2],plugin:0,howev:2,omit:2,unfortun:0,weakref:2,turn:0,licens:1,dice_rol:0,"__repr__":0,context:2,pick:0,gener:[0,2],extrem:2,implement:[0,2],assign:2,block:2,first:0,weakvaluedictionari:2,arg:2,via:1,effici:[0,2],notifi:2,can:[0,2],mit:1,modul:[0,1],"while":0,automat:[1,2],down:0,deprec:2,unlik:2,api:[0,1,2],done:0,been:0,apc:0,payload:1,unit:2,odd_subscrib:0,processor_b:0,quit:1,differ:[0,2],fast:1,from:[0,1,2],would:2,caught:0,regist:0,due:2,construct:0,custom:[0,1,2],avail:2,readi:0,live:2,call:[0,2],interest:0,subscrib:[0,1,2],scope:2,conveni:[0,2],"__doc__":2,quickli:0,"function":[0,2],consol:0,statement:2,form:0,namespac:[0,2],tupl:2,basic:[1,2],about:0,notic:0,ani:[0,2],broadcast:1,provid:[0,1,2],altprocessor:0,order:2,particular:0,renam:2,temporarily_connected_to:2,hold:2,outsid:2,behalf:2,none:2,cleanup:2,keyword:0,possibl:0,whether:0,alia:2,remov:2,properti:0,uniqu:0,durat:2,below:0,receive_data:0,abov:0,optimist:2,posit:2,anonym:[0,1],listen:[0,2],observ:0,def:0,result:0,featur:1,creat:[0,2],process:0,respons:0,emiss:2,argument:[0,2],accept:[0,2],kwarg:2,perman:1,aliv:2,have:0,deliv:2,need:0,everi:0,doe:[0,2],check:[0,2],"__init__":0,option:[0,2],filter:2,decor:[0,1,2],multipl:2,built:0,callback:2,perform:2,self:0,when:[0,2],same:[0,2],member:2,also:0,instanc:[0,2],bool:0,test:[0,2],you:0,probabl:2,simpl:[0,1],roll:0,singl:2,nice:0,connect_via:[0,2],map:2,notif:[0,2],kwd:2,registri:1,see:[0,2],alwai:[0,2],optim:[0,1],after:2,most:0,meaning:2,share:0,pair:[0,2],receivers_for:2,decoupl:[0,1],data:[0,1,2],"class":[0,2],repeat:2,assert:0,sphinx:0,longer:2,emit:[0,1,2],doc:[0,2],later:1,stronger:2,object:[0,1,2],processor:0,caus:0,receiv:[0,1,2],exampl:0,unconnect:0,expens:0,allow:[0,2],time:[0,2],undefin:2,processor_a:0,b_subscrib:0,section:0,inexpens:0},objtypes:{"0":"py:class","1":"py:attribute","2":"py:method","3":"py:function"},titles:["Signals","Blinker Documentation","API Documentation"],objnames:{"0":["py","class","Python class"],"1":["py","attribute","Python attribute"],"2":["py","method","Python method"],"3":["py","function","Python function"]},filenames:["signals","index","api"]})blinker-1.3/docs/html/signals.html000664 000765 000024 00000066746 12164774166 017204 0ustar00jekstaff000000 000000 Signals — Blinker tip documentation

Signals

Decoupling With Named Signals

Named signals are created with signal():

>>> from blinker import signal
>>> initialized = signal('initialized')
>>> initialized is signal('initialized')
True

Every call to signal('name') returns the same signal object, allowing unconnected parts of code (different modules, plugins, anything) to all use the same signal without requiring any code sharing or special imports.

Subscribing to Signals

Signal.connect() registers a function to be invoked each time the signal is emitted. Connected functions are always passed the object that caused the signal to be emitted.

>>> def subscriber(sender):
...     print("Got a signal sent by %r" % sender)
...
>>> ready = signal('ready')
>>> ready.connect(subscriber)
<function subscriber at 0x...>

Emitting Signals

Code producing events of interest can Signal.send() notifications to all connected receivers.

Below, a simple Processor class emits a ready signal when it’s about to process something, and complete when it is done. It passes self to the send() method, signifying that that particular instance was responsible for emitting the signal.

>>> class Processor:
...    def __init__(self, name):
...        self.name = name
...
...    def go(self):
...        ready = signal('ready')
...        ready.send(self)
...        print("Processing.")
...        complete = signal('complete')
...        complete.send(self)
...
...    def __repr__(self):
...        return '<Processor %s>' % self.name
...
>>> processor_a = Processor('a')
>>> processor_a.go()
Got a signal sent by <Processor a>
Processing.

Notice the complete signal in go()? No receivers have connected to complete yet, and that’s a-ok. Calling send() on a signal with no receivers will result in no notifications being sent, and these no-op sends are optimized to be as inexpensive as possible.

Subscribing to Specific Senders

The default connection to a signal invokes the receiver function when any sender emits it. The Signal.connect() function accepts an optional argument to restrict the subscription to one specific sending object:

>>> def b_subscriber(sender):
...     print("Caught signal from processor_b.")
...     assert sender.name == 'b'
...
>>> processor_b = Processor('b')
>>> ready.connect(b_subscriber, sender=processor_b)
<function b_subscriber at 0x...>

This function has been subscribed to ready but only when sent by processor_b:

>>> processor_a.go()
Got a signal sent by <Processor a>
Processing.
>>> processor_b.go()
Got a signal sent by <Processor b>
Caught signal from processor_b.
Processing.

Sending and Receiving Data Through Signals

Additional keyword arguments can be passed to send(). These will in turn be passed to the connected functions:

>>> send_data = signal('send-data')
>>> @send_data.connect
... def receive_data(sender, **kw):
...     print("Caught signal from %r, data %r" % (sender, kw))
...     return 'received!'
...
>>> result = send_data.send('anonymous', abc=123)
Caught signal from 'anonymous', data {'abc': 123}

The return value of send() collects the return values of each connected function as a list of (receiver function, return value) pairs:

>>> result
[(<function receive_data at 0x...>, 'received!')]

Anonymous Signals

Signals need not be named. The Signal constructor creates a unique signal each time it is invoked. For example, an alternative implementation of the Processor from above might provide the processing signals as class attributes:

>>> from blinker import Signal
>>> class AltProcessor:
...    on_ready = Signal()
...    on_complete = Signal()
...
...    def __init__(self, name):
...        self.name = name
...
...    def go(self):
...        self.on_ready.send(self)
...        print("Alternate processing.")
...        self.on_complete.send(self)
...
...    def __repr__(self):
...        return '<AltProcessor %s>' % self.name
...

connect as a Decorator

You may have noticed the return value of connect() in the console output in the sections above. This allows connect to be used as a decorator on functions:

>>> apc = AltProcessor('c')
>>> @apc.on_complete.connect
... def completed(sender):
...     print "AltProcessor %s completed!" % sender.name
...
>>> apc.go()
Alternate processing.
AltProcessor c completed!

While convenient, this form unfortunately does not allow the sender or weak arguments to be customized for the connected function. For this, connect_via() can be used:

>>> dice_roll = signal('dice_roll')
>>> @dice_roll.connect_via(1)
... @dice_roll.connect_via(3)
... @dice_roll.connect_via(5)
... def odd_subscriber(sender):
...     print("Observed dice roll %r." % sender)
...
>>> result = dice_roll.send(3)
Observed dice roll 3.

Optimizing Signal Sending

Signals are optimized to send very quickly, whether receivers are connected or not. If the data to be sent down a signal is very expensive, it can be more efficient to check to see if any receivers are connected first by testing the receivers property:

>>> bool(signal('ready').receivers)
True
>>> bool(signal('complete').receivers)
False
>>> bool(AltProcessor.on_complete.receivers)
True

Checking for a receiver listening for a particular sender is also possible:

>>> signal('ready').has_receivers_for(processor_a)
True

Documenting Signals

Both named and anonymous signals can be passed a doc argument at construction to set the pydoc help text for the signal. This documentation will be picked up by most documentation generators (such as sphinx) and is nice for documenting any additional data parameters that will be sent down with the signal.

See the documentation of the receiver_connected built-in signal for an example.

More

Disconnecting receivers from signals, introspection of connected receivers, private namespaces for named signals and more are discussed in the API Documentation.

blinker-1.3/docs/html/_static/basic.css000664 000765 000024 00000020417 12164774167 020061 0ustar00jekstaff000000 000000 /* * basic.css * ~~~~~~~~~ * * Sphinx stylesheet -- basic theme. * * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ /* -- main layout ----------------------------------------------------------- */ div.clearer { clear: both; } /* -- relbar ---------------------------------------------------------------- */ div.related { width: 100%; font-size: 90%; } div.related h3 { display: none; } div.related ul { margin: 0; padding: 0 0 0 10px; list-style: none; } div.related li { display: inline; } div.related li.right { float: right; margin-right: 5px; } /* -- sidebar --------------------------------------------------------------- */ div.sphinxsidebarwrapper { padding: 10px 5px 0 10px; } div.sphinxsidebar { float: left; width: 230px; margin-left: -100%; font-size: 90%; } div.sphinxsidebar ul { list-style: none; } div.sphinxsidebar ul ul, div.sphinxsidebar ul.want-points { margin-left: 20px; list-style: square; } div.sphinxsidebar ul ul { margin-top: 0; margin-bottom: 0; } div.sphinxsidebar form { margin-top: 10px; } div.sphinxsidebar input { border: 1px solid #98dbcc; font-family: sans-serif; font-size: 1em; } div.sphinxsidebar #searchbox input[type="text"] { width: 170px; } div.sphinxsidebar #searchbox input[type="submit"] { width: 30px; } img { border: 0; } /* -- search page ----------------------------------------------------------- */ ul.search { margin: 10px 0 0 20px; padding: 0; } ul.search li { padding: 5px 0 5px 20px; background-image: url(file.png); background-repeat: no-repeat; background-position: 0 7px; } ul.search li a { font-weight: bold; } ul.search li div.context { color: #888; margin: 2px 0 0 30px; text-align: left; } ul.keywordmatches li.goodmatch a { font-weight: bold; } /* -- index page ------------------------------------------------------------ */ table.contentstable { width: 90%; } table.contentstable p.biglink { line-height: 150%; } a.biglink { font-size: 1.3em; } span.linkdescr { font-style: italic; padding-top: 5px; font-size: 90%; } /* -- general index --------------------------------------------------------- */ table.indextable { width: 100%; } table.indextable td { text-align: left; vertical-align: top; } table.indextable dl, table.indextable dd { margin-top: 0; margin-bottom: 0; } table.indextable tr.pcap { height: 10px; } table.indextable tr.cap { margin-top: 10px; background-color: #f2f2f2; } img.toggler { margin-right: 3px; margin-top: 3px; cursor: pointer; } div.modindex-jumpbox { border-top: 1px solid #ddd; border-bottom: 1px solid #ddd; margin: 1em 0 1em 0; padding: 0.4em; } div.genindex-jumpbox { border-top: 1px solid #ddd; border-bottom: 1px solid #ddd; margin: 1em 0 1em 0; padding: 0.4em; } /* -- general body styles --------------------------------------------------- */ a.headerlink { visibility: hidden; } h1:hover > a.headerlink, h2:hover > a.headerlink, h3:hover > a.headerlink, h4:hover > a.headerlink, h5:hover > a.headerlink, h6:hover > a.headerlink, dt:hover > a.headerlink { visibility: visible; } div.body p.caption { text-align: inherit; } div.body td { text-align: left; } .field-list ul { padding-left: 1em; } .first { margin-top: 0 !important; } p.rubric { margin-top: 30px; font-weight: bold; } img.align-left, .figure.align-left, object.align-left { clear: left; float: left; margin-right: 1em; } img.align-right, .figure.align-right, object.align-right { clear: right; float: right; margin-left: 1em; } img.align-center, .figure.align-center, object.align-center { display: block; margin-left: auto; margin-right: auto; } .align-left { text-align: left; } .align-center { text-align: center; } .align-right { text-align: right; } /* -- sidebars -------------------------------------------------------------- */ div.sidebar { margin: 0 0 0.5em 1em; border: 1px solid #ddb; padding: 7px 7px 0 7px; background-color: #ffe; width: 40%; float: right; } p.sidebar-title { font-weight: bold; } /* -- topics ---------------------------------------------------------------- */ div.topic { border: 1px solid #ccc; padding: 7px 7px 0 7px; margin: 10px 0 10px 0; } p.topic-title { font-size: 1.1em; font-weight: bold; margin-top: 10px; } /* -- admonitions ----------------------------------------------------------- */ div.admonition { margin-top: 10px; margin-bottom: 10px; padding: 7px; } div.admonition dt { font-weight: bold; } div.admonition dl { margin-bottom: 0; } p.admonition-title { margin: 0px 10px 5px 0px; font-weight: bold; } div.body p.centered { text-align: center; margin-top: 25px; } /* -- tables ---------------------------------------------------------------- */ table.docutils { border: 0; border-collapse: collapse; } table.docutils td, table.docutils th { padding: 1px 8px 1px 5px; border-top: 0; border-left: 0; border-right: 0; border-bottom: 1px solid #aaa; } table.field-list td, table.field-list th { border: 0 !important; } table.footnote td, table.footnote th { border: 0 !important; } th { text-align: left; padding-right: 5px; } table.citation { border-left: solid 1px gray; margin-left: 1px; } table.citation td { border-bottom: none; } /* -- other body styles ----------------------------------------------------- */ ol.arabic { list-style: decimal; } ol.loweralpha { list-style: lower-alpha; } ol.upperalpha { list-style: upper-alpha; } ol.lowerroman { list-style: lower-roman; } ol.upperroman { list-style: upper-roman; } dl { margin-bottom: 15px; } dd p { margin-top: 0px; } dd ul, dd table { margin-bottom: 10px; } dd { margin-top: 3px; margin-bottom: 10px; margin-left: 30px; } dt:target, .highlighted { background-color: #fbe54e; } dl.glossary dt { font-weight: bold; font-size: 1.1em; } .field-list ul { margin: 0; padding-left: 1em; } .field-list p { margin: 0; } .refcount { color: #060; } .optional { font-size: 1.3em; } .versionmodified { font-style: italic; } .system-message { background-color: #fda; padding: 5px; border: 3px solid red; } .footnote:target { background-color: #ffa; } .line-block { display: block; margin-top: 1em; margin-bottom: 1em; } .line-block .line-block { margin-top: 0; margin-bottom: 0; margin-left: 1.5em; } .guilabel, .menuselection { font-family: sans-serif; } .accelerator { text-decoration: underline; } .classifier { font-style: oblique; } abbr, acronym { border-bottom: dotted 1px; cursor: help; } /* -- code displays --------------------------------------------------------- */ pre { overflow: auto; overflow-y: hidden; /* fixes display issues on Chrome browsers */ } td.linenos pre { padding: 5px 0px; border: 0; background-color: transparent; color: #aaa; } table.highlighttable { margin-left: 0.5em; } table.highlighttable td { padding: 0 0.5em 0 0.5em; } tt.descname { background-color: transparent; font-weight: bold; font-size: 1.2em; } tt.descclassname { background-color: transparent; } tt.xref, a tt { background-color: transparent; font-weight: bold; } h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt { background-color: transparent; } .viewcode-link { float: right; } .viewcode-back { float: right; font-family: sans-serif; } div.viewcode-block:target { margin: -1px -10px; padding: 0 10px; } /* -- math display ---------------------------------------------------------- */ img.math { vertical-align: middle; } div.body div.math p { text-align: center; } span.eqno { float: right; } /* -- printout stylesheet --------------------------------------------------- */ @media print { div.document, div.documentwrapper, div.bodywrapper { margin: 0 !important; width: 100%; } div.sphinxsidebar, div.related, div.footer, #top-link { display: none; } }blinker-1.3/docs/html/_static/comment-bright.png000664 000765 000024 00000006654 11727204047 021707 0ustar00jekstaff000000 000000 PNG  IHDRa OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3-bKGD pHYs  tIME 6 B\<IDAT8˅Kh]es1mA`jh[-E(FEaA!bIȐ*BX"؁4)NURZ!Mhjssm؋^-\gg ]o|Ҭ[346>zd ]#8Oݺt{5uIXN!I=@Vf=v1}e>;fvnvxaHrʪJF`D¹WZ]S%S)WAb |0K=So7D~\~q-˟\aMZ,S'*} F`Nnz674U H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3-bKGD pHYs  tIME!,IDAT8e_Hu?}s3y˕U2MvQ֊FE.łĊbE$DDZF5b@Q":2{n.s<_ y?mwV@tR`}Z _# _=_@ w^R%6gC-έ(K>| ${} H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3-bKGD pHYs  tIME 1;VIDAT8ukU?sg4h`G1 RQܸp%Bn"bЍXJ .4V iZ##T;m!4bP~7r>ιbwc;m;oӍAΆ ζZ^/|s{;yR=9(rtVoG1w#_ө{*E&!(LVuoᲵ‘D PG4 :&~*ݳreu: S-,U^E&JY[P!RB ŖޞʖR@_ȐdBfNvHf"2T]R j'B1ddAak/DIJD D2H&L`&L $Ex,6|~_\P $MH`I=@Z||ttvgcЕWTZ'3rje"ܵx9W> mb|byfFRx{w%DZC$wdցHmWnta(M<~;9]C/_;Տ#}o`zSڷ_>:;x컓?yݩ|}~wam-/7=0S5RP"*֯ IENDB`blinker-1.3/docs/html/_static/default.css000664 000765 000024 00000007710 12164774167 020425 0ustar00jekstaff000000 000000 /* * default.css_t * ~~~~~~~~~~~~~ * * Sphinx stylesheet -- default theme. * * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ @import url("basic.css"); /* -- page layout ----------------------------------------------------------- */ body { font-family: sans-serif; font-size: 100%; background-color: #11303d; color: #000; margin: 0; padding: 0; } div.document { background-color: #1c4e63; } div.documentwrapper { float: left; width: 100%; } div.bodywrapper { margin: 0 0 0 230px; } div.body { background-color: #ffffff; color: #000000; padding: 0 20px 30px 20px; } div.footer { color: #ffffff; width: 100%; padding: 9px 0 9px 0; text-align: center; font-size: 75%; } div.footer a { color: #ffffff; text-decoration: underline; } div.related { background-color: #133f52; line-height: 30px; color: #ffffff; } div.related a { color: #ffffff; } div.sphinxsidebar { } div.sphinxsidebar h3 { font-family: 'Trebuchet MS', sans-serif; color: #ffffff; font-size: 1.4em; font-weight: normal; margin: 0; padding: 0; } div.sphinxsidebar h3 a { color: #ffffff; } div.sphinxsidebar h4 { font-family: 'Trebuchet MS', sans-serif; color: #ffffff; font-size: 1.3em; font-weight: normal; margin: 5px 0 0 0; padding: 0; } div.sphinxsidebar p { color: #ffffff; } div.sphinxsidebar p.topless { margin: 5px 10px 10px 10px; } div.sphinxsidebar ul { margin: 10px; padding: 0; color: #ffffff; } div.sphinxsidebar a { color: #98dbcc; } div.sphinxsidebar input { border: 1px solid #98dbcc; font-family: sans-serif; font-size: 1em; } /* -- hyperlink styles ------------------------------------------------------ */ a { color: #355f7c; text-decoration: none; } a:visited { color: #355f7c; text-decoration: none; } a:hover { text-decoration: underline; } /* -- body styles ----------------------------------------------------------- */ div.body h1, div.body h2, div.body h3, div.body h4, div.body h5, div.body h6 { font-family: 'Trebuchet MS', sans-serif; background-color: #f2f2f2; font-weight: normal; color: #20435c; border-bottom: 1px solid #ccc; margin: 20px -20px 10px -20px; padding: 3px 0 3px 10px; } div.body h1 { margin-top: 0; font-size: 200%; } div.body h2 { font-size: 160%; } div.body h3 { font-size: 140%; } div.body h4 { font-size: 120%; } div.body h5 { font-size: 110%; } div.body h6 { font-size: 100%; } a.headerlink { color: #c60f0f; font-size: 0.8em; padding: 0 4px 0 4px; text-decoration: none; } a.headerlink:hover { background-color: #c60f0f; color: white; } div.body p, div.body dd, div.body li { text-align: justify; line-height: 130%; } div.admonition p.admonition-title + p { display: inline; } div.admonition p { margin-bottom: 5px; } div.admonition pre { margin-bottom: 5px; } div.admonition ul, div.admonition ol { margin-bottom: 5px; } div.note { background-color: #eee; border: 1px solid #ccc; } div.seealso { background-color: #ffc; border: 1px solid #ff6; } div.topic { background-color: #eee; } div.warning { background-color: #ffe4e4; border: 1px solid #f66; } p.admonition-title { display: inline; } p.admonition-title:after { content: ":"; } pre { padding: 5px; background-color: #eeffcc; color: #333333; line-height: 120%; border: 1px solid #ac9; border-left: none; border-right: none; } tt { background-color: #ecf0f3; padding: 0 1px 0 1px; font-size: 0.95em; } th { background-color: #ede; } .warning tt { background: #efc2c2; } .note tt { background: #d6d6d6; } .viewcode-back { font-family: sans-serif; } div.viewcode-block:target { background-color: #f4debf; border-top: 1px solid #ac9; border-bottom: 1px solid #ac9; }blinker-1.3/docs/html/_static/down-pressed.png000664 000765 000024 00000000560 11727204047 021370 0ustar00jekstaff000000 000000 PNG  IHDRasRGBbKGDC pHYs B(xtIME -vF#IDAT8!OAJ, ++@I vbÿ@W7F HN#48646TMvv޼7Dsax1U q;< E-f)j%po4xF78G>)- EYm4%7YTk-Qa"NWAo-yeq,) Ypt\hqmszG]Nar߶s^l vh\2%0EeRvIENDB`blinker-1.3/docs/html/_static/down.png000664 000765 000024 00000000553 11727204047 017727 0ustar00jekstaff000000 000000 PNG  IHDRasRGBbKGDC pHYs B(xtIME"U{IDAT8ҡNCAJ, ++@4>/U^,~T&3M^^^PM6ٹs*RJa)eG*W<"F Fg78G>q OIp:sAj5GنyD^+yU:p_%G@D|aOs(yM,"msx:.b@D|`Vٟ۲иeKſ/G!IENDB`blinker-1.3/docs/html/_static/file.png000664 000765 000024 00000000610 11727204047 017671 0ustar00jekstaff000000 000000 PNG  IHDRabKGD pHYs  tIME  )TIDAT8˭J@Ir('[ "&xYZ X0!i|_@tD] #xjv YNaEi(əy@D&`6PZk$)5%"z.NA#Aba`Vs_3c,2mj [klvy|!Iմy;v "߮a?A7`c^nk?Bg}TЙD# "RD1yER*6MJ3K_Ut8F~IENDB`blinker-1.3/docs/html/_static/minus.png000664 000765 000024 00000000307 11727204047 020110 0ustar00jekstaff000000 000000 PNG  IHDR &q pHYs  tIME <8tEXtComment̖RIDATcz(BpipPc |IENDB`blinker-1.3/docs/html/_static/pygments.css000664 000765 000024 00000007534 12164774167 020653 0ustar00jekstaff000000 000000 .highlight .hll { background-color: #ffffcc } .highlight { background: #eeffcc; } .highlight .c { color: #408090; font-style: italic } /* Comment */ .highlight .err { border: 1px solid #FF0000 } /* Error */ .highlight .k { color: #007020; font-weight: bold } /* Keyword */ .highlight .o { color: #666666 } /* Operator */ .highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */ .highlight .cp { color: #007020 } /* Comment.Preproc */ .highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */ .highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ .highlight .gd { color: #A00000 } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .gr { color: #FF0000 } /* Generic.Error */ .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ .highlight .gi { color: #00A000 } /* Generic.Inserted */ .highlight .go { color: #303030 } /* Generic.Output */ .highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ .highlight .gt { color: #0040D0 } /* Generic.Traceback */ .highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #007020 } /* Keyword.Pseudo */ .highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #902000 } /* Keyword.Type */ .highlight .m { color: #208050 } /* Literal.Number */ .highlight .s { color: #4070a0 } /* Literal.String */ .highlight .na { color: #4070a0 } /* Name.Attribute */ .highlight .nb { color: #007020 } /* Name.Builtin */ .highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ .highlight .no { color: #60add5 } /* Name.Constant */ .highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ .highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ .highlight .ne { color: #007020 } /* Name.Exception */ .highlight .nf { color: #06287e } /* Name.Function */ .highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ .highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ .highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #bb60d5 } /* Name.Variable */ .highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mf { color: #208050 } /* Literal.Number.Float */ .highlight .mh { color: #208050 } /* Literal.Number.Hex */ .highlight .mi { color: #208050 } /* Literal.Number.Integer */ .highlight .mo { color: #208050 } /* Literal.Number.Oct */ .highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ .highlight .sc { color: #4070a0 } /* Literal.String.Char */ .highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ .highlight .s2 { color: #4070a0 } /* Literal.String.Double */ .highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ .highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ .highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ .highlight .sx { color: #c65d09 } /* Literal.String.Other */ .highlight .sr { color: #235388 } /* Literal.String.Regex */ .highlight .s1 { color: #4070a0 } /* Literal.String.Single */ .highlight .ss { color: #517918 } /* Literal.String.Symbol */ .highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ .highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ .highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ .highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ .highlight .il { color: #208050 } /* Literal.Number.Integer.Long */blinker-1.3/docs/html/_static/up-pressed.png000664 000765 000024 00000000564 11727204047 021051 0ustar00jekstaff000000 000000 PNG  IHDRasRGBbKGDC pHYs B(xtIME ,ZeIDAT8͓jA*WKk-,By@- و/`cXYh!6jf GrOlXvvfk2!p!GOOԲ &zf 6|M~%`]* ΛM]K ZĆ1Er%ȶcm1`>> from blinker import signal >>> initialized = signal('initialized') >>> initialized is signal('initialized') True Every call to ``signal('name')`` returns the same signal object, allowing unconnected parts of code (different modules, plugins, anything) to all use the same signal without requiring any code sharing or special imports. Subscribing to Signals ---------------------- :meth:`Signal.connect` registers a function to be invoked each time the signal is emitted. Connected functions are always passed the object that caused the signal to be emitted. .. doctest:: >>> def subscriber(sender): ... print("Got a signal sent by %r" % sender) ... >>> ready = signal('ready') >>> ready.connect(subscriber) Emitting Signals ---------------- Code producing events of interest can :meth:`Signal.send` notifications to all connected receivers. Below, a simple ``Processor`` class emits a ``ready`` signal when it's about to process something, and ``complete`` when it is done. It passes ``self`` to the :meth:`~Signal.send` method, signifying that that particular instance was responsible for emitting the signal. .. doctest:: >>> class Processor: ... def __init__(self, name): ... self.name = name ... ... def go(self): ... ready = signal('ready') ... ready.send(self) ... print("Processing.") ... complete = signal('complete') ... complete.send(self) ... ... def __repr__(self): ... return '' % self.name ... >>> processor_a = Processor('a') >>> processor_a.go() Got a signal sent by Processing. Notice the ``complete`` signal in ``go()``? No receivers have connected to ``complete`` yet, and that's a-ok. Calling :meth:`~Signal.send` on a signal with no receivers will result in no notifications being sent, and these no-op sends are optimized to be as inexpensive as possible. Subscribing to Specific Senders ------------------------------- The default connection to a signal invokes the receiver function when any sender emits it. The :meth:`Signal.connect` function accepts an optional argument to restrict the subscription to one specific sending object: .. doctest:: >>> def b_subscriber(sender): ... print("Caught signal from processor_b.") ... assert sender.name == 'b' ... >>> processor_b = Processor('b') >>> ready.connect(b_subscriber, sender=processor_b) This function has been subscribed to ``ready`` but only when sent by ``processor_b``: .. doctest:: >>> processor_a.go() Got a signal sent by Processing. >>> processor_b.go() Got a signal sent by Caught signal from processor_b. Processing. Sending and Receiving Data Through Signals ------------------------------------------ Additional keyword arguments can be passed to :meth:`~Signal.send`. These will in turn be passed to the connected functions: .. doctest:: >>> send_data = signal('send-data') >>> @send_data.connect ... def receive_data(sender, **kw): ... print("Caught signal from %r, data %r" % (sender, kw)) ... return 'received!' ... >>> result = send_data.send('anonymous', abc=123) Caught signal from 'anonymous', data {'abc': 123} The return value of :meth:`~Signal.send` collects the return values of each connected function as a list of (``receiver function``, ``return value``) pairs: .. doctest:: >>> result [(, 'received!')] Anonymous Signals ----------------- Signals need not be named. The :class:`Signal` constructor creates a unique signal each time it is invoked. For example, an alternative implementation of the Processor from above might provide the processing signals as class attributes: .. doctest:: >>> from blinker import Signal >>> class AltProcessor: ... on_ready = Signal() ... on_complete = Signal() ... ... def __init__(self, name): ... self.name = name ... ... def go(self): ... self.on_ready.send(self) ... print("Alternate processing.") ... self.on_complete.send(self) ... ... def __repr__(self): ... return '' % self.name ... ``connect`` as a Decorator -------------------------- You may have noticed the return value of :meth:`~Signal.connect` in the console output in the sections above. This allows ``connect`` to be used as a decorator on functions: .. doctest:: >>> apc = AltProcessor('c') >>> @apc.on_complete.connect ... def completed(sender): ... print "AltProcessor %s completed!" % sender.name ... >>> apc.go() Alternate processing. AltProcessor c completed! While convenient, this form unfortunately does not allow the ``sender`` or ``weak`` arguments to be customized for the connected function. For this, :meth:`~Signal.connect_via` can be used: .. doctest:: >>> dice_roll = signal('dice_roll') >>> @dice_roll.connect_via(1) ... @dice_roll.connect_via(3) ... @dice_roll.connect_via(5) ... def odd_subscriber(sender): ... print("Observed dice roll %r." % sender) ... >>> result = dice_roll.send(3) Observed dice roll 3. Optimizing Signal Sending ------------------------- Signals are optimized to send very quickly, whether receivers are connected or not. If the data to be sent down a signal is very expensive, it can be more efficient to check to see if any receivers are connected first by testing the :attr:`~Signal.receivers` property: .. doctest:: >>> bool(signal('ready').receivers) True >>> bool(signal('complete').receivers) False >>> bool(AltProcessor.on_complete.receivers) True Checking for a receiver listening for a particular sender is also possible: .. doctest:: >>> signal('ready').has_receivers_for(processor_a) True Documenting Signals ------------------- Both named and anonymous signals can be passed a ``doc`` argument at construction to set the pydoc help text for the signal. This documentation will be picked up by most documentation generators (such as sphinx) and is nice for documenting any additional data parameters that will be sent down with the signal. See the documentation of the :obj:`receiver_connected` built-in signal for an example. More ---- Disconnecting receivers from signals, introspection of connected receivers, private namespaces for named signals and more are discussed in the :ref:`api`. blinker-1.3/blinker/__init__.py000664 000765 000024 00000000454 12164774103 016470 0ustar00jekstaff000000 000000 from blinker.base import ( ANY, NamedSignal, Namespace, Signal, WeakNamespace, receiver_connected, signal, ) __all__ = [ 'ANY', 'NamedSignal', 'Namespace', 'Signal', 'WeakNamespace', 'receiver_connected', 'signal', ] __version__ = '1.3' blinker-1.3/blinker/_saferef.py000664 000765 000024 00000022007 11652154310 016472 0ustar00jekstaff000000 000000 # extracted from Louie, http://pylouie.org/ # updated for Python 3 # # Copyright (c) 2006 Patrick K. O'Brien, Mike C. Fletcher, # Matthew R. Scott # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # * Neither the name of the nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # """Refactored 'safe reference from dispatcher.py""" import operator import sys import traceback import weakref try: callable except NameError: def callable(object): return hasattr(object, '__call__') if sys.version_info < (3,): get_self = operator.attrgetter('im_self') get_func = operator.attrgetter('im_func') else: get_self = operator.attrgetter('__self__') get_func = operator.attrgetter('__func__') def safe_ref(target, on_delete=None): """Return a *safe* weak reference to a callable target. - ``target``: The object to be weakly referenced, if it's a bound method reference, will create a BoundMethodWeakref, otherwise creates a simple weakref. - ``on_delete``: If provided, will have a hard reference stored to the callable to be called after the safe reference goes out of scope with the reference object, (either a weakref or a BoundMethodWeakref) as argument. """ try: im_self = get_self(target) except AttributeError: if callable(on_delete): return weakref.ref(target, on_delete) else: return weakref.ref(target) else: if im_self is not None: # Turn a bound method into a BoundMethodWeakref instance. # Keep track of these instances for lookup by disconnect(). assert hasattr(target, 'im_func') or hasattr(target, '__func__'), ( "safe_ref target %r has im_self, but no im_func, " "don't know how to create reference" % target) reference = BoundMethodWeakref(target=target, on_delete=on_delete) return reference class BoundMethodWeakref(object): """'Safe' and reusable weak references to instance methods. BoundMethodWeakref objects provide a mechanism for referencing a bound method without requiring that the method object itself (which is normally a transient object) is kept alive. Instead, the BoundMethodWeakref object keeps weak references to both the object and the function which together define the instance method. Attributes: - ``key``: The identity key for the reference, calculated by the class's calculate_key method applied to the target instance method. - ``deletion_methods``: Sequence of callable objects taking single argument, a reference to this object which will be called when *either* the target object or target function is garbage collected (i.e. when this object becomes invalid). These are specified as the on_delete parameters of safe_ref calls. - ``weak_self``: Weak reference to the target object. - ``weak_func``: Weak reference to the target function. Class Attributes: - ``_all_instances``: Class attribute pointing to all live BoundMethodWeakref objects indexed by the class's calculate_key(target) method applied to the target objects. This weak value dictionary is used to short-circuit creation so that multiple references to the same (object, function) pair produce the same BoundMethodWeakref instance. """ _all_instances = weakref.WeakValueDictionary() def __new__(cls, target, on_delete=None, *arguments, **named): """Create new instance or return current instance. Basically this method of construction allows us to short-circuit creation of references to already- referenced instance methods. The key corresponding to the target is calculated, and if there is already an existing reference, that is returned, with its deletion_methods attribute updated. Otherwise the new instance is created and registered in the table of already-referenced methods. """ key = cls.calculate_key(target) current = cls._all_instances.get(key) if current is not None: current.deletion_methods.append(on_delete) return current else: base = super(BoundMethodWeakref, cls).__new__(cls) cls._all_instances[key] = base base.__init__(target, on_delete, *arguments, **named) return base def __init__(self, target, on_delete=None): """Return a weak-reference-like instance for a bound method. - ``target``: The instance-method target for the weak reference, must have im_self and im_func attributes and be reconstructable via the following, which is true of built-in instance methods:: target.im_func.__get__( target.im_self ) - ``on_delete``: Optional callback which will be called when this weak reference ceases to be valid (i.e. either the object or the function is garbage collected). Should take a single argument, which will be passed a pointer to this object. """ def remove(weak, self=self): """Set self.isDead to True when method or instance is destroyed.""" methods = self.deletion_methods[:] del self.deletion_methods[:] try: del self.__class__._all_instances[self.key] except KeyError: pass for function in methods: try: if callable(function): function(self) except Exception: try: traceback.print_exc() except AttributeError: e = sys.exc_info()[1] print ('Exception during saferef %s ' 'cleanup function %s: %s' % (self, function, e)) self.deletion_methods = [on_delete] self.key = self.calculate_key(target) im_self = get_self(target) im_func = get_func(target) self.weak_self = weakref.ref(im_self, remove) self.weak_func = weakref.ref(im_func, remove) self.self_name = str(im_self) self.func_name = str(im_func.__name__) def calculate_key(cls, target): """Calculate the reference key for this reference. Currently this is a two-tuple of the id()'s of the target object and the target function respectively. """ return (id(get_self(target)), id(get_func(target))) calculate_key = classmethod(calculate_key) def __str__(self): """Give a friendly representation of the object.""" return "%s(%s.%s)" % ( self.__class__.__name__, self.self_name, self.func_name, ) __repr__ = __str__ def __nonzero__(self): """Whether we are still a valid reference.""" return self() is not None def __cmp__(self, other): """Compare with another reference.""" if not isinstance(other, self.__class__): return cmp(self.__class__, type(other)) return cmp(self.key, other.key) def __call__(self): """Return a strong reference to the bound method. If the target cannot be retrieved, then will return None, otherwise returns a bound instance method for our object and function. Note: You may call this method any number of times, as it does not invalidate the reference. """ target = self.weak_self() if target is not None: function = self.weak_func() if function is not None: return function.__get__(target) return None blinker-1.3/blinker/_utilities.py000664 000765 000024 00000010551 12164774103 017102 0ustar00jekstaff000000 000000 from weakref import ref from blinker._saferef import BoundMethodWeakref try: callable except NameError: def callable(object): return hasattr(object, '__call__') try: from collections import defaultdict except: class defaultdict(dict): def __init__(self, default_factory=None, *a, **kw): if (default_factory is not None and not hasattr(default_factory, '__call__')): raise TypeError('first argument must be callable') dict.__init__(self, *a, **kw) self.default_factory = default_factory def __getitem__(self, key): try: return dict.__getitem__(self, key) except KeyError: return self.__missing__(key) def __missing__(self, key): if self.default_factory is None: raise KeyError(key) self[key] = value = self.default_factory() return value def __reduce__(self): if self.default_factory is None: args = tuple() else: args = self.default_factory, return type(self), args, None, None, self.items() def copy(self): return self.__copy__() def __copy__(self): return type(self)(self.default_factory, self) def __deepcopy__(self, memo): import copy return type(self)(self.default_factory, copy.deepcopy(self.items())) def __repr__(self): return 'defaultdict(%s, %s)' % (self.default_factory, dict.__repr__(self)) try: from contextlib import contextmanager except ImportError: def contextmanager(fn): def oops(*args, **kw): raise RuntimeError("Python 2.5 or above is required to use " "context managers.") oops.__name__ = fn.__name__ return oops class _symbol(object): def __init__(self, name): """Construct a new named symbol.""" self.__name__ = self.name = name def __reduce__(self): return symbol, (self.name,) def __repr__(self): return self.name _symbol.__name__ = 'symbol' class symbol(object): """A constant symbol. >>> symbol('foo') is symbol('foo') True >>> symbol('foo') foo A slight refinement of the MAGICCOOKIE=object() pattern. The primary advantage of symbol() is its repr(). They are also singletons. Repeated calls of symbol('name') will all return the same instance. """ symbols = {} def __new__(cls, name): try: return cls.symbols[name] except KeyError: return cls.symbols.setdefault(name, _symbol(name)) try: text = (str, unicode) except NameError: text = str def hashable_identity(obj): if hasattr(obj, '__func__'): return (id(obj.__func__), id(obj.__self__)) elif hasattr(obj, 'im_func'): return (id(obj.im_func), id(obj.im_self)) elif isinstance(obj, text): return obj else: return id(obj) WeakTypes = (ref, BoundMethodWeakref) class annotatable_weakref(ref): """A weakref.ref that supports custom instance attributes.""" def reference(object, callback=None, **annotations): """Return an annotated weak ref.""" if callable(object): weak = callable_reference(object, callback) else: weak = annotatable_weakref(object, callback) for key, value in annotations.items(): setattr(weak, key, value) return weak def callable_reference(object, callback=None): """Return an annotated weak ref, supporting bound instance methods.""" if hasattr(object, 'im_self') and object.im_self is not None: return BoundMethodWeakref(target=object, on_delete=callback) elif hasattr(object, '__self__') and object.__self__ is not None: return BoundMethodWeakref(target=object, on_delete=callback) return annotatable_weakref(object, callback) class lazy_property(object): """A @property that is only evaluated once.""" def __init__(self, deferred): self._deferred = deferred self.__doc__ = deferred.__doc__ def __get__(self, obj, cls): if obj is None: return self value = self._deferred(obj) setattr(obj, self._deferred.__name__, value) return value blinker-1.3/blinker/base.py000664 000765 000024 00000034777 12164774103 015662 0ustar00jekstaff000000 000000 # -*- coding: utf-8; fill-column: 76 -*- """Signals and events. A small implementation of signals, inspired by a snippet of Django signal API client code seen in a blog post. Signals are first-class objects and each manages its own receivers and message emission. The :func:`signal` function provides singleton behavior for named signals. """ from warnings import warn from weakref import WeakValueDictionary from blinker._utilities import ( WeakTypes, contextmanager, defaultdict, hashable_identity, lazy_property, reference, symbol, ) ANY = symbol('ANY') ANY.__doc__ = 'Token for "any sender".' ANY_ID = 0 class Signal(object): """A notification emitter.""" #: An :obj:`ANY` convenience synonym, allows ``Signal.ANY`` #: without an additional import. ANY = ANY @lazy_property def receiver_connected(self): """Emitted after each :meth:`connect`. The signal sender is the signal instance, and the :meth:`connect` arguments are passed through: *receiver*, *sender*, and *weak*. .. versionadded:: 1.2 """ return Signal(doc="Emitted after a receiver connects.") @lazy_property def receiver_disconnected(self): """Emitted after :meth:`disconnect`. The sender is the signal instance, and the :meth:`disconnect` arguments are passed through: *receiver* and *sender*. Note, this signal is emitted **only** when :meth:`disconnect` is called explicitly. The disconnect signal can not be emitted by an automatic disconnect (due to a weakly referenced receiver or sender going out of scope), as the receiver and/or sender instances are no longer available for use at the time this signal would be emitted. An alternative approach is available by subscribing to :attr:`receiver_connected` and setting up a custom weakref cleanup callback on weak receivers and senders. .. versionadded:: 1.2 """ return Signal(doc="Emitted after a receiver disconnects.") def __init__(self, doc=None): """ :param doc: optional. If provided, will be assigned to the signal's __doc__ attribute. """ if doc: self.__doc__ = doc #: A mapping of connected receivers. #: #: The values of this mapping are not meaningful outside of the #: internal :class:`Signal` implementation, however the boolean value #: of the mapping is useful as an extremely efficient check to see if #: any receivers are connected to the signal. self.receivers = {} self._by_receiver = defaultdict(set) self._by_sender = defaultdict(set) self._weak_senders = {} def connect(self, receiver, sender=ANY, weak=True): """Connect *receiver* to signal events sent by *sender*. :param receiver: A callable. Will be invoked by :meth:`send` with `sender=` as a single positional argument and any \*\*kwargs that were provided to a call to :meth:`send`. :param sender: Any object or :obj:`ANY`, defaults to ``ANY``. Restricts notifications delivered to *receiver* to only those :meth:`send` emissions sent by *sender*. If ``ANY``, the receiver will always be notified. A *receiver* may be connected to multiple *sender* values on the same Signal through multiple calls to :meth:`connect`. :param weak: If true, the Signal will hold a weakref to *receiver* and automatically disconnect when *receiver* goes out of scope or is garbage collected. Defaults to True. """ receiver_id = hashable_identity(receiver) if weak: receiver_ref = reference(receiver, self._cleanup_receiver) receiver_ref.receiver_id = receiver_id else: receiver_ref = receiver if sender is ANY: sender_id = ANY_ID else: sender_id = hashable_identity(sender) self.receivers.setdefault(receiver_id, receiver_ref) self._by_sender[sender_id].add(receiver_id) self._by_receiver[receiver_id].add(sender_id) del receiver_ref if sender is not ANY and sender_id not in self._weak_senders: # wire together a cleanup for weakref-able senders try: sender_ref = reference(sender, self._cleanup_sender) sender_ref.sender_id = sender_id except TypeError: pass else: self._weak_senders.setdefault(sender_id, sender_ref) del sender_ref # broadcast this connection. if receivers raise, disconnect. if ('receiver_connected' in self.__dict__ and self.receiver_connected.receivers): try: self.receiver_connected.send(self, receiver=receiver, sender=sender, weak=weak) except: self.disconnect(receiver, sender) raise if receiver_connected.receivers and self is not receiver_connected: try: receiver_connected.send(self, receiver_arg=receiver, sender_arg=sender, weak_arg=weak) except: self.disconnect(receiver, sender) raise return receiver def connect_via(self, sender, weak=False): """Connect the decorated function as a receiver for *sender*. :param sender: Any object or :obj:`ANY`. The decorated function will only receive :meth:`send` emissions sent by *sender*. If ``ANY``, the receiver will always be notified. A function may be decorated multiple times with differing *sender* values. :param weak: If true, the Signal will hold a weakref to the decorated function and automatically disconnect when *receiver* goes out of scope or is garbage collected. Unlike :meth:`connect`, this defaults to False. The decorated function will be invoked by :meth:`send` with `sender=` as a single positional argument and any \*\*kwargs that were provided to the call to :meth:`send`. .. versionadded:: 1.1 """ def decorator(fn): self.connect(fn, sender, weak) return fn return decorator @contextmanager def connected_to(self, receiver, sender=ANY): """Execute a block with the signal temporarily connected to *receiver*. :param receiver: a receiver callable :param sender: optional, a sender to filter on This is a context manager for use in the ``with`` statement. It can be useful in unit tests. *receiver* is connected to the signal for the duration of the ``with`` block, and will be disconnected automatically when exiting the block: .. testsetup:: from __future__ import with_statement from blinker import Signal on_ready = Signal() receiver = lambda sender: None .. testcode:: with on_ready.connected_to(receiver): # do stuff on_ready.send(123) .. versionadded:: 1.1 """ self.connect(receiver, sender=sender, weak=False) try: yield None except: self.disconnect(receiver) raise else: self.disconnect(receiver) def temporarily_connected_to(self, receiver, sender=ANY): """An alias for :meth:`connected_to`. :param receiver: a receiver callable :param sender: optional, a sender to filter on .. versionadded:: 0.9 .. versionchanged:: 1.1 Renamed to :meth:`connected_to`. ``temporarily_connected_to`` was deprecated in 1.2 and removed in a subsequent version. """ warn("temporarily_connected_to is deprecated; " "use connected_to instead.", DeprecationWarning) return self.connected_to(receiver, sender) def send(self, *sender, **kwargs): """Emit this signal on behalf of *sender*, passing on \*\*kwargs. Returns a list of 2-tuples, pairing receivers with their return value. The ordering of receiver notification is undefined. :param \*sender: Any object or ``None``. If omitted, synonymous with ``None``. Only accepts one positional argument. :param \*\*kwargs: Data to be sent to receivers. """ # Using '*sender' rather than 'sender=None' allows 'sender' to be # used as a keyword argument- i.e. it's an invisible name in the # function signature. if len(sender) == 0: sender = None elif len(sender) > 1: raise TypeError('send() accepts only one positional argument, ' '%s given' % len(sender)) else: sender = sender[0] if not self.receivers: return [] else: return [(receiver, receiver(sender, **kwargs)) for receiver in self.receivers_for(sender)] def has_receivers_for(self, sender): """True if there is probably a receiver for *sender*. Performs an optimistic check only. Does not guarantee that all weakly referenced receivers are still alive. See :meth:`receivers_for` for a stronger search. """ if not self.receivers: return False if self._by_sender[ANY_ID]: return True if sender is ANY: return False return hashable_identity(sender) in self._by_sender def receivers_for(self, sender): """Iterate all live receivers listening for *sender*.""" # TODO: test receivers_for(ANY) if self.receivers: sender_id = hashable_identity(sender) if sender_id in self._by_sender: ids = (self._by_sender[ANY_ID] | self._by_sender[sender_id]) else: ids = self._by_sender[ANY_ID].copy() for receiver_id in ids: receiver = self.receivers.get(receiver_id) if receiver is None: continue if isinstance(receiver, WeakTypes): strong = receiver() if strong is None: self._disconnect(receiver_id, ANY_ID) continue receiver = strong yield receiver def disconnect(self, receiver, sender=ANY): """Disconnect *receiver* from this signal's events. :param receiver: a previously :meth:`connected` callable :param sender: a specific sender to disconnect from, or :obj:`ANY` to disconnect from all senders. Defaults to ``ANY``. """ if sender is ANY: sender_id = ANY_ID else: sender_id = hashable_identity(sender) receiver_id = hashable_identity(receiver) self._disconnect(receiver_id, sender_id) if ('receiver_disconnected' in self.__dict__ and self.receiver_disconnected.receivers): self.receiver_disconnected.send(self, receiver=receiver, sender=sender) def _disconnect(self, receiver_id, sender_id): if sender_id == ANY_ID: if self._by_receiver.pop(receiver_id, False): for bucket in self._by_sender.values(): bucket.discard(receiver_id) self.receivers.pop(receiver_id, None) else: self._by_sender[sender_id].discard(receiver_id) def _cleanup_receiver(self, receiver_ref): """Disconnect a receiver from all senders.""" self._disconnect(receiver_ref.receiver_id, ANY_ID) def _cleanup_sender(self, sender_ref): """Disconnect all receivers from a sender.""" sender_id = sender_ref.sender_id assert sender_id != ANY_ID self._weak_senders.pop(sender_id, None) for receiver_id in self._by_sender.pop(sender_id, ()): self._by_receiver[receiver_id].discard(sender_id) def _clear_state(self): """Throw away all signal state. Useful for unit tests.""" self._weak_senders.clear() self.receivers.clear() self._by_sender.clear() self._by_receiver.clear() receiver_connected = Signal("""\ Sent by a :class:`Signal` after a receiver connects. :argument: the Signal that was connected to :keyword receiver_arg: the connected receiver :keyword sender_arg: the sender to connect to :keyword weak_arg: true if the connection to receiver_arg is a weak reference .. deprecated:: 1.2 As of 1.2, individual signals have their own private :attr:`~Signal.receiver_connected` and :attr:`~Signal.receiver_disconnected` signals with a slightly simplified call signature. This global signal is planned to be removed in 1.6. """) class NamedSignal(Signal): """A named generic notification emitter.""" def __init__(self, name, doc=None): Signal.__init__(self, doc) #: The name of this signal. self.name = name def __repr__(self): base = Signal.__repr__(self) return "%s; %r>" % (base[:-1], self.name) class Namespace(dict): """A mapping of signal names to signals.""" def signal(self, name, doc=None): """Return the :class:`NamedSignal` *name*, creating it if required. Repeated calls to this function will return the same signal object. """ try: return self[name] except KeyError: return self.setdefault(name, NamedSignal(name, doc)) class WeakNamespace(WeakValueDictionary): """A weak mapping of signal names to signals. Automatically cleans up unused Signals when the last reference goes out of scope. This namespace implementation exists for a measure of legacy compatibility with Blinker <= 1.2, and may be dropped in the future. """ def signal(self, name, doc=None): """Return the :class:`NamedSignal` *name*, creating it if required. Repeated calls to this function will return the same signal object. """ try: return self[name] except KeyError: return self.setdefault(name, NamedSignal(name, doc)) signal = Namespace().signal