././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1676664578.5341449 PyDispatcher-2.0.7/0000755000175000017500000000000014373757403014330 5ustar00mcfletchmcfletch././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1574192583.0 PyDispatcher-2.0.7/MANIFEST.in0000644000175000017500000000050613565042707016063 0ustar00mcfletchmcfletchinclude MANIFEST.in include license.txt include *.py recursive-include docs *.html recursive-include docs/images *.png recursive-include docs/style *.css recursive-include docs/pydoc *.html *.py recursive-include examples *.py recursive-include tests *.py global-exclude *.bat global-exclude ./CVS global-exclude .cvsignore ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1676664578.5341449 PyDispatcher-2.0.7/PKG-INFO0000644000175000017500000000453514373757403015434 0ustar00mcfletchmcfletchMetadata-Version: 2.1 Name: PyDispatcher Version: 2.0.7 Summary: Multi-producer multi-consumer in-memory signal dispatch system Home-page: https://github.com/mcfletch/pydispatcher Download-URL: https://pypi.org/project/pydispatcher/ Author: Patrick K. O'Brien Maintainer: Mike C. Fletcher Maintainer-email: "Mike C. Fletcher" License: BSD Keywords: dispatcher,dispatch,pydispatch,event,signal,sender,receiver,propagate,multi-consumer,multi-producer,saferef,robustapply,apply Platform: Any Classifier: License :: OSI Approved :: BSD License Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 3 Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Intended Audience :: Developers Description-Content-Type: text/markdown Provides-Extra: dev # PyDispatcher Multi-producer Multi-consumer Observables PyDispatcher provides the Python programmer with a multiple-producer-multiple-consumer signal-registration and routing infrastructure for use in multiple contexts. The mechanism of PyDispatcher started life as a highly rated [recipe](http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/87056) in the [Python Cookbook](http://aspn.activestate.com/ASPN/Python/Cookbook/). The [project](https://github.com/mcfletch/pydispatcher) aims to include various enhancements to the recipe developed during use in various applications. It is primarily maintained by [Mike Fletcher](http://www.vrplumber.com). A derivative of the project provides the Django web framework's "signal" system. ## Installation PyDispatcher is available on PyPI via standard PIP: ``` pip install PyDispatcher ``` [![Latest PyPI Version](https://img.shields.io/pypi/v/pydispatcher.svg)](https://pypi.python.org/pypi/pydispatcher) [![Latest PyPI Version](https://img.shields.io/pypi/dm/pydispatcher.svg)](https://pypi.python.org/pypi/pydispatcher) ## Usage [Documentation](https://mcfletch.github.io/pydispatcher/) is available for detailed usage, but the basic idea is: ``` from pydispatch import dispatcher metaKey = "moo" MyNode = object() event = {"sample": "event"} def callback(event=None): """Handle signal being sent""" print("Signal received", event) dispatcher.connect(callback, sender=MyNode, signal=metaKey) dispatcher.send(metaKey, MyNode, event=event) ``` ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1676664578.5341449 PyDispatcher-2.0.7/PyDispatcher.egg-info/0000755000175000017500000000000014373757403020421 5ustar00mcfletchmcfletch././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1676664578.0 PyDispatcher-2.0.7/PyDispatcher.egg-info/PKG-INFO0000644000175000017500000000453514373757402021524 0ustar00mcfletchmcfletchMetadata-Version: 2.1 Name: PyDispatcher Version: 2.0.7 Summary: Multi-producer multi-consumer in-memory signal dispatch system Home-page: https://github.com/mcfletch/pydispatcher Download-URL: https://pypi.org/project/pydispatcher/ Author: Patrick K. O'Brien Maintainer: Mike C. Fletcher Maintainer-email: "Mike C. Fletcher" License: BSD Keywords: dispatcher,dispatch,pydispatch,event,signal,sender,receiver,propagate,multi-consumer,multi-producer,saferef,robustapply,apply Platform: Any Classifier: License :: OSI Approved :: BSD License Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 3 Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Intended Audience :: Developers Description-Content-Type: text/markdown Provides-Extra: dev # PyDispatcher Multi-producer Multi-consumer Observables PyDispatcher provides the Python programmer with a multiple-producer-multiple-consumer signal-registration and routing infrastructure for use in multiple contexts. The mechanism of PyDispatcher started life as a highly rated [recipe](http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/87056) in the [Python Cookbook](http://aspn.activestate.com/ASPN/Python/Cookbook/). The [project](https://github.com/mcfletch/pydispatcher) aims to include various enhancements to the recipe developed during use in various applications. It is primarily maintained by [Mike Fletcher](http://www.vrplumber.com). A derivative of the project provides the Django web framework's "signal" system. ## Installation PyDispatcher is available on PyPI via standard PIP: ``` pip install PyDispatcher ``` [![Latest PyPI Version](https://img.shields.io/pypi/v/pydispatcher.svg)](https://pypi.python.org/pypi/pydispatcher) [![Latest PyPI Version](https://img.shields.io/pypi/dm/pydispatcher.svg)](https://pypi.python.org/pypi/pydispatcher) ## Usage [Documentation](https://mcfletch.github.io/pydispatcher/) is available for detailed usage, but the basic idea is: ``` from pydispatch import dispatcher metaKey = "moo" MyNode = object() event = {"sample": "event"} def callback(event=None): """Handle signal being sent""" print("Signal received", event) dispatcher.connect(callback, sender=MyNode, signal=metaKey) dispatcher.send(metaKey, MyNode, event=event) ``` ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1676664578.0 PyDispatcher-2.0.7/PyDispatcher.egg-info/SOURCES.txt0000644000175000017500000000177614373757402022317 0ustar00mcfletchmcfletchMANIFEST.in README.md license.txt pyproject.toml setup.cfg setup.py PyDispatcher.egg-info/PKG-INFO PyDispatcher.egg-info/SOURCES.txt PyDispatcher.egg-info/dependency_links.txt PyDispatcher.egg-info/requires.txt PyDispatcher.egg-info/top_level.txt docs/index.html docs/images/greypinstripe.png docs/pydoc/__init__.py docs/pydoc/builddocs.py docs/pydoc/pydispatch.__init__.html docs/pydoc/pydispatch.dispatcher.html docs/pydoc/pydispatch.errors.html docs/pydoc/pydispatch.html docs/pydoc/pydispatch.robust.html docs/pydoc/pydispatch.robustapply.html docs/pydoc/pydispatch.saferef.html docs/pydoc/pydoc2.py docs/pydoc/weakref.html docs/style/sitestyle.css examples/__init__.py examples/extra_args.py examples/hello_messages.py examples/minimal.py examples/simple_sample.py pydispatch/__init__.py pydispatch/dispatcher.py pydispatch/errors.py pydispatch/robust.py pydispatch/robustapply.py pydispatch/saferef.py tests/__init__.py tests/test_dispatcher.py tests/test_packaging.py tests/test_robustapply.py tests/test_saferef.py././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1676664578.0 PyDispatcher-2.0.7/PyDispatcher.egg-info/dependency_links.txt0000644000175000017500000000000114373757402024466 0ustar00mcfletchmcfletch ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1676664578.0 PyDispatcher-2.0.7/PyDispatcher.egg-info/requires.txt0000644000175000017500000000001314373757402023012 0ustar00mcfletchmcfletch [dev] tox ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1676664578.0 PyDispatcher-2.0.7/PyDispatcher.egg-info/top_level.txt0000644000175000017500000000001314373757402023144 0ustar00mcfletchmcfletchpydispatch ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1661980653.0 PyDispatcher-2.0.7/README.md0000644000175000017500000000275314303747755015620 0ustar00mcfletchmcfletch# PyDispatcher Multi-producer Multi-consumer Observables PyDispatcher provides the Python programmer with a multiple-producer-multiple-consumer signal-registration and routing infrastructure for use in multiple contexts. The mechanism of PyDispatcher started life as a highly rated [recipe](http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/87056) in the [Python Cookbook](http://aspn.activestate.com/ASPN/Python/Cookbook/). The [project](https://github.com/mcfletch/pydispatcher) aims to include various enhancements to the recipe developed during use in various applications. It is primarily maintained by [Mike Fletcher](http://www.vrplumber.com). A derivative of the project provides the Django web framework's "signal" system. ## Installation PyDispatcher is available on PyPI via standard PIP: ``` pip install PyDispatcher ``` [![Latest PyPI Version](https://img.shields.io/pypi/v/pydispatcher.svg)](https://pypi.python.org/pypi/pydispatcher) [![Latest PyPI Version](https://img.shields.io/pypi/dm/pydispatcher.svg)](https://pypi.python.org/pypi/pydispatcher) ## Usage [Documentation](https://mcfletch.github.io/pydispatcher/) is available for detailed usage, but the basic idea is: ``` from pydispatch import dispatcher metaKey = "moo" MyNode = object() event = {"sample": "event"} def callback(event=None): """Handle signal being sent""" print("Signal received", event) dispatcher.connect(callback, sender=MyNode, signal=metaKey) dispatcher.send(metaKey, MyNode, event=event) ``` ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1676664578.5341449 PyDispatcher-2.0.7/docs/0000755000175000017500000000000014373757403015260 5ustar00mcfletchmcfletch././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1676664578.5341449 PyDispatcher-2.0.7/docs/images/0000755000175000017500000000000014373757403016525 5ustar00mcfletchmcfletch././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1574192583.0 PyDispatcher-2.0.7/docs/images/greypinstripe.png0000644000175000017500000000021313565042707022127 0ustar00mcfletchmcfletchPNG  IHDR'gAMA@ cHRMntFdIX*LIDATxbb&ښ<IENDB`././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1661978464.0 PyDispatcher-2.0.7/docs/index.html0000644000175000017500000002400014303743540017237 0ustar00mcfletchmcfletch Python Dispatch Package

PyDispatcher

PyDispatcher provides the Python programmer with a multiple-producer-multiple-consumer signal-registration and routing infrastructure for use in multiple contexts. The mechanism of PyDispatcher started life as a highly rated recipe in the Python Cookbook. The project aims to include various enhancements to the recipe developed during use in various applications. It is primarily maintained by Mike Fletcher. A derivative of the project provides the Django web framework's "signal" system.

To be more concrete about what PyDispatcher does for you:

The dispatcher mechanism is particularly useful when constructing Model-View-Controller style applications where it is not desirable to have the Model objects aware of the event model.

Acquisition and Installation

PyDispatcher is available as a standard Python distutils installation package from the Python Package Index (PyPI). To install, run:

pip install PyDispatcher

PyDispatcher does not include any binary packages, so there should be no issues in installation. PyDispatcher is maintained on the [git project on GitHub](https://github.com/mcfletch/pydispatcher). To help develop, check out the project like so:

git clone https://github.com/mcfletch/pydispatcher.git

You can send a pull request via GitHub

Documentation

You can find usage samples in the examples directory of the distribution. The dispatcher module's reference documentation is currently the major source of information regarding usage.

PyDispatcher welcomes contributions, suggestions, and feedback from users in the pydispatcher-dev mailing list.

Usage

To set up a function to receive signals:

from pydispatch import dispatcher
SIGNAL = 'my-first-signal'

def handle_event( sender ):
    """Simple event handler"""
    print('Signal was sent by', sender)
    dispatcher.connect( handle_event, signal=SIGNAL, sender=dispatcher.Any )

The use of the Any object allows the handler to listen for messages from any Sender or to listen to Any message being sent. To send messages:

first_sender = object()
second_sender = {}
def main( ):
    dispatcher.send( signal=SIGNAL, sender=first_sender )
    dispatcher.send( signal=SIGNAL, sender=second_sender )

Which causes the following to be printed:

Signal was sent by <object object at 0x196a090>
Signal was sent by {}

Handler Functions

Handler functions in PyDispatcher are relatively loose in their definition. A handler can simply declare the parameters it would like to receive and receive only those parameters when the signal is sent. The sender can include extra parameters for those handlers which require them without worrying about whether a more generic handler can accept them:

def handle_specific_event( sender, moo ):
    """Handle a simple event, requiring a "moo" parameter"""
    print 'Specialized event for %(sender)s moo=%(moo)r'%locals()
dispatcher.connect( handle_specific_event, signal=SIGNAL2, sender=dispatcher.Any )

This connection requires that all senders of the particular signal send a "moo" parameter, but a handler that listens for all events and does not provide a "moo" parameter would silently ignore the sender having passed a "moo".

2 parameters are always available to handler functions if they would like to use them:

Parameter Value
sender Object from/for which the event was sent, can be dispatcher.Anonymous for anonymous signals
signal Signal object used when sending

Positional arguments and named arguments are passed through, but if positional arguments are used, they will fill in the parameters of the receiver in order and cause conflicts if named parameters are specified which match their names. Generally it is advisable to use named arguments when defining sending messages.

Real World Examples

OpenGLContext uses PyDispatcher to provide a link between PyVRML97 (model level) and OpenGLContext (the controller and view levels). Changes to fields in the model send events, as do changes to object lists. A cache observes these changes and allows the view/model level to register dependencies on particular fields of particular nodes. The result is that rendering code can cache data extensively and have the caches consistently invalidated when their data-dependencies are changed.

Related Software

Release Notes

././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1676664578.5341449 PyDispatcher-2.0.7/docs/pydoc/0000755000175000017500000000000014373757403016376 5ustar00mcfletchmcfletch././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1574192583.0 PyDispatcher-2.0.7/docs/pydoc/__init__.py0000644000175000017500000000045613565042707020510 0ustar00mcfletchmcfletch"""pydoc documentation system with enhancements and automatic local builder This package is based on the standard pydoc package, with a few minor enhancements, and a slightly modified format. An automatic mechanism for generating extensive documentation for the OpenGLContext project is provided. """././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1574192583.0 PyDispatcher-2.0.7/docs/pydoc/builddocs.py0000755000175000017500000000104413565042707020716 0ustar00mcfletchmcfletch#! /usr/bin/env python """Script to automatically generate OpenGLContext documentation""" import pydoc2 if __name__ == "__main__": excludes = [ "math", "string", ] stops = [ "OpenGL.Demo.NeHe", "OpenGL.Demo.GLE", "OpenGL.Demo.da", ] modules = [ "pydispatch", "weakref", ] pydoc2.PackageDocumentationGenerator( baseModules = modules, destinationDirectory = ".", exclusions = excludes, recursionStops = stops, ).process () ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1661979366.0 PyDispatcher-2.0.7/docs/pydoc/pydispatch.__init__.html0000644000175000017500000000456114303745346023174 0ustar00mcfletchmcfletch Python: module pydispatch.__init__
 
 
pydispatch.__init__ (version 2.0.6)
index
/home/mcfletch/OpenGL-dev/pydispatcher/pydispatch/__init__.py

Multi-consumer multi-producer dispatching mechanism

 
Data
        __author__ = "Patrick K. O'Brien"
__cached__ = '/home/mcfletch/OpenGL-dev/pydispatcher/pydispatch/__pycache__/__init__.cpython-310.pyc'
__file__ = '/home/mcfletch/OpenGL-dev/pydispatcher/pydispatch/__init__.py'
__license__ = 'BSD-style, see license.txt for details'
__loader__ = <_frozen_importlib_external.SourceFileLoader object>
__name__ = 'pydispatch.__init__'
__package__ = 'pydispatch'
__spec__ = ModuleSpec(name='pydispatch.__init__', loader=<_.../OpenGL-dev/pydispatcher/pydispatch/__init__.py')
__version__ = '2.0.6'

 
Author
        Patrick K. O'Brien
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1661979366.0 PyDispatcher-2.0.7/docs/pydoc/pydispatch.dispatcher.html0000644000175000017500000006060014303745346023557 0ustar00mcfletchmcfletch Python: module pydispatch.dispatcher
 
 
pydispatch.dispatcher
index
/home/mcfletch/OpenGL-dev/pydispatcher/pydispatch/dispatcher.py

Multiple-producer-multiple-consumer signal-dispatching
 
dispatcher is the core of the PyDispatcher system,
providing the primary API and the core logic for the
system.
 
Module attributes of note:
 
    Any -- Singleton used to signal either "Any Sender" or
        "Any Signal".  See documentation of the _Any class.
    Anonymous -- Singleton used to signal "Anonymous Sender"
        See documentation of the _Anonymous class.
 
Internal attributes:
    WEAKREF_TYPES -- tuple of types/classes which represent
        weak references to receivers, and thus must be de-
        referenced on retrieval to retrieve the callable
        object
    connections -- { senderkey (id) : { signal : [receivers...]}}
    senders -- { senderkey (id) : weakref(sender) }
        used for cleaning up sender references on sender
        deletion
    sendersBack -- { receiverkey (id) : [senderkey (id)...] }
        used for cleaning up receiver references on receiver
        deletion, (considerably speeds up the cleanup process
        vs. the original code.)

 
Modules
       
pydispatch.errors
pydispatch.robustapply
pydispatch.saferef
weakref

 
Classes
       
object
_Parameter
_Anonymous
_Any

 
class _Anonymous(_Parameter)
    Singleton used to signal "Anonymous Sender"
 
The Anonymous object is used to signal that the sender
of a message is not specified (as distinct from being
"any sender").  Registering callbacks for Anonymous
will only receive messages sent without senders.  Sending
with anonymous will only send messages to those receivers
registered for Any or Anonymous.
 
Note:
    The default sender for connect is Any, while the
    default sender for send is Anonymous.  This has
    the effect that if you do not specify any senders
    in either function then all messages are routed
    as though there was a single sender (Anonymous)
    being used everywhere.
 
 
Method resolution order:
_Anonymous
_Parameter
object

Methods inherited from _Parameter:
__repr__(self)
Return repr(self).

Data descriptors inherited from _Parameter:
__dict__
dictionary for instance variables (if defined)
__weakref__
list of weak references to the object (if defined)

 
class _Any(_Parameter)
    Singleton used to signal either "Any Sender" or "Any Signal"
 
The Any object can be used with connect, disconnect,
send, or sendExact to signal that the parameter given
Any should react to all senders/signals, not just
a particular sender/signal.
 
 
Method resolution order:
_Any
_Parameter
object

Methods inherited from _Parameter:
__repr__(self)
Return repr(self).

Data descriptors inherited from _Parameter:
__dict__
dictionary for instance variables (if defined)
__weakref__
list of weak references to the object (if defined)

 
class _Parameter(object)
    Used to represent default parameter values.
 
  Methods defined here:
__repr__(self)
Return repr(self).

Data descriptors defined here:
__dict__
dictionary for instance variables (if defined)
__weakref__
list of weak references to the object (if defined)

 
Functions
       
_cleanupConnections(senderkey, signal)
Delete any empty signals for senderkey. Delete senderkey if empty.
_killBackref(receiver, senderkey)
Do the actual removal of back reference from receiver to senderkey
_removeBackrefs(senderkey)
Remove all back-references to this senderkey
_removeOldBackRefs(senderkey, signal, receiver, receivers)
Kill old sendersBack references from receiver
 
This guards against multiple registration of the same
receiver for a given signal and sender leaking memory
as old back reference records build up.
 
Also removes old receiver instance from receivers
_removeReceiver(receiver)
Remove receiver from connections.
_removeSender(senderkey)
Remove senderkey from connections.
connect(receiver, signal=_Any, sender=_Any, weak=True)
Connect receiver to sender for signal
 
receiver -- a callable Python object which is to receive
    messages/signals/events.  Receivers must be hashable
    objects.
 
    if weak is True, then receiver must be weak-referencable
    (more precisely saferef.safeRef() must be able to create
    a reference to the receiver).
 
    Receivers are fairly flexible in their specification,
    as the machinery in the robustApply module takes care
    of most of the details regarding figuring out appropriate
    subsets of the sent arguments to apply to a given
    receiver.
 
    Note:
        if receiver is itself a weak reference (a callable),
        it will be de-referenced by the system's machinery,
        so *generally* weak references are not suitable as
        receivers, though some use might be found for the
        facility whereby a higher-level library passes in
        pre-weakrefed receiver references.
 
signal -- the signal to which the receiver should respond
 
    if Any, receiver will receive any signal from the
    indicated sender (which might also be Any, but is not
    necessarily Any).
    
    Otherwise must be a hashable Python object other than
    None (DispatcherError raised on None).
    
sender -- the sender to which the receiver should respond
 
    if Any, receiver will receive the indicated signals
    from any sender.
    
    if Anonymous, receiver will only receive indicated
    signals from send/sendExact which do not specify a
    sender, or specify Anonymous explicitly as the sender.
 
    Otherwise can be any python object.
    
weak -- whether to use weak references to the receiver
    By default, the module will attempt to use weak
    references to the receiver objects.  If this parameter
    is false, then strong references will be used.
 
returns None, may raise DispatcherTypeError
disconnect(receiver, signal=_Any, sender=_Any, weak=True)
Disconnect receiver from sender for signal
 
receiver -- the registered receiver to disconnect
signal -- the registered signal to disconnect
sender -- the registered sender to disconnect
weak -- the weakref state to disconnect
 
disconnect reverses the process of connect,
the semantics for the individual elements are
logically equivalent to a tuple of
(receiver, signal, sender, weak) used as a key
to be deleted from the internal routing tables.
(The actual process is slightly more complex
but the semantics are basically the same).
 
Note:
    Using disconnect is not required to cleanup
    routing when an object is deleted, the framework
    will remove routes for deleted objects
    automatically.  It's only necessary to disconnect
    if you want to stop routing to a live object.
    
returns None, may raise DispatcherTypeError or
    DispatcherKeyError
getAllReceivers(sender=_Any, signal=_Any)
Get list of all receivers from global tables
 
This gets all receivers which should receive
the given signal from sender, each receiver should
be produced only once by the resulting generator
getReceivers(sender=_Any, signal=_Any)
Get list of receivers from global tables
 
This utility function allows you to retrieve the
raw list of receivers from the connections table
for the given sender and signal pair.
 
Note:
    there is no guarantee that this is the actual list
    stored in the connections table, so the value
    should be treated as a simple iterable/truth value
    rather than, for instance a list to which you
    might append new records.
 
Normally you would use liveReceiversgetReceivers( ...))
to retrieve the actual receiver objects as an iterable
object.
liveReceivers(receivers)
Filter sequence of receivers to get resolved, live receivers
 
This is a generator which will iterate over
the passed sequence, checking for weak references
and resolving them, then returning all live
receivers.
send(signal=_Any, sender=_Anonymous, *arguments, **named)
Send signal from sender to all connected receivers.
 
signal -- (hashable) signal value, see connect for details
 
sender -- the sender of the signal
 
    if Any, only receivers registered for Any will receive
    the message.
 
    if Anonymous, only receivers registered to receive
    messages from Anonymous or Any will receive the message
 
    Otherwise can be any python object (normally one
    registered with a connect if you actually want
    something to occur).
 
arguments -- positional arguments which will be passed to
    *all* receivers. Note that this may raise TypeErrors
    if the receivers do not allow the particular arguments.
    Note also that arguments are applied before named
    arguments, so they should be used with care.
 
named -- named arguments which will be filtered according
    to the parameters of the receivers to only provide those
    acceptable to the receiver.
 
Return a list of tuple pairs [(receiver, response), ... ]
 
if any receiver raises an error, the error propagates back
through send, terminating the dispatch loop, so it is quite
possible to not have all receivers called if a raises an
error.
sendExact(signal=_Any, sender=_Anonymous, *arguments, **named)
Send signal only to those receivers registered for exact message
 
sendExact allows for avoiding Any/Anonymous registered
handlers, sending only to those receivers explicitly
registered for a particular signal on a particular
sender.

 
Data
        Anonymous = _Anonymous
Any = _Any
WEAKREF_TYPES = (<class 'weakref.ReferenceType'>, <class 'pydispatch.saferef.BoundMethodWeakref'>)
__cached__ = '/home/mcfletch/OpenGL-dev/pydispatcher/pydispatch/__pycache__/dispatcher.cpython-310.pyc'
__file__ = '/home/mcfletch/OpenGL-dev/pydispatcher/pydispatch/dispatcher.py'
__loader__ = <_frozen_importlib_external.SourceFileLoader object>
__name__ = 'pydispatch.dispatcher'
__package__ = 'pydispatch'
__spec__ = ModuleSpec(name='pydispatch.dispatcher', loader=...penGL-dev/pydispatcher/pydispatch/dispatcher.py')
connections = {}
senders = {}
sendersBack = {}
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1661979366.0 PyDispatcher-2.0.7/docs/pydoc/pydispatch.errors.html0000644000175000017500000003623714303745346022756 0ustar00mcfletchmcfletch Python: module pydispatch.errors
 
 
pydispatch.errors
index
/home/mcfletch/OpenGL-dev/pydispatcher/pydispatch/errors.py

Error types for dispatcher mechanism

 
Classes
       
Exception(BaseException)
DispatcherError
DispatcherKeyError(KeyError, DispatcherError)
DispatcherTypeError(TypeError, DispatcherError)
KeyError(LookupError)
DispatcherKeyError(KeyError, DispatcherError)
TypeError(Exception)
DispatcherTypeError(TypeError, DispatcherError)

 
class DispatcherError(Exception)
    Base class for all Dispatcher errors
 
 
Method resolution order:
DispatcherError
Exception
BaseException
object

Data descriptors defined here:
__weakref__
list of weak references to the object (if defined)

Methods inherited from Exception:
__init__(self, /, *args, **kwargs)
Initialize self.  See help(type(self)) for accurate signature.

Static methods inherited from Exception:
__new__(*args, **kwargs) from type
Create and return a new object.  See help(type) for accurate signature.

Methods inherited from BaseException:
__delattr__(self, name, /)
Implement delattr(self, name).
__getattribute__(self, name, /)
Return getattr(self, name).
__reduce__(...)
Helper for pickle.
__repr__(self, /)
Return repr(self).
__setattr__(self, name, value, /)
Implement setattr(self, name, value).
__setstate__(...)
__str__(self, /)
Return str(self).
with_traceback(...)
Exception.with_traceback(tb) --
set self.__traceback__ to tb and return self.

Data descriptors inherited from BaseException:
__cause__
exception cause
__context__
exception context
__dict__
__suppress_context__
__traceback__
args

 
class DispatcherKeyError(KeyError, DispatcherError)
    Error raised when unknown (sender,signal) set specified
 
 
Method resolution order:
DispatcherKeyError
KeyError
LookupError
DispatcherError
Exception
BaseException
object

Data descriptors defined here:
__weakref__
list of weak references to the object (if defined)

Methods inherited from KeyError:
__init__(self, /, *args, **kwargs)
Initialize self.  See help(type(self)) for accurate signature.
__str__(self, /)
Return str(self).

Static methods inherited from LookupError:
__new__(*args, **kwargs) from type
Create and return a new object.  See help(type) for accurate signature.

Methods inherited from BaseException:
__delattr__(self, name, /)
Implement delattr(self, name).
__getattribute__(self, name, /)
Return getattr(self, name).
__reduce__(...)
Helper for pickle.
__repr__(self, /)
Return repr(self).
__setattr__(self, name, value, /)
Implement setattr(self, name, value).
__setstate__(...)
with_traceback(...)
Exception.with_traceback(tb) --
set self.__traceback__ to tb and return self.

Data descriptors inherited from BaseException:
__cause__
exception cause
__context__
exception context
__dict__
__suppress_context__
__traceback__
args

 
class DispatcherTypeError(TypeError, DispatcherError)
    Error raised when inappropriate signal-type specified (None)
 
 
Method resolution order:
DispatcherTypeError
TypeError
DispatcherError
Exception
BaseException
object

Data descriptors defined here:
__weakref__
list of weak references to the object (if defined)

Methods inherited from TypeError:
__init__(self, /, *args, **kwargs)
Initialize self.  See help(type(self)) for accurate signature.

Static methods inherited from TypeError:
__new__(*args, **kwargs) from type
Create and return a new object.  See help(type) for accurate signature.

Methods inherited from BaseException:
__delattr__(self, name, /)
Implement delattr(self, name).
__getattribute__(self, name, /)
Return getattr(self, name).
__reduce__(...)
Helper for pickle.
__repr__(self, /)
Return repr(self).
__setattr__(self, name, value, /)
Implement setattr(self, name, value).
__setstate__(...)
__str__(self, /)
Return str(self).
with_traceback(...)
Exception.with_traceback(tb) --
set self.__traceback__ to tb and return self.

Data descriptors inherited from BaseException:
__cause__
exception cause
__context__
exception context
__dict__
__suppress_context__
__traceback__
args

 
Data
        __cached__ = '/home/mcfletch/OpenGL-dev/pydispatcher/pydispatch/__pycache__/errors.cpython-310.pyc'
__file__ = '/home/mcfletch/OpenGL-dev/pydispatcher/pydispatch/errors.py'
__loader__ = <_frozen_importlib_external.SourceFileLoader object>
__name__ = 'pydispatch.errors'
__package__ = 'pydispatch'
__spec__ = ModuleSpec(name='pydispatch.errors', loader=<_fr...ch/OpenGL-dev/pydispatcher/pydispatch/errors.py')
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1661979366.0 PyDispatcher-2.0.7/docs/pydoc/pydispatch.html0000644000175000017500000000650614303745346021437 0ustar00mcfletchmcfletch Python: package pydispatch
 
 
pydispatch (version 2.0.6)
index
/home/mcfletch/OpenGL-dev/pydispatcher/pydispatch/__init__.py

Multi-consumer multi-producer dispatching mechanism

 
Package Contents
        __init__ -- Multi-consumer multi-producer dispatching mechanism
dispatcher -- Multiple-producer-multiple-consumer signal-dispatching
errors -- Error types for dispatcher mechanism
robust -- Module implementing error-catching version of send (sendRobust)
robustapply -- Robust apply mechanism
saferef -- Refactored "safe reference" from dispatcher.py

 
Data
        __author__ = "Patrick K. O'Brien"
__cached__ = '/home/mcfletch/OpenGL-dev/pydispatcher/pydispatch/__pycache__/__init__.cpython-310.pyc'
__file__ = '/home/mcfletch/OpenGL-dev/pydispatcher/pydispatch/__init__.py'
__license__ = 'BSD-style, see license.txt for details'
__loader__ = <_frozen_importlib_external.SourceFileLoader object>
__name__ = 'pydispatch'
__package__ = 'pydispatch'
__path__ = ['/home/mcfletch/OpenGL-dev/pydispatcher/pydispatch']
__spec__ = ModuleSpec(name='pydispatch', loader=<_frozen_im...me/mcfletch/OpenGL-dev/pydispatcher/pydispatch'])
__version__ = '2.0.6'

 
Author
        Patrick K. O'Brien
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1661979366.0 PyDispatcher-2.0.7/docs/pydoc/pydispatch.robust.html0000644000175000017500000001115614303745346022751 0ustar00mcfletchmcfletch Python: module pydispatch.robust
 
 
pydispatch.robust
index
/home/mcfletch/OpenGL-dev/pydispatcher/pydispatch/robust.py

Module implementing error-catching version of send (sendRobust)

 
Functions
       
sendRobust(signal=_Any, sender=_Anonymous, *arguments, **named)
Send signal from sender to all connected receivers catching errors
 
signal -- (hashable) signal value, see connect for details
 
sender -- the sender of the signal
 
    if Any, only receivers registered for Any will receive
    the message.
 
    if Anonymous, only receivers registered to receive
    messages from Anonymous or Any will receive the message
 
    Otherwise can be any python object (normally one
    registered with a connect if you actually want
    something to occur).
 
arguments -- positional arguments which will be passed to
    *all* receivers. Note that this may raise TypeErrors
    if the receivers do not allow the particular arguments.
    Note also that arguments are applied before named
    arguments, so they should be used with care.
 
named -- named arguments which will be filtered according
    to the parameters of the receivers to only provide those
    acceptable to the receiver.
 
Return a list of tuple pairs [(receiver, response), ... ]
 
if any receiver raises an error (specifically any subclass of Exception),
the error instance is returned as the result for that receiver.

 
Data
        Anonymous = _Anonymous
Any = _Any
__cached__ = '/home/mcfletch/OpenGL-dev/pydispatcher/pydispatch/__pycache__/robust.cpython-310.pyc'
__file__ = '/home/mcfletch/OpenGL-dev/pydispatcher/pydispatch/robust.py'
__loader__ = <_frozen_importlib_external.SourceFileLoader object>
__name__ = 'pydispatch.robust'
__package__ = 'pydispatch'
__spec__ = ModuleSpec(name='pydispatch.robust', loader=<_fr...ch/OpenGL-dev/pydispatcher/pydispatch/robust.py')
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1661979366.0 PyDispatcher-2.0.7/docs/pydoc/pydispatch.robustapply.html0000644000175000017500000000747314303745346024026 0ustar00mcfletchmcfletch Python: module pydispatch.robustapply
 
 
pydispatch.robustapply
index
/home/mcfletch/OpenGL-dev/pydispatcher/pydispatch/robustapply.py

Robust apply mechanism
 
Provides a function "call", which can sort out
what arguments a given callable object can take,
and subset the given arguments to match only
those which are acceptable.

 
Modules
       
sys

 
Functions
       
function(receiver)
Get function-like callable object for given receiver
 
returns (function_or_method, codeObject, fromMethod)
 
If fromMethod is true, then the callable already
has its first argument bound
robustApply(receiver, *arguments, **named)
Call receiver with arguments and an appropriate subset of named

 
Data
        __cached__ = '/home/mcfletch/OpenGL-dev/pydispatcher/pydispatch/__pycache__/robustapply.cpython-310.pyc'
__file__ = '/home/mcfletch/OpenGL-dev/pydispatcher/pydispatch/robustapply.py'
__loader__ = <_frozen_importlib_external.SourceFileLoader object>
__name__ = 'pydispatch.robustapply'
__package__ = 'pydispatch'
__spec__ = ModuleSpec(name='pydispatch.robustapply', loader...enGL-dev/pydispatcher/pydispatch/robustapply.py')
func_code = '__code__'
im_code = '__code__'
im_func = '__func__'
im_self = '__self__'
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1661979366.0 PyDispatcher-2.0.7/docs/pydoc/pydispatch.saferef.html0000644000175000017500000003232614303745346023050 0ustar00mcfletchmcfletch Python: module pydispatch.saferef
 
 
pydispatch.saferef
index
/home/mcfletch/OpenGL-dev/pydispatcher/pydispatch/saferef.py

Refactored "safe reference" from dispatcher.py

 
Modules
       
sys
traceback
weakref

 
Classes
       
object
BoundMethodWeakref

 
class BoundMethodWeakref(object)
    BoundMethodWeakref(target, onDelete=None, *arguments, **named)
 
'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 calculateKey method applied to the
        target instance method
    deletionMethods -- 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 onDelete parameters of safeRef calls.
    weakSelf -- weak reference to the target object
    weakFunc -- weak reference to the target function
 
Class Attributes:
    _allInstances -- class attribute pointing to all live
        BoundMethodWeakref objects indexed by the class's
        calculateKey(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.
 
  Methods defined here:
__bool__ = __nonzero__(self)
__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.
__cmp__(self, other)
Compare with another reference
__init__(self, target, onDelete=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:
        target.<im_func>.__get__( target.<im_self> )
    which is true of built-in instance methods.
onDelete -- 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.
__nonzero__(self)
Whether we are still a valid reference
__repr__ = __str__(self)
__str__(self)
Give a friendly representation of the object

Class methods defined here:
calculateKey(target) from type
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.

Static methods defined here:
__new__(cls, target, onDelete=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
deletionMethods attribute updated.  Otherwise the
new instance is created and registered in the table
of already-referenced methods.

Data descriptors defined here:
__dict__
dictionary for instance variables (if defined)
__weakref__
list of weak references to the object (if defined)

 
Functions
       
safeRef(target, onDelete=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.
onDelete -- 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.

 
Data
        __cached__ = '/home/mcfletch/OpenGL-dev/pydispatcher/pydispatch/__pycache__/saferef.cpython-310.pyc'
__file__ = '/home/mcfletch/OpenGL-dev/pydispatcher/pydispatch/saferef.py'
__loader__ = <_frozen_importlib_external.SourceFileLoader object>
__name__ = 'pydispatch.saferef'
__package__ = 'pydispatch'
__spec__ = ModuleSpec(name='pydispatch.saferef', loader=<_f...h/OpenGL-dev/pydispatcher/pydispatch/saferef.py')
im_func = '__func__'
im_self = '__self__'
././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1661979365.0 PyDispatcher-2.0.7/docs/pydoc/pydoc2.py0000644000175000017500000003754114303745345020155 0ustar00mcfletchmcfletch"""Pydoc sub-class for generating documentation for entire packages""" import pydoc, inspect, os, string import sys, imp, os, stat, re, types, inspect from reprlib import Repr class DefaultFormatter(pydoc.HTMLDoc): def docmodule(self, object, name=None, mod=None, packageContext=None, *ignored): """Produce HTML documentation for a module object.""" name = object.__name__ # ignore the passed-in name parts = name.split(".") links = [] for i in range(len(parts) - 1): links.append( '%s' % (".".join(parts[: i + 1]), parts[i]) ) linkedname = ".".join(links + parts[-1:]) head = "%s" % linkedname try: path = inspect.getabsfile(object) url = path if sys.platform == "win32": import nturl2path url = nturl2path.pathname2url(path) filelink = '%s' % (url, path) except TypeError: filelink = "(built-in)" info = [] if hasattr(object, "__version__"): version = str(object.__version__) if version[:11] == "$" + "Revision: " and version[-1:] == "$": version = version[11:-1].strip() info.append("version %s" % self.escape(version)) if hasattr(object, "__date__"): info.append(self.escape(str(object.__date__))) if info: head = head + " (%s)" % ", ".join(info) result = self.heading( head, "#ffffff", "#7799ee", 'index
' + filelink ) modules = inspect.getmembers(object, inspect.ismodule) classes, cdict = [], {} for key, value in inspect.getmembers(object, inspect.isclass): if (inspect.getmodule(value) or object) is object: classes.append((key, value)) cdict[key] = cdict[value] = "#" + key for key, value in classes: for base in value.__bases__: key, modname = base.__name__, base.__module__ module = sys.modules.get(modname) if modname != name and module and hasattr(module, key): if getattr(module, key) is base: if key not in cdict: cdict[key] = cdict[base] = modname + ".html#" + key funcs, fdict = [], {} for key, value in inspect.getmembers(object, inspect.isroutine): if inspect.isbuiltin(value) or inspect.getmodule(value) is object: funcs.append((key, value)) fdict[key] = "#-" + key if inspect.isfunction(value): fdict[value] = fdict[key] data = [] for key, value in inspect.getmembers(object, pydoc.isdata): if key not in ["__builtins__", "__doc__"]: data.append((key, value)) doc = self.markup(pydoc.getdoc(object), self.preformat, fdict, cdict) doc = doc and "%s" % doc result = result + "

%s

\n" % doc packageContext.clean(classes, object) packageContext.clean(funcs, object) packageContext.clean(data, object) if hasattr(object, "__path__"): modpkgs = [] modnames = [] for file in os.listdir(object.__path__[0]): path = os.path.join(object.__path__[0], file) modname = inspect.getmodulename(file) if modname and modname not in modnames: modpkgs.append((modname, name, 0, 0)) modnames.append(modname) elif pydoc.ispackage(path): modpkgs.append((file, name, 1, 0)) modpkgs.sort() contents = self.multicolumn(modpkgs, self.modpkglink) ## result = result + self.bigsection( ## 'Package Contents', '#ffffff', '#aa55cc', contents) result = result + self.moduleSection(object, packageContext) elif modules: contents = self.multicolumn( modules, lambda item, s=self: s.modulelink(item[1]) ) result = result + self.bigsection("Modules", "#fffff", "#aa55cc", contents) if classes: classlist = [key_value[1] for key_value in classes] contents = [self.formattree(inspect.getclasstree(classlist, 1), name)] for key, value in classes: contents.append(self.document(value, key, name, fdict, cdict)) result = result + self.bigsection( "Classes", "#ffffff", "#ee77aa", "".join(contents) ) if funcs: contents = [] for key, value in funcs: contents.append(self.document(value, key, name, fdict, cdict)) result = result + self.bigsection( "Functions", "#ffffff", "#eeaa77", "".join(contents) ) if data: contents = [] for key, value in data: contents.append(self.document(value, key)) result = result + self.bigsection( "Data", "#ffffff", "#55aa55", "
\n".join(contents) ) if hasattr(object, "__author__"): contents = self.markup(str(object.__author__), self.preformat) result = result + self.bigsection("Author", "#ffffff", "#7799ee", contents) if hasattr(object, "__credits__"): contents = self.markup(str(object.__credits__), self.preformat) result = result + self.bigsection("Credits", "#ffffff", "#7799ee", contents) return result def classlink(self, object, modname): """Make a link for a class.""" name, module = object.__name__, sys.modules.get(object.__module__) if hasattr(module, name) and getattr(module, name) is object: return '%s' % (module.__name__, name, name) return pydoc.classname(object, modname) def moduleSection(self, object, packageContext): """Create a module-links section for the given object (module)""" modules = inspect.getmembers(object, inspect.ismodule) packageContext.clean(modules, object) packageContext.recurseScan(modules) if hasattr(object, "__path__"): modpkgs = [] modnames = [] for file in os.listdir(object.__path__[0]): path = os.path.join(object.__path__[0], file) modname = inspect.getmodulename(file) if modname and modname not in modnames: modpkgs.append((modname, object.__name__, 0, 0)) modnames.append(modname) elif pydoc.ispackage(path): modpkgs.append((file, object.__name__, 1, 0)) modpkgs.sort() # do more recursion here... for (modname, name, ya, yo) in modpkgs: packageContext.addInteresting(".".join((object.__name__, modname))) items = [] for (modname, name, ispackage, isshadowed) in modpkgs: try: # get the actual module object... ## if modname == "events": ## import pdb ## pdb.set_trace() module = pydoc.safeimport("%s.%s" % (name, modname)) description, documentation = pydoc.splitdoc(inspect.getdoc(module)) if description: items.append( """%s -- %s""" % ( self.modpkglink((modname, name, ispackage, isshadowed)), description, ) ) else: items.append( self.modpkglink((modname, name, ispackage, isshadowed)) ) except: items.append( self.modpkglink((modname, name, ispackage, isshadowed)) ) contents = "
".join(items) result = self.bigsection("Package Contents", "#ffffff", "#aa55cc", contents) elif modules: contents = self.multicolumn( modules, lambda item, s=self: s.modulelink(item[1]) ) result = self.bigsection("Modules", "#fffff", "#aa55cc", contents) else: result = "" return result class AlreadyDone(Exception): pass class PackageDocumentationGenerator: """A package document generator creates documentation for an entire package using pydoc's machinery. baseModules -- modules which will be included and whose included and children modules will be considered fair game for documentation destinationDirectory -- the directory into which the HTML documentation will be written recursion -- whether to add modules which are referenced by and/or children of base modules exclusions -- a list of modules whose contents will not be shown in any other module, commonly such modules as OpenGL.GL, wxPython.wx etc. recursionStops -- a list of modules which will explicitly stop recursion (i.e. they will never be included), even if they are children of base modules. formatter -- allows for passing in a custom formatter see DefaultFormatter for sample implementation. """ def __init__( self, baseModules, destinationDirectory=".", recursion=1, exclusions=(), recursionStops=(), formatter=None, ): self.destinationDirectory = os.path.abspath(destinationDirectory) self.exclusions = {} self.warnings = [] self.baseSpecifiers = {} self.completed = {} self.recursionStops = {} self.recursion = recursion for stop in recursionStops: self.recursionStops[stop] = 1 self.pending = [] for exclusion in exclusions: try: self.exclusions[exclusion] = pydoc.locate(exclusion) except pydoc.ErrorDuringImport as value: self.warn( """Unable to import the module %s which was specified as an exclusion module""" % (repr(exclusion)) ) self.formatter = formatter or DefaultFormatter() for base in baseModules: self.addBase(base) def warn(self, message): """Warnings are used for recoverable, but not necessarily ignorable conditions""" self.warnings.append(message) def info(self, message): """Information/status report""" print(message) def addBase(self, specifier): """Set the base of the documentation set, only children of these modules will be documented""" try: self.baseSpecifiers[specifier] = pydoc.locate(specifier) self.pending.append(specifier) except pydoc.ErrorDuringImport as value: self.warn( """Unable to import the module %s which was specified as a base module""" % (repr(specifier)) ) def addInteresting(self, specifier): """Add a module to the list of interesting modules""" if self.checkScope(specifier): ## print "addInteresting", specifier self.pending.append(specifier) else: self.completed[specifier] = 1 def checkScope(self, specifier): """Check that the specifier is "in scope" for the recursion""" if not self.recursion: return 0 items = specifier.split(".") stopCheck = items[:] while stopCheck: name = ".".join(items) if self.recursionStops.get(name): return 0 elif self.completed.get(name): return 0 del stopCheck[-1] while items: if self.baseSpecifiers.get(".".join(items)): return 1 del items[-1] # was not within any given scope return 0 def process(self): """Having added all of the base and/or interesting modules, proceed to generate the appropriate documentation for each module in the appropriate directory, doing the recursion as we go.""" try: while self.pending: try: if self.pending[0] in self.completed: raise AlreadyDone(self.pending[0]) self.info("""Start %s""" % (repr(self.pending[0]))) object = pydoc.locate(self.pending[0]) self.info(""" ... found %s""" % (repr(object.__name__))) except AlreadyDone: pass except pydoc.ErrorDuringImport as value: self.info(""" ... FAILED %s""" % (repr(value))) self.warn( """Unable to import the module %s""" % (repr(self.pending[0])) ) except (SystemError, SystemExit) as value: self.info(""" ... FAILED %s""" % (repr(value))) self.warn( """Unable to import the module %s""" % (repr(self.pending[0])) ) except Exception as value: self.info(""" ... FAILED %s""" % (repr(value))) self.warn( """Unable to import the module %s""" % (repr(self.pending[0])) ) else: page = self.formatter.page( pydoc.describe(object), self.formatter.docmodule( object, object.__name__, packageContext=self, ), ) file = open( os.path.join( self.destinationDirectory, self.pending[0] + ".html", ), "w", ) file.write(page) file.close() self.completed[self.pending[0]] = object del self.pending[0] finally: for item in self.warnings: print(item) def clean(self, objectList, object): """callback from the formatter object asking us to remove those items in the key, value pairs where the object is imported from one of the excluded modules""" for key, value in objectList[:]: for excludeObject in list(self.exclusions.values()): if hasattr(excludeObject, key) and excludeObject is not object: if getattr(excludeObject, key) is value or ( hasattr(excludeObject, "__name__") and excludeObject.__name__ == "Numeric" ): objectList[:] = [(k, o) for k, o in objectList if k != key] def recurseScan(self, objectList): """Process the list of modules trying to add each to the list of interesting modules""" for key, value in objectList: self.addInteresting(value.__name__) if __name__ == "__main__": excludes = [ "OpenGL.GL", "OpenGL.GLU", "OpenGL.GLUT", "OpenGL.GLE", "OpenGL.GLX", "wxPython.wx", "Numeric", "_tkinter", "Tkinter", ] modules = [ "OpenGLContext.debug", ## "wxPython.glcanvas", ## "OpenGL.Tk", ## "OpenGL", ] PackageDocumentationGenerator( baseModules=modules, destinationDirectory="z:\\temp", exclusions=excludes, ).process() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1661979366.0 PyDispatcher-2.0.7/docs/pydoc/weakref.html0000644000175000017500000017445014303745346020717 0ustar00mcfletchmcfletch Python: module weakref
 
 
weakref
index
/usr/lib/python3.10/weakref.py

Weak reference support for Python.
 
This module is an implementation of PEP 205:
 
https://www.python.org/dev/peps/pep-0205/

 
Modules
       
collections.abc
itertools
sys

 
Classes
       
object
CallableProxyType
ProxyType
ReferenceType
KeyedRef
WeakMethod
finalize
MutableMapping(Mapping)
WeakKeyDictionary
WeakValueDictionary

 
class CallableProxyType(object)
     Methods defined here:
__abs__(self, /)
abs(self)
__add__(self, value, /)
Return self+value.
__and__(self, value, /)
Return self&value.
__bool__(self, /)
True if self else False
__call__(self, /, *args, **kwargs)
Call self as a function.
__contains__(self, key, /)
Return key in self.
__delattr__(self, name, /)
Implement delattr(self, name).
__delitem__(self, key, /)
Delete self[key].
__divmod__(self, value, /)
Return divmod(self, value).
__eq__(self, value, /)
Return self==value.
__float__(self, /)
float(self)
__floordiv__(self, value, /)
Return self//value.
__ge__(self, value, /)
Return self>=value.
__getattribute__(self, name, /)
Return getattr(self, name).
__getitem__(self, key, /)
Return self[key].
__gt__(self, value, /)
Return self>value.
__iadd__(self, value, /)
Return self+=value.
__iand__(self, value, /)
Return self&=value.
__ifloordiv__(self, value, /)
Return self//=value.
__ilshift__(self, value, /)
Return self<<=value.
__imatmul__(self, value, /)
Return self@=value.
__imod__(self, value, /)
Return self%=value.
__imul__(self, value, /)
Return self*=value.
__index__(self, /)
Return self converted to an integer, if self is suitable for use as an index into a list.
__int__(self, /)
int(self)
__invert__(self, /)
~self
__ior__(self, value, /)
Return self|=value.
__ipow__(self, value, /)
Return self**=value.
__irshift__(self, value, /)
Return self>>=value.
__isub__(self, value, /)
Return self-=value.
__iter__(self, /)
Implement iter(self).
__itruediv__(self, value, /)
Return self/=value.
__ixor__(self, value, /)
Return self^=value.
__le__(self, value, /)
Return self<=value.
__len__(self, /)
Return len(self).
__lshift__(self, value, /)
Return self<<value.
__lt__(self, value, /)
Return self<value.
__matmul__(self, value, /)
Return self@value.
__mod__(self, value, /)
Return self%value.
__mul__(self, value, /)
Return self*value.
__ne__(self, value, /)
Return self!=value.
__neg__(self, /)
-self
__next__(self, /)
Implement next(self).
__or__(self, value, /)
Return self|value.
__pos__(self, /)
+self
__pow__(self, value, mod=None, /)
Return pow(self, value, mod).
__radd__(self, value, /)
Return value+self.
__rand__(self, value, /)
Return value&self.
__rdivmod__(self, value, /)
Return divmod(value, self).
__repr__(self, /)
Return repr(self).
__rfloordiv__(self, value, /)
Return value//self.
__rlshift__(self, value, /)
Return value<<self.
__rmatmul__(self, value, /)
Return value@self.
__rmod__(self, value, /)
Return value%self.
__rmul__(self, value, /)
Return value*self.
__ror__(self, value, /)
Return value|self.
__rpow__(self, value, mod=None, /)
Return pow(value, self, mod).
__rrshift__(self, value, /)
Return value>>self.
__rshift__(self, value, /)
Return self>>value.
__rsub__(self, value, /)
Return value-self.
__rtruediv__(self, value, /)
Return value/self.
__rxor__(self, value, /)
Return value^self.
__setattr__(self, name, value, /)
Implement setattr(self, name, value).
__setitem__(self, key, value, /)
Set self[key] to value.
__str__(self, /)
Return str(self).
__sub__(self, value, /)
Return self-value.
__truediv__(self, value, /)
Return self/value.
__xor__(self, value, /)
Return self^value.

Data and other attributes defined here:
__hash__ = None

 
class KeyedRef(ReferenceType)
    KeyedRef(ob, callback, key)
 
Specialized reference that includes a key corresponding to the value.
 
This is used in the WeakValueDictionary to avoid having to create
a function object for each key stored in the mapping.  A shared
callback object can use the 'key' attribute of a KeyedRef instead
of getting a reference to the key from an enclosing scope.
 
 
Method resolution order:
KeyedRef
ReferenceType
object

Methods defined here:
__init__(self, ob, callback, key)
Initialize self.  See help(type(self)) for accurate signature.

Static methods defined here:
__new__(type, ob, callback, key)
Create and return a new object.  See help(type) for accurate signature.

Data descriptors defined here:
key

Methods inherited from ReferenceType:
__call__(self, /, *args, **kwargs)
Call self as a function.
__eq__(self, value, /)
Return self==value.
__ge__(self, value, /)
Return self>=value.
__gt__(self, value, /)
Return self>value.
__hash__(self, /)
Return hash(self).
__le__(self, value, /)
Return self<=value.
__lt__(self, value, /)
Return self<value.
__ne__(self, value, /)
Return self!=value.
__repr__(self, /)
Return repr(self).

Class methods inherited from ReferenceType:
__class_getitem__(...) from type
See PEP 585

Data descriptors inherited from ReferenceType:
__callback__

 
class ProxyType(object)
     Methods defined here:
__abs__(self, /)
abs(self)
__add__(self, value, /)
Return self+value.
__and__(self, value, /)
Return self&value.
__bool__(self, /)
True if self else False
__bytes__(...)
__contains__(self, key, /)
Return key in self.
__delattr__(self, name, /)
Implement delattr(self, name).
__delitem__(self, key, /)
Delete self[key].
__divmod__(self, value, /)
Return divmod(self, value).
__eq__(self, value, /)
Return self==value.
__float__(self, /)
float(self)
__floordiv__(self, value, /)
Return self//value.
__ge__(self, value, /)
Return self>=value.
__getattribute__(self, name, /)
Return getattr(self, name).
__getitem__(self, key, /)
Return self[key].
__gt__(self, value, /)
Return self>value.
__iadd__(self, value, /)
Return self+=value.
__iand__(self, value, /)
Return self&=value.
__ifloordiv__(self, value, /)
Return self//=value.
__ilshift__(self, value, /)
Return self<<=value.
__imatmul__(self, value, /)
Return self@=value.
__imod__(self, value, /)
Return self%=value.
__imul__(self, value, /)
Return self*=value.
__index__(self, /)
Return self converted to an integer, if self is suitable for use as an index into a list.
__int__(self, /)
int(self)
__invert__(self, /)
~self
__ior__(self, value, /)
Return self|=value.
__ipow__(self, value, /)
Return self**=value.
__irshift__(self, value, /)
Return self>>=value.
__isub__(self, value, /)
Return self-=value.
__iter__(self, /)
Implement iter(self).
__itruediv__(self, value, /)
Return self/=value.
__ixor__(self, value, /)
Return self^=value.
__le__(self, value, /)
Return self<=value.
__len__(self, /)
Return len(self).
__lshift__(self, value, /)
Return self<<value.
__lt__(self, value, /)
Return self<value.
__matmul__(self, value, /)
Return self@value.
__mod__(self, value, /)
Return self%value.
__mul__(self, value, /)
Return self*value.
__ne__(self, value, /)
Return self!=value.
__neg__(self, /)
-self
__next__(self, /)
Implement next(self).
__or__(self, value, /)
Return self|value.
__pos__(self, /)
+self
__pow__(self, value, mod=None, /)
Return pow(self, value, mod).
__radd__(self, value, /)
Return value+self.
__rand__(self, value, /)
Return value&self.
__rdivmod__(self, value, /)
Return divmod(value, self).
__repr__(self, /)
Return repr(self).
__reversed__(...)
__rfloordiv__(self, value, /)
Return value//self.
__rlshift__(self, value, /)
Return value<<self.
__rmatmul__(self, value, /)
Return value@self.
__rmod__(self, value, /)
Return value%self.
__rmul__(self, value, /)
Return value*self.
__ror__(self, value, /)
Return value|self.
__rpow__(self, value, mod=None, /)
Return pow(value, self, mod).
__rrshift__(self, value, /)
Return value>>self.
__rshift__(self, value, /)
Return self>>value.
__rsub__(self, value, /)
Return value-self.
__rtruediv__(self, value, /)
Return value/self.
__rxor__(self, value, /)
Return value^self.
__setattr__(self, name, value, /)
Implement setattr(self, name, value).
__setitem__(self, key, value, /)
Set self[key] to value.
__str__(self, /)
Return str(self).
__sub__(self, value, /)
Return self-value.
__truediv__(self, value, /)
Return self/value.
__xor__(self, value, /)
Return self^value.

Data and other attributes defined here:
__hash__ = None

 
class ReferenceType(object)
     Methods defined here:
__call__(self, /, *args, **kwargs)
Call self as a function.
__eq__(self, value, /)
Return self==value.
__ge__(self, value, /)
Return self>=value.
__gt__(self, value, /)
Return self>value.
__hash__(self, /)
Return hash(self).
__init__(self, /, *args, **kwargs)
Initialize self.  See help(type(self)) for accurate signature.
__le__(self, value, /)
Return self<=value.
__lt__(self, value, /)
Return self<value.
__ne__(self, value, /)
Return self!=value.
__repr__(self, /)
Return repr(self).

Class methods defined here:
__class_getitem__(...) from type
See PEP 585

Static methods defined here:
__new__(*args, **kwargs) from type
Create and return a new object.  See help(type) for accurate signature.

Data descriptors defined here:
__callback__

 
class WeakKeyDictionary(MutableMapping)
    WeakKeyDictionary(dict=None)
 
Mapping class that references keys weakly.
 
Entries in the dictionary will be discarded when there is no
longer a strong reference to the key. This can be used to
associate additional data with an object owned by other parts of
an application without adding attributes to those objects. This
can be especially useful with objects that override attribute
accesses.
 
 
Method resolution order:
WeakKeyDictionary
MutableMapping
Mapping
Collection
Sized
Iterable
Container
object

Methods defined here:
__contains__(self, key)
__copy__ = copy(self)
__deepcopy__(self, memo)
__delitem__(self, key)
__getitem__(self, key)
__init__(self, dict=None)
Initialize self.  See help(type(self)) for accurate signature.
__ior__(self, other)
__iter__ = keys(self)
__len__(self)
__or__(self, other)
Return self|value.
__repr__(self)
Return repr(self).
__ror__(self, other)
Return value|self.
__setitem__(self, key, value)
copy(self)
get(self, key, default=None)
D.get(k[,d]) -> D[k] if k in D, else d.  d defaults to None.
items(self)
D.items() -> a set-like object providing a view on D's items
keyrefs(self)
Return a list of weak references to the keys.
 
The references are not guaranteed to be 'live' at the time
they are used, so the result of calling the references needs
to be checked before being used.  This can be used to avoid
creating references that will cause the garbage collector to
keep the keys around longer than needed.
keys(self)
D.keys() -> a set-like object providing a view on D's keys
pop(self, key, *args)
D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
If key is not found, d is returned if given, otherwise KeyError is raised.
popitem(self)
D.popitem() -> (k, v), remove and return some (key, value) pair
as a 2-tuple; but raise KeyError if D is empty.
setdefault(self, key, default=None)
D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D
update(self, dict=None, /, **kwargs)
D.update([E, ]**F) -> None.  Update D from mapping/iterable E and F.
If E present and has a .keys() method, does:     for k in E: D[k] = E[k]
If E present and lacks .keys() method, does:     for (k, v) in E: D[k] = v
In either case, this is followed by: for k, v in F.items(): D[k] = v
values(self)
D.values() -> an object providing a view on D's values

Data descriptors defined here:
__dict__
dictionary for instance variables (if defined)
__weakref__
list of weak references to the object (if defined)

Data and other attributes defined here:
__abstractmethods__ = frozenset()

Methods inherited from MutableMapping:
clear(self)
D.clear() -> None.  Remove all items from D.

Methods inherited from Mapping:
__eq__(self, other)
Return self==value.

Data and other attributes inherited from Mapping:
__hash__ = None
__reversed__ = None

Class methods inherited from Collection:
__subclasshook__(C) from ABCMeta
Abstract classes can override this to customize issubclass().
 
This is invoked early on by abc.ABCMeta.__subclasscheck__().
It should return True, False or NotImplemented.  If it returns
NotImplemented, the normal algorithm is used.  Otherwise, it
overrides the normal algorithm (and the outcome is cached).

Class methods inherited from Iterable:
__class_getitem__ = GenericAlias(...) from ABCMeta
Represent a PEP 585 generic type
 
E.g. for t = list[int], t.__origin__ is list and t.__args__ is (int,).

 
class WeakMethod(ReferenceType)
    WeakMethod(meth, callback=None)
 
A custom `weakref.ref` subclass which simulates a weak reference to
a bound method, working around the lifetime problem of bound methods.
 
 
Method resolution order:
WeakMethod
ReferenceType
object

Methods defined here:
__call__(self)
Call self as a function.
__eq__(self, other)
Return self==value.
__hash__(self, /)
Return hash(self).
__ne__(self, other)
Return self!=value.

Static methods defined here:
__new__(cls, meth, callback=None)
Create and return a new object.  See help(type) for accurate signature.

Data descriptors defined here:
__weakref__
list of weak references to the object (if defined)

Methods inherited from ReferenceType:
__ge__(self, value, /)
Return self>=value.
__gt__(self, value, /)
Return self>value.
__init__(self, /, *args, **kwargs)
Initialize self.  See help(type(self)) for accurate signature.
__le__(self, value, /)
Return self<=value.
__lt__(self, value, /)
Return self<value.
__repr__(self, /)
Return repr(self).

Class methods inherited from ReferenceType:
__class_getitem__(...) from type
See PEP 585

Data descriptors inherited from ReferenceType:
__callback__

 
class WeakValueDictionary(MutableMapping)
    WeakValueDictionary(other=(), /, **kw)
 
Mapping class that references values weakly.
 
Entries in the dictionary will be discarded when no strong
reference to the value exists anymore
 
 
Method resolution order:
WeakValueDictionary
MutableMapping
Mapping
Collection
Sized
Iterable
Container
object

Methods defined here:
__contains__(self, key)
__copy__ = copy(self)
__deepcopy__(self, memo)
__delitem__(self, key)
__getitem__(self, key)
__init__(self, other=(), /, **kw)
Initialize self.  See help(type(self)) for accurate signature.
__ior__(self, other)
__iter__ = keys(self)
__len__(self)
__or__(self, other)
Return self|value.
__repr__(self)
Return repr(self).
__ror__(self, other)
Return value|self.
__setitem__(self, key, value)
copy(self)
get(self, key, default=None)
D.get(k[,d]) -> D[k] if k in D, else d.  d defaults to None.
items(self)
D.items() -> a set-like object providing a view on D's items
itervaluerefs(self)
Return an iterator that yields the weak references to the values.
 
The references are not guaranteed to be 'live' at the time
they are used, so the result of calling the references needs
to be checked before being used.  This can be used to avoid
creating references that will cause the garbage collector to
keep the values around longer than needed.
keys(self)
D.keys() -> a set-like object providing a view on D's keys
pop(self, key, *args)
D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
If key is not found, d is returned if given, otherwise KeyError is raised.
popitem(self)
D.popitem() -> (k, v), remove and return some (key, value) pair
as a 2-tuple; but raise KeyError if D is empty.
setdefault(self, key, default=None)
D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D
update(self, other=None, /, **kwargs)
D.update([E, ]**F) -> None.  Update D from mapping/iterable E and F.
If E present and has a .keys() method, does:     for k in E: D[k] = E[k]
If E present and lacks .keys() method, does:     for (k, v) in E: D[k] = v
In either case, this is followed by: for k, v in F.items(): D[k] = v
valuerefs(self)
Return a list of weak references to the values.
 
The references are not guaranteed to be 'live' at the time
they are used, so the result of calling the references needs
to be checked before being used.  This can be used to avoid
creating references that will cause the garbage collector to
keep the values around longer than needed.
values(self)
D.values() -> an object providing a view on D's values

Data descriptors defined here:
__dict__
dictionary for instance variables (if defined)
__weakref__
list of weak references to the object (if defined)

Data and other attributes defined here:
__abstractmethods__ = frozenset()

Methods inherited from MutableMapping:
clear(self)
D.clear() -> None.  Remove all items from D.

Methods inherited from Mapping:
__eq__(self, other)
Return self==value.

Data and other attributes inherited from Mapping:
__hash__ = None
__reversed__ = None

Class methods inherited from Collection:
__subclasshook__(C) from ABCMeta
Abstract classes can override this to customize issubclass().
 
This is invoked early on by abc.ABCMeta.__subclasscheck__().
It should return True, False or NotImplemented.  If it returns
NotImplemented, the normal algorithm is used.  Otherwise, it
overrides the normal algorithm (and the outcome is cached).

Class methods inherited from Iterable:
__class_getitem__ = GenericAlias(...) from ABCMeta
Represent a PEP 585 generic type
 
E.g. for t = list[int], t.__origin__ is list and t.__args__ is (int,).

 
class finalize(object)
    finalize(obj, func, /, *args, **kwargs)
 
Class for finalization of weakrefable objects
 
finalize(obj, func, *args, **kwargs) returns a callable finalizer
object which will be called when obj is garbage collected. The
first time the finalizer is called it evaluates func(*arg, **kwargs)
and returns the result. After this the finalizer is dead, and
calling it just returns None.
 
When the program exits any remaining finalizers for which the
atexit attribute is true will be run in reverse order of creation.
By default atexit is true.
 
  Methods defined here:
__call__(self, _=None)
If alive then mark as dead and return func(*args, **kwargs);
otherwise return None
__init__(self, obj, func, /, *args, **kwargs)
Initialize self.  See help(type(self)) for accurate signature.
__repr__(self)
Return repr(self).
detach(self)
If alive then mark as dead and return (obj, func, args, kwargs);
otherwise return None
peek(self)
If alive then return (obj, func, args, kwargs);
otherwise return None

Readonly properties defined here:
alive
Whether finalizer is alive

Data descriptors defined here:
atexit
Whether finalizer should be called at exit

 
ref = class ReferenceType(object)
     Methods defined here:
__call__(self, /, *args, **kwargs)
Call self as a function.
__eq__(self, value, /)
Return self==value.
__ge__(self, value, /)
Return self>=value.
__gt__(self, value, /)
Return self>value.
__hash__(self, /)
Return hash(self).
__init__(self, /, *args, **kwargs)
Initialize self.  See help(type(self)) for accurate signature.
__le__(self, value, /)
Return self<=value.
__lt__(self, value, /)
Return self<value.
__ne__(self, value, /)
Return self!=value.
__repr__(self, /)
Return repr(self).

Class methods defined here:
__class_getitem__(...) from type
See PEP 585

Static methods defined here:
__new__(*args, **kwargs) from type
Create and return a new object.  See help(type) for accurate signature.

Data descriptors defined here:
__callback__

 
Functions
       
_remove_dead_weakref(dct, key, /)
Atomically remove key from dict if it points to a dead weakref.
getweakrefcount(object, /)
Return the number of weak references to 'object'.
getweakrefs(...)
getweakrefs(object) -- return a list of all weak reference objects
that point to 'object'.
proxy(...)
proxy(object[, callback]) -- create a proxy object that weakly
references 'object'.  'callback', if given, is called with a
reference to the proxy when 'object' is about to be finalized.

 
Data
        ProxyTypes = (<class 'weakref.ProxyType'>, <class 'weakref.CallableProxyType'>)
__all__ = ['ref', 'proxy', 'getweakrefcount', 'getweakrefs', 'WeakKeyDictionary', 'ReferenceType', 'ProxyType', 'CallableProxyType', 'ProxyTypes', 'WeakValueDictionary', 'WeakSet', 'WeakMethod', 'finalize']
__cached__ = '/usr/lib/python3.10/__pycache__/weakref.cpython-310.pyc'
__file__ = '/usr/lib/python3.10/weakref.py'
__loader__ = <_frozen_importlib_external.SourceFileLoader object>
__name__ = 'weakref'
__spec__ = ModuleSpec(name='weakref', loader=<_frozen_impor...a55a80>, origin='/usr/lib/python3.10/weakref.py')
././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1676664578.5341449 PyDispatcher-2.0.7/docs/style/0000755000175000017500000000000014373757403016420 5ustar00mcfletchmcfletch././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1574192583.0 PyDispatcher-2.0.7/docs/style/sitestyle.css0000644000175000017500000000164513565042707021161 0ustar00mcfletchmcfletchh1,h2,h3 { color: #111144; background-image: url(../images/greypinstripe.png); border-top-style: solid; border-top-width: 1 } .footer { color: #111144; background-image: url(../images/greypinstripe.png); text-align: center; border-bottom-style: solid; border-bottom-width: 1 } th { color: #111144; background-image: url(../images/greypinstripe.png); text-align: center; } .introduction { margin-left: 60; margin-right: 60; color: #555555; } .technical { margin-left: 60; margin-right: 60; color: #557755; } p { margin-left: 10; margin-right: 10; } ul { margin-left: 30; } pre { background-color: #ffffcc; margin-left: 60; } blockquote { margin-left: 90; } body { background-color: #FFFFFF; color: #000000; font-family: Arial, Helvetica; } a:link { color: #3333e0; text-decoration: none; } a:visited { color: #1111aa; text-decoration: none; } a:active { color: #111133; text-decoration: none; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1676664578.5341449 PyDispatcher-2.0.7/examples/0000755000175000017500000000000014373757403016146 5ustar00mcfletchmcfletch././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1574192583.0 PyDispatcher-2.0.7/examples/__init__.py0000644000175000017500000000006013565042707020247 0ustar00mcfletchmcfletch"""Example scripts for the dispatch project """ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1574192583.0 PyDispatcher-2.0.7/examples/extra_args.py0000755000175000017500000000153513565042707020662 0ustar00mcfletchmcfletch#! /usr/bin/env python from __future__ import print_function from pydispatch import dispatcher SIGNAL = 'my-first-signal' SIGNAL2 = 'my-second-signal' def handle_event( sender ): """Simple event handler""" print('Signal was sent by', sender) dispatcher.connect( handle_event, signal=SIGNAL, sender=dispatcher.Any ) def handle_specific_event( sender, moo ): """Handle a simple event, requiring a "moo" parameter""" print('Specialized event for %(sender)s moo=%(moo)r'%locals()) dispatcher.connect( handle_specific_event, signal=SIGNAL2, sender=dispatcher.Any ) first_sender = object() second_sender = {} def main( ): dispatcher.send( signal=SIGNAL, sender=first_sender ) dispatcher.send( signal=SIGNAL, sender=second_sender ) dispatcher.send( signal=SIGNAL2, sender=second_sender, moo='this' ) if __name__ == "__main__": main()././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1574192583.0 PyDispatcher-2.0.7/examples/hello_messages.py0000755000175000017500000000077313565042707021520 0ustar00mcfletchmcfletch#! /usr/bin/env python from __future__ import print_function from pydispatch import dispatcher SIGNAL = 'my-first-signal' def handle_event( sender ): """Simple event handler""" print('Signal was sent by', sender) dispatcher.connect( handle_event, signal=SIGNAL, sender=dispatcher.Any ) first_sender = object() second_sender = {} def main( ): dispatcher.send( signal=SIGNAL, sender=first_sender ) dispatcher.send( signal=SIGNAL, sender=second_sender ) if __name__ == "__main__": main()././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1661978391.0 PyDispatcher-2.0.7/examples/minimal.py0000644000175000017500000000046014303743427020140 0ustar00mcfletchmcfletchfrom pydispatch import dispatcher metaKey = "moo" MyNode = object() event = {"sample": "event"} def callback(event=None): """Handle signal being sent""" print("Signal received", event) dispatcher.connect(callback, sender=MyNode, signal=metaKey) dispatcher.send(metaKey, MyNode, event=event) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1574192583.0 PyDispatcher-2.0.7/examples/simple_sample.py0000644000175000017500000000444713565042707021357 0ustar00mcfletchmcfletch"""Simple sample showing basic usage pattern""" from __future__ import print_function from pydispatch import dispatcher def doSomethingUseful( table, signal, sender ): """Sample method to receive signals""" print(' doSomethingUseful', repr(table), signal, sender) def doSomethingElse( signal, **named ): """Sample method to receive signals This method demonstrates the use of the **named parameter, which allows a method to receive all remaining parameters from the send call. """ print(' doSomethingElse', named) def doDefault( ): """Sample method to receive All signals Note that this function will be registered for all signals from a given object. It does not have the same interface as any of the other functions registered for those signals. The system will automatically determine the appropriate calling signature for the function. """ print(' doDefault (no arguments)') class Node(object): """Sample object to send signals, note lack of dispatcher-aware code""" def __init__( self, name="an object" ): self.name = name def __repr__( self ): return "%s( %r )"%( self.__class__.__name__, self.name ) DO_LOTS = 0 DO_SOMETHING = ('THIS','IS','A','MORE','COMPLEX','SIGNAL') DO_SOMETHING_ELSE = Node() ourObjects = [ Node(), Node(), Node(), ] if __name__ == "__main__": # Establish some "routing" connections dispatcher.connect ( doSomethingUseful, signal = DO_LOTS, sender = ourObjects[0], ) dispatcher.connect ( doSomethingElse, signal = DO_SOMETHING, sender = ourObjects[0], ) dispatcher.connect( doDefault, signal = dispatcher.Any, # this is actually the default, sender = ourObjects[0], ) print("Sending DO_LOTS from first object") dispatcher.send( signal = DO_LOTS, sender = ourObjects[0], table = "Table Argument", ) print("Sending DO_SOMETHING from first object") dispatcher.send( signal = DO_SOMETHING, sender = ourObjects[0], table = "Table Argument", ) print("Sending DO_SOMETHING_ELSE from first object") dispatcher.send( signal = DO_SOMETHING_ELSE, sender = ourObjects[0], table = "Table Argument", )././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1574192583.0 PyDispatcher-2.0.7/license.txt0000644000175000017500000000303413565042707016507 0ustar00mcfletchmcfletchPyDispatcher License Copyright (c) 2001-2006, Patrick K. O'Brien and Contributors All rights reserved. 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. The name of Patrick K. O'Brien, or the name of any Contributor, may not 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 HOLDERS AND 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. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1676664578.5341449 PyDispatcher-2.0.7/pydispatch/0000755000175000017500000000000014373757403016500 5ustar00mcfletchmcfletch././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1676663879.0 PyDispatcher-2.0.7/pydispatch/__init__.py0000644000175000017500000000020714373756107020610 0ustar00mcfletchmcfletch"""Multi-consumer multi-producer dispatching mechanism """ __version__ = "2.0.7" __author__ = "Patrick K. O'Brien" __license__ = "BSD" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1574192583.0 PyDispatcher-2.0.7/pydispatch/dispatcher.py0000644000175000017500000004055213565042707021202 0ustar00mcfletchmcfletch"""Multiple-producer-multiple-consumer signal-dispatching dispatcher is the core of the PyDispatcher system, providing the primary API and the core logic for the system. Module attributes of note: Any -- Singleton used to signal either "Any Sender" or "Any Signal". See documentation of the _Any class. Anonymous -- Singleton used to signal "Anonymous Sender" See documentation of the _Anonymous class. Internal attributes: WEAKREF_TYPES -- tuple of types/classes which represent weak references to receivers, and thus must be de- referenced on retrieval to retrieve the callable object connections -- { senderkey (id) : { signal : [receivers...]}} senders -- { senderkey (id) : weakref(sender) } used for cleaning up sender references on sender deletion sendersBack -- { receiverkey (id) : [senderkey (id)...] } used for cleaning up receiver references on receiver deletion, (considerably speeds up the cleanup process vs. the original code.) """ import weakref from pydispatch import saferef, robustapply, errors class _Parameter: """Used to represent default parameter values.""" def __repr__(self): return self.__class__.__name__ class _Any(_Parameter): """Singleton used to signal either "Any Sender" or "Any Signal" The Any object can be used with connect, disconnect, send, or sendExact to signal that the parameter given Any should react to all senders/signals, not just a particular sender/signal. """ Any = _Any() class _Anonymous(_Parameter): """Singleton used to signal "Anonymous Sender" The Anonymous object is used to signal that the sender of a message is not specified (as distinct from being "any sender"). Registering callbacks for Anonymous will only receive messages sent without senders. Sending with anonymous will only send messages to those receivers registered for Any or Anonymous. Note: The default sender for connect is Any, while the default sender for send is Anonymous. This has the effect that if you do not specify any senders in either function then all messages are routed as though there was a single sender (Anonymous) being used everywhere. """ Anonymous = _Anonymous() WEAKREF_TYPES = (weakref.ReferenceType, saferef.BoundMethodWeakref) connections = {} senders = {} sendersBack = {} def connect(receiver, signal=Any, sender=Any, weak=True): """Connect receiver to sender for signal receiver -- a callable Python object which is to receive messages/signals/events. Receivers must be hashable objects. if weak is True, then receiver must be weak-referencable (more precisely saferef.safeRef() must be able to create a reference to the receiver). Receivers are fairly flexible in their specification, as the machinery in the robustApply module takes care of most of the details regarding figuring out appropriate subsets of the sent arguments to apply to a given receiver. Note: if receiver is itself a weak reference (a callable), it will be de-referenced by the system's machinery, so *generally* weak references are not suitable as receivers, though some use might be found for the facility whereby a higher-level library passes in pre-weakrefed receiver references. signal -- the signal to which the receiver should respond if Any, receiver will receive any signal from the indicated sender (which might also be Any, but is not necessarily Any). Otherwise must be a hashable Python object other than None (DispatcherError raised on None). sender -- the sender to which the receiver should respond if Any, receiver will receive the indicated signals from any sender. if Anonymous, receiver will only receive indicated signals from send/sendExact which do not specify a sender, or specify Anonymous explicitly as the sender. Otherwise can be any python object. weak -- whether to use weak references to the receiver By default, the module will attempt to use weak references to the receiver objects. If this parameter is false, then strong references will be used. returns None, may raise DispatcherTypeError """ if signal is None: raise errors.DispatcherTypeError( 'Signal cannot be None (receiver=%r sender=%r)'%( receiver,sender) ) if weak: receiver = saferef.safeRef(receiver, onDelete=_removeReceiver) senderkey = id(sender) if senderkey in connections: signals = connections[senderkey] else: connections[senderkey] = signals = {} # Keep track of senders for cleanup. # Is Anonymous something we want to clean up? if sender not in (None, Anonymous, Any): def remove(object, senderkey=senderkey): _removeSender(senderkey=senderkey) # Skip objects that can not be weakly referenced, which means # they won't be automatically cleaned up, but that's too bad. try: weakSender = weakref.ref(sender, remove) senders[senderkey] = weakSender except: pass receiverID = id(receiver) # get current set, remove any current references to # this receiver in the set, including back-references if signal in signals: receivers = signals[signal] _removeOldBackRefs(senderkey, signal, receiver, receivers) else: receivers = signals[signal] = [] try: current = sendersBack.get( receiverID ) if current is None: sendersBack[ receiverID ] = current = [] if senderkey not in current: current.append(senderkey) except: pass receivers.append(receiver) def disconnect(receiver, signal=Any, sender=Any, weak=True): """Disconnect receiver from sender for signal receiver -- the registered receiver to disconnect signal -- the registered signal to disconnect sender -- the registered sender to disconnect weak -- the weakref state to disconnect disconnect reverses the process of connect, the semantics for the individual elements are logically equivalent to a tuple of (receiver, signal, sender, weak) used as a key to be deleted from the internal routing tables. (The actual process is slightly more complex but the semantics are basically the same). Note: Using disconnect is not required to cleanup routing when an object is deleted, the framework will remove routes for deleted objects automatically. It's only necessary to disconnect if you want to stop routing to a live object. returns None, may raise DispatcherTypeError or DispatcherKeyError """ if signal is None: raise errors.DispatcherTypeError( 'Signal cannot be None (receiver=%r sender=%r)'%( receiver,sender) ) if weak: receiver = saferef.safeRef(receiver) senderkey = id(sender) try: signals = connections[senderkey] receivers = signals[signal] except KeyError: raise errors.DispatcherKeyError( """No receivers found for signal %r from sender %r""" %( signal, sender ) ) try: # also removes from receivers _removeOldBackRefs(senderkey, signal, receiver, receivers) except ValueError: raise errors.DispatcherKeyError( """No connection to receiver %s for signal %s from sender %s""" %( receiver, signal, sender ) ) _cleanupConnections(senderkey, signal) def getReceivers( sender = Any, signal = Any ): """Get list of receivers from global tables This utility function allows you to retrieve the raw list of receivers from the connections table for the given sender and signal pair. Note: there is no guarantee that this is the actual list stored in the connections table, so the value should be treated as a simple iterable/truth value rather than, for instance a list to which you might append new records. Normally you would use liveReceivers( getReceivers( ...)) to retrieve the actual receiver objects as an iterable object. """ try: return connections[id(sender)][signal] except KeyError: return [] def liveReceivers(receivers): """Filter sequence of receivers to get resolved, live receivers This is a generator which will iterate over the passed sequence, checking for weak references and resolving them, then returning all live receivers. """ for receiver in receivers: if isinstance( receiver, WEAKREF_TYPES): # Dereference the weak reference. receiver = receiver() if receiver is not None: yield receiver else: yield receiver def getAllReceivers( sender = Any, signal = Any ): """Get list of all receivers from global tables This gets all receivers which should receive the given signal from sender, each receiver should be produced only once by the resulting generator """ receivers = {} for set in ( # Get receivers that receive *this* signal from *this* sender. getReceivers( sender, signal ), # Add receivers that receive *any* signal from *this* sender. getReceivers( sender, Any ), # Add receivers that receive *this* signal from *any* sender. getReceivers( Any, signal ), # Add receivers that receive *any* signal from *any* sender. getReceivers( Any, Any ), ): for receiver in set: if receiver: # filter out dead instance-method weakrefs try: if receiver not in receivers: receivers[receiver] = 1 yield receiver except TypeError: # dead weakrefs raise TypeError on hash... pass def send(signal=Any, sender=Anonymous, *arguments, **named): """Send signal from sender to all connected receivers. signal -- (hashable) signal value, see connect for details sender -- the sender of the signal if Any, only receivers registered for Any will receive the message. if Anonymous, only receivers registered to receive messages from Anonymous or Any will receive the message Otherwise can be any python object (normally one registered with a connect if you actually want something to occur). arguments -- positional arguments which will be passed to *all* receivers. Note that this may raise TypeErrors if the receivers do not allow the particular arguments. Note also that arguments are applied before named arguments, so they should be used with care. named -- named arguments which will be filtered according to the parameters of the receivers to only provide those acceptable to the receiver. Return a list of tuple pairs [(receiver, response), ... ] if any receiver raises an error, the error propagates back through send, terminating the dispatch loop, so it is quite possible to not have all receivers called if a raises an error. """ # Call each receiver with whatever arguments it can accept. # Return a list of tuple pairs [(receiver, response), ... ]. responses = [] for receiver in liveReceivers(getAllReceivers(sender, signal)): response = robustapply.robustApply( receiver, signal=signal, sender=sender, *arguments, **named ) responses.append((receiver, response)) return responses def sendExact( signal=Any, sender=Anonymous, *arguments, **named ): """Send signal only to those receivers registered for exact message sendExact allows for avoiding Any/Anonymous registered handlers, sending only to those receivers explicitly registered for a particular signal on a particular sender. """ responses = [] for receiver in liveReceivers(getReceivers(sender, signal)): response = robustapply.robustApply( receiver, signal=signal, sender=sender, *arguments, **named ) responses.append((receiver, response)) return responses def _removeReceiver(receiver): """Remove receiver from connections.""" if not sendersBack: # During module cleanup the mapping will be replaced with None return False backKey = id(receiver) try: backSet = sendersBack.pop(backKey) except KeyError: return False else: for senderkey in backSet: try: signals = list(connections[senderkey].keys()) except KeyError: pass else: for signal in signals: try: receivers = connections[senderkey][signal] except KeyError: pass else: try: receivers.remove( receiver ) except Exception: pass _cleanupConnections(senderkey, signal) def _cleanupConnections(senderkey, signal): """Delete any empty signals for senderkey. Delete senderkey if empty.""" try: receivers = connections[senderkey][signal] except: pass else: if not receivers: # No more connected receivers. Therefore, remove the signal. try: signals = connections[senderkey] except KeyError: pass else: del signals[signal] if not signals: # No more signal connections. Therefore, remove the sender. _removeSender(senderkey) def _removeSender(senderkey): """Remove senderkey from connections.""" _removeBackrefs(senderkey) try: del connections[senderkey] except KeyError: pass # Senderkey will only be in senders dictionary if sender # could be weakly referenced. try: del senders[senderkey] except: pass def _removeBackrefs( senderkey): """Remove all back-references to this senderkey""" try: signals = connections[senderkey] except KeyError: signals = None else: items = signals.items() def allReceivers( ): for signal,set in items: for item in set: yield item for receiver in allReceivers(): _killBackref( receiver, senderkey ) def _removeOldBackRefs(senderkey, signal, receiver, receivers): """Kill old sendersBack references from receiver This guards against multiple registration of the same receiver for a given signal and sender leaking memory as old back reference records build up. Also removes old receiver instance from receivers """ try: index = receivers.index(receiver) # need to scan back references here and remove senderkey except ValueError: return False else: oldReceiver = receivers[index] del receivers[index] found = 0 signals = connections.get(signal) if signals is not None: for sig,recs in connections.get(signal,{}).items(): if sig != signal: for rec in recs: if rec is oldReceiver: found = 1 break if not found: _killBackref( oldReceiver, senderkey ) return True return False def _killBackref( receiver, senderkey ): """Do the actual removal of back reference from receiver to senderkey""" receiverkey = id(receiver) set = sendersBack.get( receiverkey, () ) while senderkey in set: try: set.remove( senderkey ) except: break if not set: try: del sendersBack[ receiverkey ] except KeyError: pass return True ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1574192583.0 PyDispatcher-2.0.7/pydispatch/errors.py0000644000175000017500000000056313565042707020366 0ustar00mcfletchmcfletch"""Error types for dispatcher mechanism """ class DispatcherError(Exception): """Base class for all Dispatcher errors""" class DispatcherKeyError(KeyError, DispatcherError): """Error raised when unknown (sender,signal) set specified""" class DispatcherTypeError(TypeError, DispatcherError): """Error raised when inappropriate signal-type specified (None)""" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1574192583.0 PyDispatcher-2.0.7/pydispatch/robust.py0000644000175000017500000000404313565042707020365 0ustar00mcfletchmcfletch"""Module implementing error-catching version of send (sendRobust)""" from pydispatch.dispatcher import Any, Anonymous, liveReceivers, getAllReceivers from pydispatch.robustapply import robustApply def sendRobust( signal=Any, sender=Anonymous, *arguments, **named ): """Send signal from sender to all connected receivers catching errors signal -- (hashable) signal value, see connect for details sender -- the sender of the signal if Any, only receivers registered for Any will receive the message. if Anonymous, only receivers registered to receive messages from Anonymous or Any will receive the message Otherwise can be any python object (normally one registered with a connect if you actually want something to occur). arguments -- positional arguments which will be passed to *all* receivers. Note that this may raise TypeErrors if the receivers do not allow the particular arguments. Note also that arguments are applied before named arguments, so they should be used with care. named -- named arguments which will be filtered according to the parameters of the receivers to only provide those acceptable to the receiver. Return a list of tuple pairs [(receiver, response), ... ] if any receiver raises an error (specifically any subclass of Exception), the error instance is returned as the result for that receiver. """ # Call each receiver with whatever arguments it can accept. # Return a list of tuple pairs [(receiver, response), ... ]. responses = [] for receiver in liveReceivers(getAllReceivers(sender, signal)): try: response = robustApply( receiver, signal=signal, sender=sender, *arguments, **named ) except Exception as err: responses.append((receiver, err)) else: responses.append((receiver, response)) return responses././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1574192583.0 PyDispatcher-2.0.7/pydispatch/robustapply.py0000644000175000017500000000404513565042707021435 0ustar00mcfletchmcfletch"""Robust apply mechanism Provides a function "call", which can sort out what arguments a given callable object can take, and subset the given arguments to match only those which are acceptable. """ import sys if sys.hexversion >= 0x3000000: im_func = '__func__' im_self = '__self__' im_code = '__code__' func_code = '__code__' else: im_func = 'im_func' im_self = 'im_self' im_code = 'im_code' func_code = 'func_code' def function( receiver ): """Get function-like callable object for given receiver returns (function_or_method, codeObject, fromMethod) If fromMethod is true, then the callable already has its first argument bound """ if hasattr(receiver, '__call__'): # Reassign receiver to the actual method that will be called. if hasattr( receiver.__call__, im_func) or hasattr( receiver.__call__, im_code): receiver = receiver.__call__ if hasattr( receiver, im_func ): # an instance-method... return receiver, getattr(getattr(receiver, im_func), func_code), 1 elif not hasattr( receiver, func_code): raise ValueError('unknown reciever type %s %s'%(receiver, type(receiver))) return receiver, getattr(receiver,func_code), 0 def robustApply(receiver, *arguments, **named): """Call receiver with arguments and an appropriate subset of named """ receiver, codeObject, startIndex = function( receiver ) acceptable = codeObject.co_varnames[startIndex+len(arguments):codeObject.co_argcount] for name in codeObject.co_varnames[startIndex:startIndex+len(arguments)]: if name in named: raise TypeError( """Argument %r specified both positionally and as a keyword for calling %r"""% ( name, receiver, ) ) if not (codeObject.co_flags & 8): # fc does not have a **kwds type parameter, therefore # remove unacceptable arguments. named = dict([(k,v) for k,v in named.items() if k in acceptable]) return receiver(*arguments, **named) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1574192583.0 PyDispatcher-2.0.7/pydispatch/saferef.py0000644000175000017500000001631613565042707020470 0ustar00mcfletchmcfletch"""Refactored "safe reference" from dispatcher.py""" import weakref, traceback, sys if sys.hexversion >= 0x3000000: im_func = '__func__' im_self = '__self__' else: im_func = 'im_func' im_self = 'im_self' def safeRef(target, onDelete = 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. onDelete -- 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. """ if hasattr(target, im_self): if getattr(target, 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), """safeRef target %r has %s, but no %s, don't know how to create reference"""%( target,im_self,im_func) reference = BoundMethodWeakref( target=target, onDelete=onDelete ) return reference if onDelete is not None: return weakref.ref(target, onDelete) else: return weakref.ref( target ) 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 calculateKey method applied to the target instance method deletionMethods -- 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 onDelete parameters of safeRef calls. weakSelf -- weak reference to the target object weakFunc -- weak reference to the target function Class Attributes: _allInstances -- class attribute pointing to all live BoundMethodWeakref objects indexed by the class's calculateKey(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. """ _allInstances = weakref.WeakValueDictionary() def __new__( cls, target, onDelete=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 deletionMethods attribute updated. Otherwise the new instance is created and registered in the table of already-referenced methods. """ key = cls.calculateKey(target) current =cls._allInstances.get(key) if current is not None: current.deletionMethods.append( onDelete) return current else: base = super( BoundMethodWeakref, cls).__new__( cls ) cls._allInstances[key] = base base.__init__( target, onDelete, *arguments,**named) return base def __init__(self, target, onDelete=None): """Return a weak-reference-like instance for a bound method target -- the instance-method target for the weak reference, must have and attributes and be reconstructable via: target..__get__( target. ) which is true of built-in instance methods. onDelete -- 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.deletionMethods[:] del self.deletionMethods[:] try: del self.__class__._allInstances[ self.key ] except KeyError: pass for function in methods: try: if hasattr(function, '__call__' ): function( self ) except Exception as e: try: traceback.print_exc() except AttributeError: print('''Exception during saferef %s cleanup function %s: %s'''%( self, function, e )) self.deletionMethods = [onDelete] self.key = self.calculateKey( target ) self.weakSelf = weakref.ref(getattr(target,im_self), remove) self.weakFunc = weakref.ref(getattr(target,im_func), remove) self.selfName = getattr(target,im_self).__class__.__name__ self.funcName = str(getattr(target,im_func).__name__) def calculateKey( 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(getattr(target,im_self)),id(getattr(target,im_func))) calculateKey = classmethod( calculateKey ) def __str__(self): """Give a friendly representation of the object""" return """%s( %s.%s )"""%( self.__class__.__name__, self.selfName, self.funcName, ) __repr__ = __str__ def __nonzero__( self ): """Whether we are still a valid reference""" return self() is not None __bool__ = __nonzero__ 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.weakSelf() if target is not None: function = self.weakFunc() if function is not None: return function.__get__(target) return None ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1676664486.0 PyDispatcher-2.0.7/pyproject.toml0000644000175000017500000000171314373757246017253 0ustar00mcfletchmcfletch[project] name="PyDispatcher" description="Multi-producer multi-consumer in-memory signal dispatch system" dynamic=["version"] keywords=["dispatcher", "dispatch", "pydispatch", "event", "signal", "sender", "receiver", "propagate", "multi-consumer", "multi-producer", "saferef", "robustapply", "apply"] authors = [ { name = "Patrick K. O'Brien" } ] maintainers = [ { name = "Mike C. Fletcher", email = "mcfletch@vrplumber.com" } ] classifiers = ["License :: OSI Approved :: BSD License", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 3", "Topic :: Software Development :: Libraries :: Python Modules", "Intended Audience :: Developers"] readme = {file="README.md", content-type="text/markdown"} license ={text= "BSD"} [project.optional-dependencies] dev = [ "tox", ] [build-system] requires = ["setuptools>=40.8.0", "wheel"] [tool.setuptools.dynamic] version = {attr = "pydispatch.__version__"} ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1676664578.5341449 PyDispatcher-2.0.7/setup.cfg0000644000175000017500000000173114373757403016153 0ustar00mcfletchmcfletch[metadata] name = PyDispatcher version = attr: pydispatch.__init__.__version__ description = Multi-Producer Multi-Consumer Observer Pattern for Python author = "Patrick K. O'Brien" maintainer = Mike C. Fletcher maintainer_email = mcfletch@vrplumber.com url = https://github.com/mcfletch/pydispatcher download_url = https://pypi.org/project/pydispatcher/ license = BSD long_description = file: README.md long_description_content_type = text/markdown platforms = Any keywords = dispatcher dispatch pydispatch event signal sender receiver propagate multi-consumer multi-producer saferef robustapply apply classifiers = License :: OSI Approved :: BSD License Programming Language :: Python Programming Language :: Python :: 2 Programming Language :: Python :: 3 Topic :: Software Development :: Libraries :: Python Modules Intended Audience :: Developers [options] packages = find: [options.packages.find] include = pydispatch [egg_info] tag_build = tag_date = 0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1661978880.0 PyDispatcher-2.0.7/setup.py0000644000175000017500000000145614303744400016032 0ustar00mcfletchmcfletch#!/usr/bin/env python """Installs PyDispatcher using distutils (or setuptools/distribute) Run: python setup.py install to install the package from the source archive. """ import sys, os from distutils.core import setup if __name__ == "__main__": ### Now the actual set up call setup( name="PyDispatcher", package_dir={ "pydispatch": "pydispatch", }, packages=[ "pydispatch", ], options={ "sdist": { "use_defaults": 0, "force_manifest": 1, "formats": ["gztar"], }, "bdist_rpm": { "group": "Libraries/Python", "provides": "python-dispatcher", "requires": "python", }, }, ) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1676664578.5341449 PyDispatcher-2.0.7/tests/0000755000175000017500000000000014373757403015472 5ustar00mcfletchmcfletch././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1574192583.0 PyDispatcher-2.0.7/tests/__init__.py0000644000175000017500000000005313565042707017575 0ustar00mcfletchmcfletch"""Unit-tests for the dispatch project """ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1574192583.0 PyDispatcher-2.0.7/tests/test_dispatcher.py0000644000175000017500000001216413565042707021231 0ustar00mcfletchmcfletchfrom pydispatch.dispatcher import * from pydispatch import dispatcher, robust import unittest def x(a): return a class Dummy( object ): pass class Callable(object): def __call__( self, a ): return a def a( self, a ): return a class DispatcherTests(unittest.TestCase): """Test suite for dispatcher (barely started)""" def _isclean( self ): """Assert that everything has been cleaned up automatically""" assert len(dispatcher.sendersBack) == 0, dispatcher.sendersBack assert len(dispatcher.connections) == 0, dispatcher.connections assert len(dispatcher.senders) == 0, dispatcher.senders def testExact (self): a = Dummy() signal = 'this' connect( x, signal, a ) expected = [(x,a)] result = send('this',a, a=a) assert result == expected,"""Send didn't return expected result:\n\texpected:%s\n\tgot:%s"""% (expected, result) disconnect( x, signal, a ) assert len(list(getAllReceivers(a,signal))) == 0 self._isclean() def testAnonymousSend(self): a = Dummy() signal = 'this' connect( x, signal ) expected = [(x,a)] result = send(signal,None, a=a) assert result == expected,"""Send didn't return expected result:\n\texpected:%s\n\tgot:%s"""% (expected, result) disconnect( x, signal ) assert len(list(getAllReceivers(None,signal))) == 0 self._isclean() def testAnyRegistration(self): a = Dummy() signal = 'this' connect( x, signal, Any ) expected = [(x,a)] result = send('this',object(), a=a) assert result == expected,"""Send didn't return expected result:\n\texpected:%s\n\tgot:%s"""% (expected, result) disconnect( x, signal, Any ) expected = [] result = send('this',object(), a=a) assert result == expected,"""Send didn't return expected result:\n\texpected:%s\n\tgot:%s"""% (expected, result) assert len(list(getAllReceivers(Any,signal))) == 0 self._isclean() def testAnyRegistration2(self): a = Dummy() signal = 'this' connect( x, Any, a ) expected = [(x,a)] result = send(signal,a, a=a) assert result == expected,"""Send didn't return expected result:\n\texpected:%s\n\tgot:%s"""% (expected, result) disconnect( x, Any, a ) assert len(list(getAllReceivers(a,Any))) == 0 self._isclean() def testGarbageCollected(self): a = Callable() b = Dummy() signal = 'this' connect( a.a, signal, b ) expected = [] del a result = send('this',b, a=b) assert result == expected,"""Send didn't return expected result:\n\texpected:%s\n\tgot:%s"""% (expected, result) assert len(list(getAllReceivers(b,signal))) == 0, """Remaining handlers: %s"""%(getAllReceivers(b,signal),) self._isclean() def testGarbageCollectedObj(self): class x: def __call__( self, a ): return a a = Callable() b = Dummy() signal = 'this' connect( a, signal, b ) expected = [] del a result = send('this',b, a=b) assert result == expected,"""Send didn't return expected result:\n\texpected:%s\n\tgot:%s"""% (expected, result) assert len(list(getAllReceivers(b,signal))) == 0, """Remaining handlers: %s"""%(getAllReceivers(b,signal),) self._isclean() def testMultipleRegistration(self): a = Callable() b = Dummy() signal = 'this' connect( a, signal, b ) connect( a, signal, b ) connect( a, signal, b ) connect( a, signal, b ) connect( a, signal, b ) connect( a, signal, b ) result = send('this',b, a=b) assert len( result ) == 1, result assert len(list(getAllReceivers(b,signal))) == 1, """Remaining handlers: %s"""%(getAllReceivers(b,signal),) del a del b del result self._isclean() def testRobust( self ): """Test the sendRobust function""" signal = 'this' def fails( ): raise ValueError( signal ) a = object() connect( fails, Any, a ) result = robust.sendRobust(signal,a, a=a) err = result[0][1] assert isinstance( err, ValueError ) assert err.args == (signal,) def testParameterRepr(self): assert repr(dispatcher.Any) == '_Any', repr(dispatcher.Any) assert str(dispatcher.Any) == '_Any', str(dispatcher.Any) def testNoNoneSignal(self): self.assertRaises( errors.DispatcherTypeError, dispatcher.connect, x, signal=None ) self.assertRaises( errors.DispatcherTypeError, dispatcher.disconnect, x, signal=None ) def testDisconnectUnconnected(self): self.assertRaises( errors.DispatcherKeyError, dispatcher.disconnect, x, signal='not-registered' ) def getSuite(): return unittest.makeSuite(DispatcherTests,'test') if __name__ == "__main__": unittest.main () ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1676662633.0 PyDispatcher-2.0.7/tests/test_packaging.py0000644000175000017500000000070114373753551021025 0ustar00mcfletchmcfletchimport unittest class PackagingTest(unittest.TestCase): def test_package_metadata(self): try: from importlib import metadata except ImportError: pass else: version = metadata.version("pydispatcher") version = [int(x) for x in version.split('.')] assert version >= [2,0,7], "Our installed version did not pick up configured attribute pydispatch.__version__" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1574192583.0 PyDispatcher-2.0.7/tests/test_robustapply.py0000644000175000017500000000133113565042707021461 0ustar00mcfletchmcfletchfrom pydispatch.robustapply import * import unittest def noArgument(): pass def oneArgument (blah): pass def twoArgument(blah, other): pass class TestCases( unittest.TestCase ): def test01( self ): robustApply(noArgument ) def test02( self ): self.assertRaises( TypeError, robustApply, noArgument, "this" ) def test03( self ): self.assertRaises( TypeError, robustApply, oneArgument ) def test04( self ): """Raise error on duplication of a particular argument""" self.assertRaises( TypeError, robustApply, oneArgument, "this", blah = "that" ) def getSuite(): return unittest.makeSuite(TestCases,'test') if __name__ == "__main__": unittest.main() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1574192583.0 PyDispatcher-2.0.7/tests/test_saferef.py0000644000175000017500000000423713565042707020520 0ustar00mcfletchmcfletchfrom pydispatch.saferef import * import unittest class T1( object): def x( self ): pass def t2(obj): pass class T2( object ): def __call__( self, obj ): pass class Tester (unittest.TestCase): def setUp (self): ts = [] ss = [] for x in range( 5000 ): t = T1() ts.append( t) s = safeRef(t.x, self._closure ) ss.append( s) ts.append( t2 ) ss.append( safeRef(t2, self._closure) ) for x in range( 30 ): t = T2() ts.append( t) s = safeRef(t, self._closure ) ss.append( s) self.ts = ts self.ss = ss self.closureCount = 0 def tearDown( self ): del self.ts del self.ss def testIn(self): """Test the "in" operator for safe references (cmp)""" for t in self.ts[:50]: assert safeRef(t.x) in self.ss def testValid(self): """Test that the references are valid (return instance methods)""" for s in self.ss: assert s() def testShortCircuit (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 safeRef(t.x) in sd else: assert safeRef(t) in sd def testRepresentation (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 test(self): self.closureCount = 0 wholeI = len(self.ts) for i in range( len(self.ts)-1, -1, -1): del self.ts[i] if wholeI-i != self.closureCount: """Unexpected number of items closed, expected %s, got %s closed"""%( wholeI-i,self.closureCount) def _closure(self, ref): """Dumb utility mechanism to increment deletion counter""" self.closureCount +=1 def getSuite(): return unittest.makeSuite(Tester,'test') if __name__ == "__main__": unittest.main ()