{ "info": { "author": "Olivier Carrere", "author_email": "olivier.carrere@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Programming Language :: Python", "Programming Language :: Python :: 2 :: Only", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Utilities" ], "description": "============\ngevent_async\n============\n\nA small set of utilities to help with writing synchronous code flows in a collaborative multitasking context.\nIt has been designed around the feature set of gevent (http://www.gevent.org)\n\n--------------\ndeferred calls\n--------------\n\n``async.DeferredCallHandler`` is a wrapper for asynchronously handled function calls.\nThis allows to control in which context the execution of those functions are done, which is essential\nin collaborative multitasking.\n\nThere are 2 available types of calls:\n - ``sync`` (synchronous): this type of call awaits for the deferred call handle to process the call\n to return. for a user's perspective, it behaves like a regular function call.\n - ``oneway`` (one way): this type of call returns instantly. Due to its nature, there is no way to know\n whether, once it has been processed, it has succeeded or failed.\n\nExample\n=======\n\nFor instance, imagining we have a Manager entity that must handle some resources in an atomic manner:\n\n.. code-block:: python\n\n from async import DeferredCallHandler\n class Manager(DeferredCallHandler):\n def manage(self):\n # do things with resources\n # with the assurance that the resources won't\n # be modified during process\n\n self.process() # process pending calls\n\n # do more things\n\n def access_resources(self):\n #returns the resources the manager has properly managed.\n\n def update_resource(self, data):\n #updates a resource info\n\n def run(self):\n while True:\n self.manage()\n\nWe can startup the manager and call functions on it from multiple greenlets:\n\n.. code-block:: python\n\n manager = Manager()\n gevent.spawn(manager.run)\n # At that point, the manager entity is will be doing resource management\n\n resources = ... # we have an array of resources\n\n def monitor(target):\n for event in target.events():\n # we could apply some transformation to the event, and then\n # forward it to the manager.\n manager.oneway.update_resource(event)\n\n for resource in resources:\n gevent.spawn(monitor, resource)\n\n\n def consumer():\n while True:\n resources = manager.access_resources()\n # at that point, we have the guarantee that the resources\n # are properly managed and will not become stale or corrupted during process.\n\n consumer()\n\nDeferredCallHandler API documentation\n=====================================\n\n* ``def process(forever=False, whitelist=None)``:\n\n Processes all the the pending deferred calls.\n\n If ``forever`` is set to ``True``, process will remain waiting for new calls until\n a call to ``stop_processing()`` is performed.\n\n If ``whitelist`` is set as a list of string, only functions which names match the elements\n in the white list will be executed.\n\n* ``def stop_processing()``:\n\n Interrupts the iteration through incoming calls of a DeferredCallHandler's call to\n ``process(forever=True)``.\n\nExceptions\n==========\n\nsync calls will forward exceptions just like regular functions:\n\n.. code-block:: python\n\n from async import DeferredCallHandler\n class Lemming(DeferredCallHandler):\n def kaboom(self):\n raise Exception(\"#high pitched# oh no!\")\n\n lemming = Lemming()\n\n spawn(lemming.process, forever=True)\n\n try:\n lemming.sync.kaboom()\n except Exception:\n pass # We should hit that\n\n # This should trigger the exception but produce an exception log entry.\n lemming.oneway.kaboom()\n\nRegular function calls\n======================\n\n``DeferredCallHandler`` objects don't prevent direct function calls. Use at your own risk:\n\n.. code-block:: python\n\n from async import DeferredCallHandler\n class Manager(DeferredCallHandler):\n def manage(self):\n # do things with resources\n # with the assurance that the resources won't\n # be modified during process\n\n self.process() # process pending calls\n\n # do more things\n\n def access_resources(self):\n #returns the resources the manager has properly managed.\n\n def update_resource(self, data):\n #updates a resource info\n\n def run(self):\n while True:\n self.manage()\n\n manager = Manager()\n gevent.spawn(manager.run)\n\n resources = manager.access_resources()\n # !!! The resources may be in the middle of a management process and their state\n # may be incoherent\n\n resources = manager.sync.access_resources()\n # In that case, we're guaranteed the management process is not running.\n\nTimeouts\n========\n\n``sync`` calls can be specified with an optional timeout, to ensure actions are performed\nwithin a given time frame:\n\n.. code-block:: python\n\n from async import DeferredCallHandler\n class ABitSlow(DeferredCallHandler):\n def taking_my_time(self):\n gevent.sleep(10)\n\n slow = ABitSlow()\n\n spawn(slow.process, forever=True)\n\n try:\n slow.sync(timeout=1).taking_my_time()\n except gevent.Timeout:\n pass # We should hit that\n\n------------------------\nmultitask state handling\n------------------------\n\nPartially inspired by the mechanism of tail recursion, we provide a way to contain and handle code\nto manage the behaviour of state machines within greenlets.\n\nThe ``@state`` decorator transforms a function method into a state greenlet. When another state function\nis invoked, it create a new state greenlet that replaces the current state greenlet, effectively replicating\nthe behaviour of tail recursion.\n\nFor instance:\n\n.. code-block:: python\n\n @state(transitions_to=\"growing\")\n def sprouting()\n # germination process here\n growing() # the sprouting greenlet terminates and leaves way to the growing one\n\n @state(transitions_to=\"flowering\")\n def growing()\n # transform CO2 and sunlight to biomass\n flowering() # the growing greenlet terminates and leaves way to the flowering one\n\n @state(transitions_to=[\"dead\", \"withering\"])\n def flowering()\n # Grow flowers\n if is_eaten:\n # parameters can be given to state changes.\n dead(is_eaten=True) # the flowering greenlet terminates and leaves way to the dead one\n else:\n withering() # the flowering greenlet terminates and leaves way to the withering one\n\n @state(transitions_to=\"dead\")\n def withering()\n # Dry up\n dead() # the withering greenlet terminates and leaves way to the dead one\n\n @state # terminal state, no transitions\n def dead(is_eaten=False)\n if not is_eaten:\n # clean up phase\n\n\n sprouting() # spawns the initial state\n\nThe ``@state`` decorator can also be used for methods:\n\n.. code-block:: python\n\n class Flower(object):\n @state(transitions_to=\"growing\")\n def sprouting(self)\n # germination process here\n growing() # the sprouting greenlet terminates and leaves way to the growing one\n\n # ...\n\nCorrect transitions must be specified by the ``transitions_to`` parameter or any incorrect transition\nwill raise the ``ValidationError`` exception.\n\nCallbacks\n=========\n\nCallbacks can be defined on transition. By setting the on_start parameter to a state, a given callback will\nbe activated whenever a state is started.\n\nThe expected callback signature is ``def on_start(state, *args, **kwargs)``, where ``state`` is the\n(at that point, still not started) ``async.state.State`` state greenlet which will handle the execution of the state and\n``*args`` and ``**kwargs`` are the parameters given to the state call.\n\nFor instance:\n\n.. code-block:: python\n\n def on_transition(new_state, target, *args, **kwargs):\n if \"store\" in kwargs and kwargs[\"store\"]:\n target.state = new_state\n\n class Object(object):\n def __init__(self):\n self.state = None\n\n @state(on_start=on_transition)\n def a_state(self, store=False):\n pass\n\n obj = Object()\n obj.a_state(store=True)\n sleep()\n\n obj.state # => is now storing the current state object.\n\n", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "http://github.com/kapouille/gevent_async", "keywords": "gevent state asychronous synchronous", "license": "UNKNOWN", "maintainer": null, "maintainer_email": null, "name": "gevent_async", "package_url": "https://pypi.org/project/gevent_async/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/gevent_async/", "project_urls": { "Download": "UNKNOWN", "Homepage": "http://github.com/kapouille/gevent_async" }, "release_url": "https://pypi.org/project/gevent_async/0.8.5/", "requires_dist": null, "requires_python": null, "summary": "A small set of utilities to help with writing synchronouscode flows in a collaborative multitasking context.", "version": "0.8.5" }, "last_serial": 1142098, "releases": { "0.6": [ { "comment_text": "", "digests": { "md5": "b08dba4664f8b885f757cafab2e72d9a", "sha256": "8226f35927f10a3237f3c37754befc90f987096b6417bd262fe585bd1edf6a4a" }, "downloads": -1, "filename": "gevent_async-0.6.tar.gz", "has_sig": false, "md5_digest": "b08dba4664f8b885f757cafab2e72d9a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6876, "upload_time": "2014-02-07T11:33:06", "url": "https://files.pythonhosted.org/packages/5d/ec/fee78745811c01a3cfde92e7aaf92aa70e60f259c6dd3649bd9fc29fb4af/gevent_async-0.6.tar.gz" } ], "0.7": [ { "comment_text": "", "digests": { "md5": "e65bcc294e6fa9f59154cb41c41d7e93", "sha256": "b790c791981f6238b8d36539734ed9da046fe5f2de4e6fdb91518b5bbeb101b1" }, "downloads": -1, "filename": "gevent_async-0.7.tar.gz", "has_sig": false, "md5_digest": "e65bcc294e6fa9f59154cb41c41d7e93", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6842, "upload_time": "2014-02-17T11:11:56", "url": "https://files.pythonhosted.org/packages/1d/af/914170406ef11947627ba3aa2e0ee6f6ea610e78eb14ba9392e8b8fb8eb8/gevent_async-0.7.tar.gz" } ], "0.8": [ { "comment_text": "", "digests": { "md5": "cb0c706c222899e5d61d6509d3bf4796", "sha256": "d694d1f5bf8f81a5b404fe77479ae80c7c36999a41c5aaa55bf9d67b1af865c0" }, "downloads": -1, "filename": "gevent_async-0.8.tar.gz", "has_sig": false, "md5_digest": "cb0c706c222899e5d61d6509d3bf4796", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7646, "upload_time": "2014-02-21T09:39:40", "url": "https://files.pythonhosted.org/packages/aa/37/5995f74d1777a1bd9c182114151447d92437fa14ec16503b289fbde5565d/gevent_async-0.8.tar.gz" } ], "0.8.1": [ { "comment_text": "", "digests": { "md5": "9414d41cb8f55d5fed574397d3c0eb0a", "sha256": "3a5e22c94e1dd7584022de34594f58b0459dd158957c067e8898b319f74c7193" }, "downloads": -1, "filename": "gevent_async-0.8.1.tar.gz", "has_sig": false, "md5_digest": "9414d41cb8f55d5fed574397d3c0eb0a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6797, "upload_time": "2014-02-21T09:51:05", "url": "https://files.pythonhosted.org/packages/3e/4f/cc6d472577e74f41ec4ea15c8090cac96724b5a37caa95a4d31dbc51afdf/gevent_async-0.8.1.tar.gz" } ], "0.8.2": [ { "comment_text": "", "digests": { "md5": "b316ef26d74f8ea213ec7ae912d1b233", "sha256": "21904865f71ed59b2b0eace8b111e309a5bb210234db319aacbc946d1829038d" }, "downloads": -1, "filename": "gevent_async-0.8.2.tar.gz", "has_sig": false, "md5_digest": "b316ef26d74f8ea213ec7ae912d1b233", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7097, "upload_time": "2014-02-26T13:56:09", "url": "https://files.pythonhosted.org/packages/b9/1c/a4d6356efd6b780c9381c7c3448ba052be7c9f15945c195a6fea46a8669e/gevent_async-0.8.2.tar.gz" } ], "0.8.3": [ { "comment_text": "", "digests": { "md5": "2027cead00b83858d453f9f66ab09576", "sha256": "08d9323985bbfa4894df3c4fac490b764b449b06a60f00900c68c18a5ae96352" }, "downloads": -1, "filename": "gevent_async-0.8.3.tar.gz", "has_sig": false, "md5_digest": "2027cead00b83858d453f9f66ab09576", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7190, "upload_time": "2014-02-27T11:47:52", "url": "https://files.pythonhosted.org/packages/a7/cc/da45a6abf51db570aa7e99edb03677b3076cd376e053c0071a3b4e01385b/gevent_async-0.8.3.tar.gz" } ], "0.8.3.dev2-g9c0eaf9": [ { "comment_text": "", "digests": { "md5": "fb59fcec12a9ed08ba95f0563e7d84d2", "sha256": "c2e1ca9aad4f24de60e629c3d36ede85ecd8a957b8b7c58fb88dd852222f2684" }, "downloads": -1, "filename": "gevent_async-0.8.3.dev2-g9c0eaf9.tar.gz", "has_sig": false, "md5_digest": "fb59fcec12a9ed08ba95f0563e7d84d2", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7213, "upload_time": "2014-02-27T11:47:01", "url": "https://files.pythonhosted.org/packages/79/ea/0c71597736ebf746b00313a811178e5b6790d97f098ec56cf1cfdbf5b9fe/gevent_async-0.8.3.dev2-g9c0eaf9.tar.gz" } ], "0.8.4": [ { "comment_text": "", "digests": { "md5": "ed78d845ddcc68dd21bbdbc46d55cf2e", "sha256": "8997445d0fce329eef05e4f99be4ee6b25600b635d697e37f1dbcfbf04fe618e" }, "downloads": -1, "filename": "gevent_async-0.8.4.tar.gz", "has_sig": false, "md5_digest": "ed78d845ddcc68dd21bbdbc46d55cf2e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7558, "upload_time": "2014-06-10T10:53:16", "url": "https://files.pythonhosted.org/packages/9a/e5/916eb703dae6550a163c94767571288bd80e04ded49606a1df9ba21f7578/gevent_async-0.8.4.tar.gz" } ], "0.8.5": [ { "comment_text": "", "digests": { "md5": "b0b01568a69ed991774087110466784d", "sha256": "558706db7d178ba5157e54271b8b7f8a0258621114bcaa4bd3ce3edcafea1ab7" }, "downloads": -1, "filename": "gevent_async-0.8.5.tar.gz", "has_sig": false, "md5_digest": "b0b01568a69ed991774087110466784d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7437, "upload_time": "2014-06-30T13:47:17", "url": "https://files.pythonhosted.org/packages/33/b9/5184b1afc0f617206997ee198eb52d2928e143235260443b936665698694/gevent_async-0.8.5.tar.gz" } ], "v0.2": [ { "comment_text": "", "digests": { "md5": "5fed890533d067cc01e2957f7d655ab0", "sha256": "d58b9dba475c86840c3bc5654b17bae9a608c9c58223e79c9eab776ff8d6ab18" }, "downloads": -1, "filename": "gevent_async-v0.2.tar.gz", "has_sig": false, "md5_digest": "5fed890533d067cc01e2957f7d655ab0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6418, "upload_time": "2014-01-31T15:53:38", "url": "https://files.pythonhosted.org/packages/e4/3a/1d93ddfc9269e67e0b949652e895a60102bbaeee6bdd8ad338ff84b5a202/gevent_async-v0.2.tar.gz" } ], "v0.3": [ { "comment_text": "", "digests": { "md5": "6b2ae2f4849c4194ff08ba7baaf950e2", "sha256": "1f5b381b521cabfec5e4fc75806b1f091d69f240bde0bca8332b67b54dc45c1f" }, "downloads": -1, "filename": "gevent_async-v0.3.tar.gz", "has_sig": false, "md5_digest": "6b2ae2f4849c4194ff08ba7baaf950e2", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6779, "upload_time": "2014-02-03T10:48:57", "url": "https://files.pythonhosted.org/packages/d8/a5/960c2c8a7d3557a92c26d54b0a0c3521499d2005361e49411baef2b714f9/gevent_async-v0.3.tar.gz" } ], "v0.4": [ { "comment_text": "", "digests": { "md5": "5740f349909ae54895d5d62017e517ad", "sha256": "aba25ceb0e3dccc2d58ebad85a7939c9f82f3325d78068467bfd1b35e935bad5" }, "downloads": -1, "filename": "gevent_async-v0.4.tar.gz", "has_sig": false, "md5_digest": "5740f349909ae54895d5d62017e517ad", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6886, "upload_time": "2014-02-06T10:51:45", "url": "https://files.pythonhosted.org/packages/b3/6b/c664b8969cfb009a2fc33a967a1c9d70e792bca921406d7d7c8a88d45c34/gevent_async-v0.4.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "b0b01568a69ed991774087110466784d", "sha256": "558706db7d178ba5157e54271b8b7f8a0258621114bcaa4bd3ce3edcafea1ab7" }, "downloads": -1, "filename": "gevent_async-0.8.5.tar.gz", "has_sig": false, "md5_digest": "b0b01568a69ed991774087110466784d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7437, "upload_time": "2014-06-30T13:47:17", "url": "https://files.pythonhosted.org/packages/33/b9/5184b1afc0f617206997ee198eb52d2928e143235260443b936665698694/gevent_async-0.8.5.tar.gz" } ] }