{ "info": { "author": "Ilja & Peter", "author_email": "ilja@wise.fish", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Topic :: Database" ], "description": ".. image:: https://badge.fury.io/py/sqlalchemy-fsm.svg\n :target: https://badge.fury.io/py/sqlalchemy-fsm\n :alt: PyPI version\n\n\n.. image:: https://travis-ci.org/VRGhost/sqlalchemy-fsm.svg?branch=master\n :target: https://travis-ci.org/VRGhost/sqlalchemy-fsm\n :alt: Build Status\n\n\n.. image:: https://api.codeclimate.com/v1/badges/2a70f885d37f7fbb3287/maintainability\n :target: https://codeclimate.com/github/VRGhost/sqlalchemy-fsm/maintainability\n :alt: Maintainability\n\n\n.. image:: https://api.codeclimate.com/v1/badges/2a70f885d37f7fbb3287/test_coverage\n :target: https://codeclimate.com/github/VRGhost/sqlalchemy-fsm/test_coverage\n :alt: Test Coverage\n\n\nFinite state machine field for sqlalchemy\n=========================================\n\nsqlalchemy-fsm adds declarative states management for sqlalchemy models.\nInstead of adding some state field to a model, and manage its\nvalues by hand, you could use FSMState field and mark model methods\nwith the ``transition`` decorator. Your method will contain the side-effects\nof the state change.\n\nThe decorator also takes a list of conditions, all of which must be met\nbefore a transition is allowed.\n\nUsage\n-----\n\nAdd FSMState field to you model\n\n.. code-block:: python\n\n from sqlalchemy_fsm import FSMField, transition\n\n class BlogPost(db.Model):\n state = db.Column(FSMField, nullable = False)\n\nUse the ``transition`` decorator to annotate model methods\n\n.. code-block:: python\n\n @transition(source='new', target='published')\n def published(self):\n \"\"\"\n This function may contain side-effects,\n like updating caches, notifying users, etc.\n The return value will be discarded.\n \"\"\"\n\n``source`` parameter accepts a list of states, or an individual state.\nYou can use ``*`` for source, to allow switching to ``target`` from any state.\n\n``@transition``\\ - annotated methods have the following API:\n\n\n#. ``.method()`` - returns an SqlAlchemy filter condition that can be used for querying the database (e.g. ``session.query(BlogPost).filter(BlogPost.published())``\\ )\n#. ``.method.is_()`` - same as ``.method() == ``\n#. ``.method()`` - returns boolean value that tells if this particular record is in the target state for that method() (e.g. ``if not blog.published():``\\ )\n#. ``.method.set(*args, **kwargs)`` - changes the state of the record object to the transitions' target state (or raises an exception if it is not able to do so)\n#. ``.method.can_proceed(*args, **kwargs)`` - returns ``True`` if calling ``.method.set(*args, **kwargs)`` (with same ``*args, **kwargs``\\ ) should succeed.\n\nYou can also use ``None`` as source state for (e.g. in case when the state column in nullable).\nHowever, it is *not possible* to create transition with ``None`` as target state due to religious reasons.\n\nTransition can be also used on a class object to create a group of handlers\nfor same target state.\n\n.. code-block:: python\n\n @transition(target='published')\n class PublishHandler(object):\n\n @transition(source='new')\n def do_one(self, instance, value):\n instance.side_effect = \"published from new\"\n\n @transition(source='draft')\n def do_two(self, instance, value):\n instance.side_effect = \"published from draft\"\n\n\n class BlogPost(db.Model):\n ...\n published = PublishHandler\n\nThe transition is still to be invoked by calling the model's ``published.set()`` method.\n\nAn alternative inline class syntax is supported too:\n\n.. code-block:: python\n\n @transition(target='published')\n class published(object):\n\n @transition(source='new')\n def do_one(self, instance, value):\n instance.side_effect = \"published from new\"\n\n @transition(source='draft')\n def do_two(self, instance, value):\n instance.side_effect = \"published from draft\"\n\nIf calling ``published.set()`` succeeds without raising an exception, the state field\nwill be changed, but not written to the database.\n\n.. code-block:: python\n\n def publish_view(request, post_id):\n post = get_object__or_404(BlogPost, pk=post_id)\n if not post.published.can_proceed():\n raise Http404;\n\n post.published.set()\n post.save()\n return redirect('/')\n\nIf your given function requires arguments to validate, you need to include them\nwhen calling ``can_proceed`` as well as including them when you call the function\nnormally. Say ``publish.set()`` required a date for some reason:\n\n.. code-block:: python\n\n if not post.published.can_proceed(the_date):\n raise Http404\n else:\n post.publish(the_date)\n\nIf your code needs to know the state model is currently in, you can just call\nthe main function function.\n\n.. code-block:: python\n\n if post.deleted():\n raise Http404\n\nIf you require some conditions to be met before changing state, use the\n``conditions`` argument to ``transition``. ``conditions`` must be a list of functions\nthat take one argument, the model instance. The function must return either\n``True`` or ``False`` or a value that evaluates to ``True`` or ``False``. If all\nfunctions return ``True``\\ , all conditions are considered to be met and transition\nis allowed to happen. If one of the functions return ``False``\\ , the transition\nwill not happen. These functions should not have any side effects.\n\nYou can use ordinary functions\n\n.. code-block:: python\n\n def can_publish(instance):\n # No publishing after 17 hours\n if datetime.datetime.now().hour > 17:\n return False\n return True\n\nOr model methods\n\n.. code-block:: python\n\n def can_destroy(self):\n return not self.is_under_investigation()\n\nUse the conditions like this:\n\n.. code-block:: python\n\n @transition(source='new', target='published', conditions=[can_publish])\n def publish(self):\n \"\"\"\n Side effects galore\n \"\"\"\n\n @transition(source='*', target='destroyed', conditions=[can_destroy])\n def destroy(self):\n \"\"\"\n Side effects galore\n \"\"\"\n\nYou can also use FSM handlers to query the database. E.g.\n\n.. code-block:: python\n\n session.query(BlogCls).filter(BlogCls.publish())\n\nwill return all \"Blog\" objects whose current state matches \"publish\"'es target state.\n\nEvents\n------\n\nSqlalchemy-fsm integrates with sqlalchemy's event system.\nThe library exposes two events ``before_state_change`` and ``after_state_change`` that are fired up\nat the expected points of state's lifecycle.\n\nYou can subscribe event listeners via standard SQLAlchemy interface of\n``listens_for`` or ``listen``.\n\n.. code-block:: python\n\n from sqlalchemy.event import listens_for\n\n @listens_for(Blog, 'before_state_change')\n def on_state_change(instance, source, target):\n ...\n\nOr\n\n.. code-block:: python\n\n from sqlalchemy import event\n\n def on_state_change(instance, source, target):\n ...\n\n event.listen(Blog, 'after_state_change', on_state_change)\n\nIt is possible to de-register an event listener call with ``sqlalchemy.event.remove()`` method.\n\nHow does sqlalchemy-fsm diverge from django-fsm?\n------------------------------------------------\n\n\n* \n Can't commit data from within transition-decorated functions\n\n* \n Does support arguments to conditions functions", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/VRGhost/sqlalchemy-fsm", "keywords": "sqlalchemy finite state machine fsm", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "sqlalchemy-fsm", "package_url": "https://pypi.org/project/sqlalchemy-fsm/", "platform": "", "project_url": "https://pypi.org/project/sqlalchemy-fsm/", "project_urls": { "Homepage": "https://github.com/VRGhost/sqlalchemy-fsm" }, "release_url": "https://pypi.org/project/sqlalchemy-fsm/2.0.8/", "requires_dist": null, "requires_python": "", "summary": "Finite state machine field for sqlalchemy", "version": "2.0.8" }, "last_serial": 4816097, "releases": { "1.1.4": [ { "comment_text": "", "digests": { "md5": "1677c9ec12b25b1352f84dfbf95d2ce0", "sha256": "31f1e3f066e0cb126fa915ad433a020def406353fd2ce553c1451481cdd31e64" }, "downloads": -1, "filename": "sqlalchemy_fsm-1.1.4.tar.gz", "has_sig": false, "md5_digest": "1677c9ec12b25b1352f84dfbf95d2ce0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7836, "upload_time": "2018-01-20T22:29:44", "url": "https://files.pythonhosted.org/packages/ec/b8/f6eadf2b22b924c1fb9ffb989d9ebca919af0627264a91850688399a77ec/sqlalchemy_fsm-1.1.4.tar.gz" } ], "1.1.5": [ { "comment_text": "", "digests": { "md5": "db5f996e8f3acf368319eaeca10e1b7e", "sha256": "c5e94528873c5a551144a9937a990f48fb20f5314d2edeffb03057befc04c251" }, "downloads": -1, "filename": "sqlalchemy_fsm-1.1.5.tar.gz", "has_sig": false, "md5_digest": "db5f996e8f3acf368319eaeca10e1b7e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7846, "upload_time": "2018-01-20T22:36:49", "url": "https://files.pythonhosted.org/packages/b4/47/a89abaf8d8df53c617342860a7e139412295253c604bcdd02041799d299d/sqlalchemy_fsm-1.1.5.tar.gz" } ], "1.1.6": [ { "comment_text": "", "digests": { "md5": "d4cd1d41ba29001cd085705740d9978f", "sha256": "3a661dbdb5969d939ca5f82c6c8727b122df76f19a3169b92b043c3042cdd95e" }, "downloads": -1, "filename": "sqlalchemy_fsm-1.1.6.tar.gz", "has_sig": false, "md5_digest": "d4cd1d41ba29001cd085705740d9978f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8054, "upload_time": "2018-01-21T10:29:48", "url": "https://files.pythonhosted.org/packages/47/99/d19ec710d9f80085c7ce1f6c353467e4fde9bd9f20ab58fe0c9e4f67e1ba/sqlalchemy_fsm-1.1.6.tar.gz" } ], "1.1.7": [ { "comment_text": "", "digests": { "md5": "9df383d9b6a52bf4a30d9f6df0c13611", "sha256": "824ab3b115bed938ed7bfdc9b1e0ab1a72e22a1048b5a5815d05a8fa5317ef5f" }, "downloads": -1, "filename": "sqlalchemy_fsm-1.1.7.tar.gz", "has_sig": false, "md5_digest": "9df383d9b6a52bf4a30d9f6df0c13611", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8060, "upload_time": "2018-01-22T09:30:17", "url": "https://files.pythonhosted.org/packages/fc/8a/dbbf7c992b7b2d0af9d28b0840883c8cf22ef88445b205412d7cdc797319/sqlalchemy_fsm-1.1.7.tar.gz" } ], "2.0.0": [ { "comment_text": "", "digests": { "md5": "e8dea21a574541bcdd0aa0eb0ff2601a", "sha256": "84d4ad04511944e9c241855d879679c2213a5c0e48413cb820ec81fd190f2163" }, "downloads": -1, "filename": "sqlalchemy_fsm-2.0.0.tar.gz", "has_sig": false, "md5_digest": "e8dea21a574541bcdd0aa0eb0ff2601a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8695, "upload_time": "2018-01-31T17:12:55", "url": "https://files.pythonhosted.org/packages/2a/73/f571065f4f5de2948df685fb9e2813fe918ad2f59c7f154916b5a9d8febe/sqlalchemy_fsm-2.0.0.tar.gz" } ], "2.0.1": [ { "comment_text": "", "digests": { "md5": "991976cf5e05e4aca5435f5c97126d15", "sha256": "2f1271b5bfbb7296c22ea44048b7422237919a5682aafd6991633d37c92c887d" }, "downloads": -1, "filename": "sqlalchemy_fsm-2.0.1.tar.gz", "has_sig": false, "md5_digest": "991976cf5e05e4aca5435f5c97126d15", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8700, "upload_time": "2018-01-31T17:36:20", "url": "https://files.pythonhosted.org/packages/7d/04/f34fb52737bf80a8d462a9cd17f60808d82da9f4b2d08076c56d5f38e31b/sqlalchemy_fsm-2.0.1.tar.gz" } ], "2.0.2": [ { "comment_text": "", "digests": { "md5": "b2e5eb0b0f68352fc5de6fc599dd4c19", "sha256": "5a309416c461026ae4428cc049b1893e9cf317101229e3261ddce2862e3b9d13" }, "downloads": -1, "filename": "sqlalchemy_fsm-2.0.2.tar.gz", "has_sig": false, "md5_digest": "b2e5eb0b0f68352fc5de6fc599dd4c19", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8825, "upload_time": "2018-02-15T11:44:57", "url": "https://files.pythonhosted.org/packages/1a/1d/e32ab418c0a586cd5672cf416524312ae83b251eb4f688c35b6029101fe3/sqlalchemy_fsm-2.0.2.tar.gz" } ], "2.0.3": [ { "comment_text": "", "digests": { "md5": "e47e9a06999d9b7591b5e86c2e49ff9d", "sha256": "59473aaebabc0f1e033c407542bbc0a215ffc3049dd57b950896152b1729d197" }, "downloads": -1, "filename": "sqlalchemy_fsm-2.0.3.tar.gz", "has_sig": false, "md5_digest": "e47e9a06999d9b7591b5e86c2e49ff9d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9213, "upload_time": "2018-02-18T10:29:04", "url": "https://files.pythonhosted.org/packages/e6/f0/a94253133f5182da7eae347348c9e4a4997a82c89080ea6f56be713c8a79/sqlalchemy_fsm-2.0.3.tar.gz" } ], "2.0.4": [ { "comment_text": "", "digests": { "md5": "efa9c6af4f60e2ed9d878e8e7ffe1e5e", "sha256": "60685af67728dd1c22fc82b5f0e3d86496cb58904012d570d29c1eb0266925e0" }, "downloads": -1, "filename": "sqlalchemy_fsm-2.0.4.tar.gz", "has_sig": false, "md5_digest": "efa9c6af4f60e2ed9d878e8e7ffe1e5e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9241, "upload_time": "2018-02-21T19:01:01", "url": "https://files.pythonhosted.org/packages/f2/62/72857fbb25f360a0690451ee5444d5407ffa6320e70a21f52299c86d3e41/sqlalchemy_fsm-2.0.4.tar.gz" } ], "2.0.5": [ { "comment_text": "", "digests": { "md5": "c41d1e40b76d46a7a7c547a1ec92eb80", "sha256": "b31389d968def091f3fedf4790812b691b343fbc6c79e998954a3eacba25650e" }, "downloads": -1, "filename": "sqlalchemy_fsm-2.0.5.tar.gz", "has_sig": false, "md5_digest": "c41d1e40b76d46a7a7c547a1ec92eb80", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9706, "upload_time": "2018-02-22T21:57:48", "url": "https://files.pythonhosted.org/packages/34/26/dc359aeceda1ed1e79b27fc0780c7366eea7d0211a18c8d61523a271b0e6/sqlalchemy_fsm-2.0.5.tar.gz" } ], "2.0.6": [ { "comment_text": "", "digests": { "md5": "e80d2596ebdf9f52a93591a606fce1e6", "sha256": "6eccca64038a83fd4f61b445ee74bcf705a613e5041511b69bbded87ea3a5870" }, "downloads": -1, "filename": "sqlalchemy_fsm-2.0.6.tar.gz", "has_sig": false, "md5_digest": "e80d2596ebdf9f52a93591a606fce1e6", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10084, "upload_time": "2018-02-23T12:10:26", "url": "https://files.pythonhosted.org/packages/14/3a/750f8b241f7d9076a823bcdea1dd281826d2ac70314134b4b8f2532de22b/sqlalchemy_fsm-2.0.6.tar.gz" } ], "2.0.7": [ { "comment_text": "", "digests": { "md5": "edeae05fe48ecd29c5080c25a84093c0", "sha256": "747c7b5299db3d5a033e1bc80df964fa17d5dfceb2b2813f4c58b4b535509d7c" }, "downloads": -1, "filename": "sqlalchemy_fsm-2.0.7.tar.gz", "has_sig": false, "md5_digest": "edeae05fe48ecd29c5080c25a84093c0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 12685, "upload_time": "2019-02-13T14:44:55", "url": "https://files.pythonhosted.org/packages/3d/89/2a75637d63167336c412695fedb728b5dc9499a25753676dffb9bed44b65/sqlalchemy_fsm-2.0.7.tar.gz" } ], "2.0.8": [ { "comment_text": "", "digests": { "md5": "ba1bd676614c937088e168cba780a43b", "sha256": "191a5c6129fbcbb6c05d99572f7db704ccc3d8d8e56f702d899821d96df231b0" }, "downloads": -1, "filename": "sqlalchemy_fsm-2.0.8.tar.gz", "has_sig": false, "md5_digest": "ba1bd676614c937088e168cba780a43b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 12683, "upload_time": "2019-02-13T14:53:48", "url": "https://files.pythonhosted.org/packages/9f/9c/a36cbbc1ac5cc14646cc95ec815c5130d1aade6c2017e4a1cc453379552e/sqlalchemy_fsm-2.0.8.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "ba1bd676614c937088e168cba780a43b", "sha256": "191a5c6129fbcbb6c05d99572f7db704ccc3d8d8e56f702d899821d96df231b0" }, "downloads": -1, "filename": "sqlalchemy_fsm-2.0.8.tar.gz", "has_sig": false, "md5_digest": "ba1bd676614c937088e168cba780a43b", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 12683, "upload_time": "2019-02-13T14:53:48", "url": "https://files.pythonhosted.org/packages/9f/9c/a36cbbc1ac5cc14646cc95ec815c5130d1aade6c2017e4a1cc453379552e/sqlalchemy_fsm-2.0.8.tar.gz" } ] }