{ "info": { "author": "Olivier Verdier", "author_email": "olivier.verdier@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", "Programming Language :: Python", "Topic :: Software Development :: Libraries :: Python Modules" ], "description": "# Dispatch: signal broadcasting in python\n\nThis python library is extracted from [django](http://djangoproject.com)'s [dispatch module](http://code.djangoproject.com/browser/django/trunk/django/dispatch).\n\nThis very documentation is also adapted from [the django documentation on signals](http://docs.djangoproject.com/en/1.1/topics/signals/).\n\n\nOverview\n========\n\nSignals are useful when two otherwise unrelated pieces of code depend on each other.\nThe general pattern is that a *receiver* (or listener) may *subscribe* (or listen) to the *signal* of a *sender*.\nWhen the sender sends (or broadcasts) a signal, the receiver is called.\n\nHere is an excerpt from the [PyPubSub](http://pypi.python.org/pypi/PyPubSub/) documentation about the advantages of the signal pattern:\n\n* the sender/listener do not need to import each other;\n* a sender doesn't need to know\n * \"who\" gets the messages,\n * what the listeners will do with the data,\n * or even *if* any listener will get the message data;\n* similarly, listeners do not necessarily need to worry about where messages come from.\n\nLazy Evaluation Pattern\n-----------------------\n\nA typical use case is the *lazy evaluation* pattern, very useful whenever any expensive computing is involved.\nImagine that some expensive function `F` depends on one variable `x`.\nSince the evaluation of the function is expensive, the value `F(x)` will be cached.\n\nAssume further that `x` is defined in a totally unrelated module.\nHow to cache the value of `F(x)` so that it is only recomputed when `x` changes?\n\nA naive approach would be for `x` (or the object responsible for it) to explicitly tell the function `F` that `x` has changed.\nThe drawback is that `x` must know all the functions that depend on it!\nIt makes the code difficult to reuse, since each time you add a function depending on `x` you will have to change the code responsible for `x`.\nThis is not acceptable.\n\nThis is where signals come to the rescue.\nThe object responsible for changing `x` just has to send a signal whenever the value of `x` changes.\nThe function `F` then listens to that signal, and sets its cached value as needing to be recomputed.\n\nThe latter approach is very flexible.\nIt allows for several functions to depend on one variable `x`, without the variable `x` being aware of it.\nIt also allows for one function to depend on several variables, as long as all those variables send signals when their value changes.\n\n\nDefining and sending signals\n============================\n\n\nDefining signals\n----------------\n\n\nAll signals are `dispatch.Signal` instances.\nThe `providing_args` is a list of the names of arguments the signal will provide to listeners.\n\nFor example:\n\n```python\nimport dispatch\n\npizza_done = dispatch.Signal(providing_args=[\"toppings\", \"size\"])\n```\n\nThis declares a `pizza_done` signal that will provide receivers with `toppings` and `size` arguments.\nRemember that you're allowed to change this list of arguments at any time, so getting the API right on the first try isn't necessary.\n\nSending signals\n---------------\n\nTo send a signal, call `Signal.send`.\nYou must provide the `sender` argument, and may provide as many other keyword arguments as you like.\n\nFor example, here's how sending our `pizza_done` signal might look:\n\n```python\nclass PizzaStore(object):\n ...\n\n def send_pizza(self, toppings, size):\n pizza_done.send(sender=self, toppings=toppings, size=size)\n ...\n```\n \n\nListening to signals\n====================\n\nTo receive a signal, you need to register a *receiver* function that gets called when the signal is sent.\nLet's see how this works by registering a signal that gets called after each pizza is finished.\nWe'll be connecting to the `pizza_done` signal.\n\nReceiver functions\n------------------\n\nFirst, we need to define a receiver function.\nA receiver can be any Python function or method:\n\n```python\ndef my_callback(sender, **kwargs):\n print \"Pizza ready!\"\n```\n\nNotice that the function takes a `sender` argument, along with wildcard keyword arguments (`**kwargs`);\nall signal handlers must take these arguments.\n\nLook at the `**kwargs` argument.\nAll signals send keyword arguments, and may change those keyword arguments at any time.\nIn the case of `pizza_done`, it's documented as sending two arguments, topping and size, which means we might be tempted to write our signal handling as `my_callback(sender, toppings, size)`.\n\n\nThis would be wrong \u2013 in fact, `dispatch` will throw an error if you do so.\nThat's because at any point arguments could get added to the signal and your receiver must be able to handle those new arguments.\n\nConnecting receiver functions\n-----------------------------\n\nNext, we'll need to connect our receiver to the signal:\n\n```python\npizza_done.connect(my_callback)\n```\n\nNow, our `my_callback` function will be called each time a pizza is ready.\n\n\nConnecting to signals sent by specific senders\n----------------------------------------------\n\nSome signals get sent many times, but you'll only be interested in receiving a certain subset of those signals.\nFor example, consider the `pizza_done` signal.\nMost of the time, you don't need to know when *any* pizza is ready \u2013 just when a pizza from a *specific* pizza store is ready.\n\nIn these cases, you can register to receive signals sent only by particular senders.\nIn the case of the pizza example, the sender will be the pizza store, so you can indicate that you only want\nsignals sent by one particular kind of pizza store, or one particular pizza store:\n\n```python\nclass VegetarianPizzaStore(PizzaStore):\n ...\n\ndef my_handler(sender, **kwargs):\n ...\n\npizza_done.connect(my_handler, sender=VegetarianPizzaStore)\n```\n\nThe `my_handler` function will only be called when a pizza from any `VegetarianPizzaStore` is ready.\n\nSimilarly, you might only be interested in pizzas prepared in one specific pizza store:\n\n```python\nmy_pizza_store = PizzaStore()\n ...\n\ndef my_handler(sender, **kwargs):\n ...\n\npizza_done.connect(my_handler, sender=my_pizza_store)\n```\n\nThe `my_handler` function will only be called when a pizza from the object `my_pizza_store` is ready.\n", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/olivierverdier/dispatch", "keywords": null, "license": "UNKNOWN", "maintainer": null, "maintainer_email": null, "name": "dispatcher", "package_url": "https://pypi.org/project/dispatcher/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/dispatcher/", "project_urls": { "Download": "UNKNOWN", "Homepage": "https://github.com/olivierverdier/dispatch" }, "release_url": "https://pypi.org/project/dispatcher/1.0/", "requires_dist": null, "requires_python": null, "summary": "A library for event-driven programming", "version": "1.0" }, "last_serial": 788989, "releases": { "1.0": [ { "comment_text": "", "digests": { "md5": "c0ea7c5faa29b357c9aa505d5b15d668", "sha256": "b82ee55904098c418d412262ff871a1ebc1cf91ea5d9cfb30e950fec3b8c0edb" }, "downloads": -1, "filename": "dispatcher-1.0.tar.gz", "has_sig": false, "md5_digest": "c0ea7c5faa29b357c9aa505d5b15d668", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7955, "upload_time": "2012-07-06T18:55:26", "url": "https://files.pythonhosted.org/packages/c0/e3/61d6b42829e97fc84d9c0a5889b5aab3ebecefc03c17cb16c85f7edc11ea/dispatcher-1.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "c0ea7c5faa29b357c9aa505d5b15d668", "sha256": "b82ee55904098c418d412262ff871a1ebc1cf91ea5d9cfb30e950fec3b8c0edb" }, "downloads": -1, "filename": "dispatcher-1.0.tar.gz", "has_sig": false, "md5_digest": "c0ea7c5faa29b357c9aa505d5b15d668", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7955, "upload_time": "2012-07-06T18:55:26", "url": "https://files.pythonhosted.org/packages/c0/e3/61d6b42829e97fc84d9c0a5889b5aab3ebecefc03c17cb16c85f7edc11ea/dispatcher-1.0.tar.gz" } ] }