{ "info": { "author": "Federico Ficarelli", "author_email": "federico.ficarelli@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: OS Independent", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Topic :: Software Development :: Libraries" ], "description": "=========\nAutomaton\n=========\n\nPythonic finite-state machines.\n\n|build-status| |coverage-status| |documentation-status| |codeqa| |pypi| |license-status|\n\nAutomaton is an easy to use, *pythonic* `finite-state machine`_ module for Python 3.4 or greater.\nThe goal here is to have something to define finite-state machines in a minimal, straightforward\nand elegant way that enforces **clarity** and **correctness**.\n\nInstallation\n============\nAutomaton is available on `pypi `_,\nso to install it just use:\n\n.. code::\n\n $ pip3 install python-automaton\n\n\nDependencies\n============\n\n* `Python >= 3.4`\n* `networkx `_\n* `tabulate `_\n\n\nGetting started\n===============\n\nIn order to define an automaton, just subclass a provided base:\n\n.. code-block:: python\n\n from automaton import *\n\n class TrafficLight(Automaton):\n\n go = Event(\"red\", \"green\")\n slowdown = Event(\"green\", \"yellow\")\n stop = Event(\"yellow\", \"red\")\n\nYou're done: you now have a new *automaton* definition that can be instantiated to an **initial state**:\n\n.. code-block:: python\n\n crossroads = TrafficLight(initial_state=\"red\")\n assert crossroads.state == \"red\"\n\nEach **event** (also known as **transition**) is a class attribute defined by its **source state** and\n**destination state**. When an *event fires*, the automaton changes its state from the *source* to the *destination*:\nyou can *fire* an event by calling it:\n\n.. code-block:: python\n\n crossroads.go()\n assert crossroads.state == \"green\"\n crossroads.slowdown()\n assert crossroads.state == \"yellow\"\n\nAn alternative way, more convenient if triggering events progammatically, is to call the ``event()`` method:\n\n.. code-block:: python\n\n crossroads.event(\"stop\")\n assert crossroads.state == \"red\"\n\nCorrectness\n-----------\n\nAutomaton enforces correctness in two ways:\n\n1. checking that the requested event is *valid*, that is a transition from the current state to the destination\n state exists in the state machine definition;\n#. checking whether the *state graph* representing the automaton is *connected* or not (that is it must have only\n one `connected component`_).\n\nSo, if you try to trigger an invalid event...\n\n.. code-block:: python\n\n crossroads = TrafficLight(initial_state=\"red\")\n crossroads.stop()\n\n...you will end up with an error:\n\n.. code::\n\n automaton.InvalidTransitionError: The specified event 'Event(source_states=('yellow',), dest_state='red')'\n is invalid in current state 'red'.\n\n\nAgain, trying to define a class like this...\n\n.. code-block:: python\n\n class BrokenTrafficLight(Automaton):\n\n go = Event(\"red\", \"green\")\n slowdown = Event(\"green\", \"yellow\")\n # broken!\n stop = Event(\"black\", \"purple\")\n\n...will trigger an error:\n\n.. code::\n\n automaton.DefinitionError: The state graph contains 2 connected components:\n ['green', 'yellow', 'red'], ['purple', 'black']\n\n\nHow to visualize an automaton?\n------------------------------\n\nWhen things are getting complex and it seems that our automata are becoming autonomous life forms grasping to escape\nour control, it could be useful to have a *human friendly* representation of their behaviour.\n\nYou can ask for the *transition table*...\n\n.. code-block:: python\n\n transitiontable(TrafficLight, fmt='rst')\n\n...and you will be presented with a nice ``reStructuredText`` snippet:\n\n.. code::\n\n ======== ====== ========\n Source Dest Event\n ======== ====== ========\n green yellow slowdown\n yellow red stop\n red green go\n ======== ====== ========\n\nYou can ask for the *state graph* as well...\n\n.. code-block:: python\n\n stategraph(TrafficLight, fmt='plantuml')\n\n...and you'll end up with a proper `PlantUML `_ representation...\n\n.. code::\n\n @startuml\n [*] --> red\n green --> yellow : slowdown\n red --> green : go\n yellow --> red : stop\n @enduml\n\n...that can of course be rendered through ``plantuml``:\n\n.. image:: https://github.com/nazavode/automaton/raw/master/docs/source/_static/trafficlight.png\n :alt: Traffic Light Graph\n\n\nKeep your docstrings tidy!\n--------------------------\n\nSince *automata are classes* here, it would be great to have a textual representation of the automaton's behaviour\nin our docstrings. What about having one that updates itself in order to stay up-to-date with the\nactual code?\n\nHere you have it:\n\n.. code-block:: python\n\n class TrafficLight(Automaton):\n \"\"\" This is a pretty standard traffic light.\n\n This automaton follows the behaviour defined by\n the following transition table:\n\n {automaton:rst}\n\n \"\"\"\n\n go = Event(\"red\", \"green\")\n slowdown = Event(\"green\", \"yellow\")\n stop = Event(\"yellow\", \"red\")\n\nUsing a standard format specifier with the ``automaton`` keyword and the proper output format (e.g.: ``rst``), *the\nautomaton representation will be inserted in the docstring during the class definition*, **just where it should be**:\n\n.. code-block:: python\n\n >>> print(TrafficLight.__doc__)\n \"\"\" This is a pretty standard traffic light.\n\n This automaton follows the behaviour defined by\n the following transition table:\n\n ======== ====== ========\n Source Dest Event\n ======== ====== ========\n green yellow slowdown\n yellow red stop\n red green go\n ======== ====== ========\n\n \"\"\"\n\n*Easy!*\n\n\nDocumentation\n=============\n\nYou can find the full documentation at http://automaton.readthedocs.org.\n\n\nChanges\n=======\n\n\n1.3.0 *(2017-02-05)*\n--------------------\n\nAdded\n`````\n- Enabled access to all event's attributes from automaton instances.\n- New constructor parameter to initialize an automaton given an initial\n *startup* event.\n\nChanged\n```````\n- Misc bugs fixed.\n- Tests cleanup.\n- Improved reference and documentation.\n\n\n1.2.1 *(2017-01-30)*\n--------------------\n\nFixed\n`````\n- Severe distribution issue: package was missing some files.\n- Tox testing: ``py.test`` was running against *source files*,\n **not against the package installed in ``tox`` virtualenv**.\n\n\n1.2.0 *(2017-01-29)*\n--------------------\n\nAdded\n`````\n- Custom format specifiers for ``Automaton`` definitions (classes and instances).\n- Auto-docstring completion: if requested, the automaton textual representation\n is automatically added to the ``__doc__`` class attribute.\n\nChanged\n```````\n- Refactored formatting functions to more streamlined and coherent interfaces.\n- Removed package, now the whole library lives in one module file.\n\n\n1.1.0 *(2017-01-28)*\n--------------------\n\nAdded\n`````\n- Automaton representation as transition table or state-transition graph.\n\n\n1.0.0 *(2017-01-25)*\n--------------------\n\nAdded\n`````\n- Functions to retrieve incoming and outgoing events from a state or a set of states.\n\n\n.. _finite-state machine:\n https://en.wikipedia.org/wiki/Finite-state_machine\n\n.. _connected component:\n https://en.wikipedia.org/wiki/Connected_component_(graph_theory)\n\n.. |build-status| image:: https://travis-ci.org/nazavode/automaton.svg?branch=master\n :target: https://travis-ci.org/nazavode/automaton\n :alt: Build status\n\n.. |documentation-status| image:: https://readthedocs.org/projects/automaton/badge/?version=latest\n :target: http://automaton.readthedocs.io/en/latest/?badge=latest\n :alt: Documentation Status\n\n.. |coverage-status| image:: https://codecov.io/gh/nazavode/automaton/branch/master/graph/badge.svg\n :target: https://codecov.io/gh/nazavode/automaton\n :alt: Coverage report\n\n.. |license-status| image:: https://img.shields.io/badge/license-Apache2.0-blue.svg\n :target: http://opensource.org/licenses/Apache2.0\n :alt: License\n\n.. |codeqa| image:: https://api.codacy.com/project/badge/Grade/0eb6d3a1a1b04030852e153b13f7cbc9\n :target: https://www.codacy.com/app/federico-ficarelli/automaton?utm_source=github.com&utm_medium=referral&utm_content=nazavode/automaton&utm_campaign=badger\n :alt: Codacy Badge\n\n.. |pypi| image:: https://badge.fury.io/py/python-automaton.svg\n :target: https://badge.fury.io/py/python-automaton\n :alt: PyPI\n", "description_content_type": null, "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/nazavode/automaton", "keywords": "automata automaton statemachine", "license": "", "maintainer": "", "maintainer_email": "", "name": "python-automaton", "package_url": "https://pypi.org/project/python-automaton/", "platform": "", "project_url": "https://pypi.org/project/python-automaton/", "project_urls": { "Homepage": "https://github.com/nazavode/automaton" }, "release_url": "https://pypi.org/project/python-automaton/1.3.1/", "requires_dist": null, "requires_python": "", "summary": "Minimal finite-state machines", "version": "1.3.1" }, "last_serial": 2620851, "releases": { "0.2.0": [ { "comment_text": "", "digests": { "md5": "349555c405eeb48a0e50073736fd70f7", "sha256": "07486191ebd04238fe7086aa8c2e59695089a7c24342307ddf49924c328ad7e7" }, "downloads": -1, "filename": "python_automaton-0.2.0-py3.4.egg", "has_sig": false, "md5_digest": "349555c405eeb48a0e50073736fd70f7", "packagetype": "bdist_egg", "python_version": "3.4", "requires_python": null, "size": 11726, "upload_time": "2015-10-12T07:11:23", "url": "https://files.pythonhosted.org/packages/4a/0f/06400c16eeee3fbf74a653d461f15fb4718ea2aec40cb8fcbe769f4fdccc/python_automaton-0.2.0-py3.4.egg" }, { "comment_text": "", "digests": { "md5": "50b2bb5d691b5141354ec03ddc16caea", "sha256": "720da8b9e6ddf75c4ec53e9cce7cd0b968c8569ce794ec3df974e54f225223a5" }, "downloads": -1, "filename": "python-automaton-0.2.0.tar.gz", "has_sig": false, "md5_digest": "50b2bb5d691b5141354ec03ddc16caea", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10795, "upload_time": "2015-10-12T07:11:19", "url": "https://files.pythonhosted.org/packages/87/6e/a8e46a189e5698e58c0a7f0bb27f0a19e382688e8cf7936f078d67dfcf25/python-automaton-0.2.0.tar.gz" } ], "1.0.0": [ { "comment_text": "", "digests": { "md5": "db00cc3b91af0ac15014e94a7a1f8245", "sha256": "d3ec9794a05c28595e530bdc0fd17f2489f51b174ceb98cf779f2553b4a957c2" }, "downloads": -1, "filename": "python-automaton-1.0.0.tar.gz", "has_sig": false, "md5_digest": "db00cc3b91af0ac15014e94a7a1f8245", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11686, "upload_time": "2017-01-23T10:38:40", "url": "https://files.pythonhosted.org/packages/42/b4/7effab45a6a38e4b4c9286870b0175dc7a6a1d0114ba6654aa43c596a47f/python-automaton-1.0.0.tar.gz" } ], "1.1.0": [ { "comment_text": "", "digests": { "md5": "c3228be2009eb17d5c066af1445cb16d", "sha256": "7b058e6a474a1f5ecb65788da65425b3c3ad1482429e7f3fc32501eee47670e6" }, "downloads": -1, "filename": "python-automaton-1.1.0.tar.gz", "has_sig": false, "md5_digest": "c3228be2009eb17d5c066af1445cb16d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13111, "upload_time": "2017-01-28T00:05:59", "url": "https://files.pythonhosted.org/packages/4c/65/7bfc3c93b99b3eb7c64fc0190217f297b6b41f892965745377f383a85276/python-automaton-1.1.0.tar.gz" } ], "1.2.1": [ { "comment_text": "", "digests": { "md5": "424a16919c44ee46569343cadc02a2a4", "sha256": "1ca5e1981431b7f145a24832aedc00dff47aef2bbad4880f4eb3e585bc2e5786" }, "downloads": -1, "filename": "python-automaton-1.2.1.tar.gz", "has_sig": false, "md5_digest": "424a16919c44ee46569343cadc02a2a4", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10748, "upload_time": "2017-01-30T22:28:47", "url": "https://files.pythonhosted.org/packages/9e/47/fc06551aaed262ac01929f17184f9672f6d124b378e7120fea4f01930f47/python-automaton-1.2.1.tar.gz" } ], "1.3.1": [ { "comment_text": "", "digests": { "md5": "f71d692f6734316d67daca7336e31724", "sha256": "d4626dca05c95d2b07ec0114f5b23a34471795653588d4fc1798dfdb21ca6aa2" }, "downloads": -1, "filename": "python-automaton-1.3.1.tar.gz", "has_sig": false, "md5_digest": "f71d692f6734316d67daca7336e31724", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13897, "upload_time": "2017-02-05T17:49:09", "url": "https://files.pythonhosted.org/packages/50/38/f5d78889017a4d7ad23b716e6ebe846e5833f0d635beb4745495d0d6525e/python-automaton-1.3.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "f71d692f6734316d67daca7336e31724", "sha256": "d4626dca05c95d2b07ec0114f5b23a34471795653588d4fc1798dfdb21ca6aa2" }, "downloads": -1, "filename": "python-automaton-1.3.1.tar.gz", "has_sig": false, "md5_digest": "f71d692f6734316d67daca7336e31724", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13897, "upload_time": "2017-02-05T17:49:09", "url": "https://files.pythonhosted.org/packages/50/38/f5d78889017a4d7ad23b716e6ebe846e5833f0d635beb4745495d0d6525e/python-automaton-1.3.1.tar.gz" } ] }