{ "info": { "author": "Kevin L. Mitchell", "author_email": "kevin.mitchell@rackspace.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 3 - Alpha", "Environment :: Console", "License :: OSI Approved :: Apache Software License", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4" ], "description": "=========================\nEvent Processor Framework\n=========================\n\nEvProc is a framework for building complex event processors. There\nare many similar frameworks available, so why EvProc? EvProc provides\na few advantages. First, a ``@want()`` decorator is available to\npre-filter events, as opposed to registering an event handler on\nspecific events. (Filtering works primarily with an event name,\nallowing flexibility, but it is also possible to register arbitrary\nfilter functions, which can evaluate an event to determine whether to\ncall the event handler.) A second advantage is the ability to\nregister event handlers using the \"entrypoint\" support of\n``setuptools``, allowing extensibility. Finally, EvProc provides\nlimited inter-handler communication, using the ``proc`` property of\n``Event`` instances, and backs this up with the ability to specify\nordering among event handlers using requirements.\n\nDefining Events\n===============\n\nAn *event* in EvProc is an instance of a subclass of ``evproc.Event``.\nThe ``Event`` class is an abstract class; subclasses must implement a\n``name`` property, the contents of which will be a unique string\nnaming the event. The constructor takes a single optional argument, a\n``ctxt`` argument, which may be used to pass a context in to event\nhandlers. The constructor may, of course, be extended as required to\nprovide any necessary information about the event, such as a specific\nresource that the event occurred on.\n\nThe ``Event`` class also provides a special ``proc`` property. This\nproperty may be used by event handlers to store data for use by other\nevent handlers, by setting attributes. To minimize the possibility of\ntwo unrelated handlers attempting to manipulate the same attribute,\nthe ``proc`` property is *namespaced*; that is, attributes on ``proc``\nmay not be set, but attributes on those attributes may.\n\nAs an example of the use of the ``proc`` property, consider two event\nhandlers that wish to communicate with each other. Assume that these\nhandlers interact to perform testing; perhaps one handler selects test\nparameters, and the second handler actually performs the test (e.g.,\nthere may be multiple tests to perform). The first handler could set,\nsay, ``proc.tests.args`` and ``proc.tests.kwargs``, and the second\nhandler would then retrieve the values it needed.\n\nEvent Handlers\n==============\n\nAn *event handler* is simply a function that will be called with two\narguments; the first argument will be an instance of\n``evproc.Processor`` (described below), and the second will be an\ninstance of ``evproc.Event`` (described above). The event handler may\nperform any code necessary to process the event. Each event handler\nmust have a unique name; by default, the name will be the same as the\nfunction name, but this may be overridden when registering the event\nhandler. Event handlers may also be loaded from ``setuptools``\nentrypoints; in this case, the name used is the entrypoint name.\n\nThere are three optional decorators that may be used on an event\nhandler function. The first is the ``@evproc.want()`` decorator,\nwhich may be called with one or more event names; the handler function\nwill only be called if the event being handled matches one of these\nevent names. The decorator may also be passed one or more *filter\nfunctions*; in this case, the event handler will only be called if all\nof the filter functions return ``True``. If event names are also\npassed, then the event must also match one of those names. The\n``@want()`` decorator may be used multiple times to specify other sets\nof filters; the event need only match *one* filter specified by\n``@want()``. For instance, consider this example::\n\n @evproc.want('ev1', 'ev2')\n @evproc.want('ev3', lambda ev: ev.resource.name == 'resource')\n def handler(proc, ev):\n ...\n\nThis handler will be called for all events with the names \"ev1\" and\n\"ev2\", but will only be called for the event \"ev3\" if\n``ev.resource.name`` contains the value ``\"resource\"``.\n\nEvent handlers are able to interact with each other, as mentioned\nabove. To do this, it is necessary to enforce certain ordering\nguarantees on the event handler. This is controlled by the\n``@evproc.requires()`` and ``@evproc.required_by()`` decorators.\nThese decorators take the names of one or more event handlers (names\nare set at registration time, as mentioned above). The\n``@requires()`` decorator is used to indicate that the specified\nfunctions must run *before* the decorated function, while the\n``@required_by()`` decorator is used to indicate that the specified\nfunction require the *decorated* function to be run first. In both\ncases, the ``@want()`` decorators of the functions must be compatible.\n\nThe ``@requires()`` and ``@required_by()`` decorators are used to\ndefine a *dependency graph*, which is then topologically sorted to\nensure that the handler functions are called in the correct order. As\nan example, consider the split test functions mentioned above. We\ncould declare the functions like so::\n\n def test_prepare(proc, ev):\n ...\n ev.tests.args = args\n ev.tests.kwargs = kwargs\n\n @evproc.requires('test_prepare')\n def test_run(proc, ev):\n args = ev.tests.args\n kwargs = ev.tests.kwargs\n intermediate = getattr(ev.tests, 'auxiliary', [])\n ...\n\n @evproc.required_by('test_run')\n @evproc.requires('test_prepare')\n def test_auxiliary(proc, ev):\n ...\n ev.tests.auxiliary = results\n\nIn this example, the ``test_prepare()`` handler function would be\ncalled first, followed by the ``test_auxiliary()`` handler function,\nand finally the ``test_run()`` handler function would be called.\n\nAn event handler may optionally return a list of events, which will\nbe processed in order.\n\nThe Event Processor\n===================\n\nThe ``evproc.Processor`` class is responsible for processing events.\nTo use EvProc, instantiate a ``Processor`` instance and use its\n``register()`` or ``load_from()`` methods to declare event handler\nfunctions. Then, simply pass ``Event`` instances to the ``process()``\nmethod to invoke the event processors in the correct order.\n\nThe ``Processor.register()`` method may be used to register individual\nevent handler functions. By default, the function's declared name\n(``func.__name__``) is used as the handler name, but this may be\noverridden by passing the optional ``name`` parameter to\n``register()``.\n\nTo load event handlers from a ``setuptools`` entrypoint, use the\n``Processor.load_from()`` method. This method takes, as its sole\nargument, the entrypoint group name; as an example, if one installed\napplication has a ``setup.py`` containing::\n\n entry_points={\n 'app.handlers': [\n 'test_prepare = app:test_prepare',\n 'test_run = app.test_run',\n ],\n }\n\nAnd if a second installed application has the following in its\n``setup.py``::\n\n entry_points={\n 'app.handlers': [\n 'test_auxiliary = otherapp:test_auxiliary',\n ],\n }\n\nThen all three handler functions could be loaded into the\n``Processor`` instance ``proc`` with the following call::\n\n proc.load_from('app.handlers')\n\nThe ``Processor.process()`` method may be called as many times as\nnecessary. In fact, most event-driven applications consist of a loop\nwhich constructs ``Event`` instances, then passes them to the\n``Processor.process()`` method. A full application could look\nsomething like the following::\n\n def main():\n proc = evproc.Processor()\n proc.load_from('app.handlers')\n\n while True:\n # Construct event objects\n ...\n ev = AppEvent(...)\n\n # Process the event\n proc.process(ev)\n\n``Processor.process()`` returns ``None`` unless an event processor\nraises a ``evproc.StopProcessing`` exception initialized with a\n``retval``, in which case it returns the exception's ``retval``.\n\nStop Processing\n---------------\n\nIt may be necessary for one event processor to stop all event\nprocessing. This could, for instance, be used by a processor that\nperforms an authorization check if the event fails that check. To\nallow this, an event processor may raise the ``evproc.StopProcessing``\nexception. When an event processor raises a ``StopProcessing``\nexception, no additional event processors will be called for that\nevent. If the ``StopProcessing`` exception is raised without a\n``retval``, yet-unprocessed events returned by prior event processors\nwill still be processed. If the ``StopProcessing`` exception is\nraised with a ``retval`` (even if ``None``), ``Processor.process()``\nwill immediately return the exception's ``retval``, and yet-unprocessed\nevents returned by prior event processors will not be processed.\n\nConclusion\n==========\n\nEvProc provides an easy to extend event processing framework, capable\nof not only calling event handler functions, but of ensuring certain\nordering constraints and limited inter-handler communication. The\nability to use ``setuptools`` entrypoints allows new event handlers to\nbe inserted into the event processing loop easily without having to\nmodify the original application, and the ordering constraints can\nallow such inserted event handlers to interact with the existing ones\njust as easily.", "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/klmitch/evproc", "keywords": null, "license": "UNKNOWN", "maintainer": null, "maintainer_email": null, "name": "evproc", "package_url": "https://pypi.org/project/evproc/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/evproc/", "project_urls": { "Download": "UNKNOWN", "Homepage": "https://github.com/klmitch/evproc" }, "release_url": "https://pypi.org/project/evproc/0.2.0/", "requires_dist": null, "requires_python": null, "summary": "Event Processor Framework", "version": "0.2.0" }, "last_serial": 2019216, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "8ef58a86a7dde58786bda55db88b20f6", "sha256": "49968fe5ab0052b848d8ce385a55c904934008b8d7b5263af4cb76b75f13f157" }, "downloads": -1, "filename": "evproc-0.1.0.tar.gz", "has_sig": false, "md5_digest": "8ef58a86a7dde58786bda55db88b20f6", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 21042, "upload_time": "2014-10-23T20:09:32", "url": "https://files.pythonhosted.org/packages/ce/47/66b0761d83bd92b94918706bfec3b413d1d9aec60b7229edb6c28edbc034/evproc-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "358c1fb95f10d60941d43747082d041a", "sha256": "63acf36493d35bc6a761c1fc1f5a779efbfb652556dc95bcbc8e94a07ae11d39" }, "downloads": -1, "filename": "evproc-0.1.1.tar.gz", "has_sig": false, "md5_digest": "358c1fb95f10d60941d43747082d041a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 21729, "upload_time": "2014-11-25T18:32:11", "url": "https://files.pythonhosted.org/packages/1b/bc/43f9e6a9c56d1dff98fc82452669d387ce2d4aee6be3d83b17b6770a58ae/evproc-0.1.1.tar.gz" } ], "0.1.2": [ { "comment_text": "", "digests": { "md5": "0e0171cff5f0d4ba99ad976d8325878e", "sha256": "a6e0cb17affe3e5d94441c6623caecc31bc8e1c00c04165317dbfb80e430eb89" }, "downloads": -1, "filename": "evproc-0.1.2.tar.gz", "has_sig": false, "md5_digest": "0e0171cff5f0d4ba99ad976d8325878e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 21799, "upload_time": "2015-07-21T18:51:22", "url": "https://files.pythonhosted.org/packages/fd/10/76aaf7dc019854eac31769482fdc51af92f99c51a32fc9312cd8e58e5c04/evproc-0.1.2.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "98ed82de1ad170e5523ff15d729b7691", "sha256": "90f2b0aaac4f454e2adbe1d03c925cac85726dff3b52b672584a49bffd45b22d" }, "downloads": -1, "filename": "evproc-0.2.0.tar.gz", "has_sig": false, "md5_digest": "98ed82de1ad170e5523ff15d729b7691", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 22035, "upload_time": "2016-03-21T18:40:50", "url": "https://files.pythonhosted.org/packages/1f/e4/f6ed3bc504883053d4e64e7821a89f5d26b17cf4a88cf2d72e2a9b8e4a01/evproc-0.2.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "98ed82de1ad170e5523ff15d729b7691", "sha256": "90f2b0aaac4f454e2adbe1d03c925cac85726dff3b52b672584a49bffd45b22d" }, "downloads": -1, "filename": "evproc-0.2.0.tar.gz", "has_sig": false, "md5_digest": "98ed82de1ad170e5523ff15d729b7691", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 22035, "upload_time": "2016-03-21T18:40:50", "url": "https://files.pythonhosted.org/packages/1f/e4/f6ed3bc504883053d4e64e7821a89f5d26b17cf4a88cf2d72e2a9b8e4a01/evproc-0.2.0.tar.gz" } ] }