{ "info": { "author": "Roman Evstifeev", "author_email": "someuniquename@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: Android", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows", "Operating System :: OS Independent", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3", "Topic :: Software Development", "Topic :: Utilities" ], "description": "Appstate\n========\n\nMinimalistic reactive local application state toolkit.\n\nThis package provides a way to store application state in a form of\nsingle-rooted recursive key-value tree, and means to subscribe to the\nchanges made to the branches of interest.\n\nIntroduction\n------------\n\nLet\u2019s consider a common application which has a \u201cscreen\u201d for user to\nchange configuration and another \u201cscreen\u201d which allows to perform\nsomething useful, depending on the current configuration.\n\nIf we organize our application into separate \u201cconfiguration screen\u201d\nmodule and \u201cmain screen\u201d module, we would have to ensure the \u201cmain\nscreen\u201d reacts accordingly when user changes values on \u201cconfiguration\nscreen\u201d.\n\nTraditional methods to compose the app from the modules together\nincludes direct function calling, \u201ccallbacks\u201d pattern,\n\u201csignal:raw-latex:`\\slot`\u201d pattern and some others. The approach\nprovided by this package may be considered as a mix of\n\u201csignal:raw-latex:`\\slot`\u201d pattern and \u201creactive programming\u201d.\n\nTo address our app case, we can make configuration screen module write\nany setting to the state:\n\n.. code:: python\n\n from app_state import state\n\n # This should likely happen in 'OK' button click callback, not displayed here.\n state.username = 'value' \n\nAnd we let the main screen module to subscribe to the setting by\ndecorating a function wich will read changed value from state and update\nmain screen display:\n\n.. code:: python\n\n from app_state import state, on\n\n @on('state.username')\n def change_user():\n title.text = 'Hello, ' + state.username\n\nInstallation\n------------\n\n::\n\n pip install app_state\n\nUsage\n-----\n\n.. code:: python\n\n from app_state import state\n\n state[\"some_data\"] = 42 # Alternatively: state.some_data = 42\n\nState is a recursive dictionary-like object. For covenience, branches\ncan also be accessed with ``.`` as attributes.\n\nListen for state changes\n~~~~~~~~~~~~~~~~~~~~~~~~\n\n``@on(*patterns)`` decorator makes the decorated function or method to\nbe called each time when the state subtree changes. Each ``pattern`` is\na dot-separated string, representing state subtree path.\n\n.. code:: python\n\n from app_state import state, on\n\n @on('state.countries')\n def countries():\n print(f'countries changed to: {state.countries}')\n\n @on('state.countries.Australia.population')\n def au_population():\n population = state.get('countries', {}).get('Australia', {}).get('population')\n print(f'Australia population now: {population}')\n\n state.countries = {'Australia': {'code': 'AU'}, 'Brazil': {}}\n state.countries.Australia.population = 4500000\n\n\nwill print:\n\n::\n\n countries changed to: {'Australia': {'code': 'AU'}, 'Brazil': {}}\n Australia population now: None\n countries changed to: {'Australia': {'code': 'AU', 'population': 4500000}, 'Brazil': {}}\n Australia population now: 4500000\n\n``@on()`` can wrap a method of a class. When state changes, that method\nwill be called for every instance of this class.\n\n.. code:: python\n\n from app_state import state, on\n\n class MainWindow:\n @on('state.user')\n def on_user(self):\n self.settext(f'Welcome, {state.user.name}')\n\n mainwindow = MainWindow()\n\n state.user = {'name': 'Alice'} # mainwindow.on_user() will be called.\n\nPersistence\n~~~~~~~~~~~\n\nBy default the state is stored in memory. But it is possible to\nautomatically store the state to a file when it is changed. Call\n``state.autopersist('myfile')`` to enable persistence. This function\nwill load the state from the file, and turn on automatic storage of the\nstate to this file.\n\nIf you want to exclude some branches from persistence, then you should\nstore them as attributes, starting with underscore:\n\n.. code:: python\n\n # `_temp_peers` will never be stored to a file\n state.countries.Australia._temp_peers = [{'ip': '8.8.8.8'}]\n\nAPI\n---\n\n.. code:: python\n\n state.autopersist(filepath, timeout=3, nursery=None)\n\nEnable automatic state persistence, create a shelve with a given\nfilepath. If file already exists, read state from it.\n\n``timeout`` - how many seconds to wait before writing to the file after\neach state change. This parameter helps to reduce frequent writes to\ndisk, grouping changes together. Only works when state changes happen in\na thread with ``asyncio`` or ``trio`` event loop.\n\n``nursery`` - required if ``trio`` is used.\n\n.. code:: python\n\n class DictNode\n\n``app_state.state`` and every its subtree is an instance of\n``DictNode``. Normally you don\u2019t need to use this class explicitly.\nInstance of ``DictNode`` is a dict-like object which emit signal when it\nis changed, so that functions decorated with ``on()`` decorator get\ncalled appropriately. When you create a dictionary and assign it to any\nstate branch, it will be implicitly converted to ``DictNode``:\n\n.. code:: python\n\n from app_state import state, DictNode\n state.countries = {}\n assert isinstance(state.countries, DictNode) # True\n\n``as_dict(full=False)``\n\nThis method returns regular dictionary, converting ``DictNode`` and all\nsubnodes.\n\nIf ``full`` is True, then all attributes, starting with underscore will\nalso be included in the dictionary as keys.\n\n.. code:: python\n\n state.config = {'name': 'user1'}\n state.config._session_start = '16:35'\n print(state.config.as_dict(full=True))\n # prints {'name': 'user1', '_session_start': '16:35'}\n\n\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/Fak3/app_state", "keywords": "", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "app-state", "package_url": "https://pypi.org/project/app-state/", "platform": "", "project_url": "https://pypi.org/project/app-state/", "project_urls": { "Homepage": "https://github.com/Fak3/app_state" }, "release_url": "https://pypi.org/project/app-state/0.5/", "requires_dist": [ "getinstance", "sniffio", "lockorator" ], "requires_python": "", "summary": "app_state", "version": "0.5" }, "last_serial": 5656945, "releases": { "0.1": [ { "comment_text": "", "digests": { "md5": "d3490e95c572cc41eea5a168688cca37", "sha256": "a1fd2f11a02d6da965b38af13fc7b23241e13e7a83d27aae8733d55ce5ff9af1" }, "downloads": -1, "filename": "app_state-0.1-py3-none-any.whl", "has_sig": false, "md5_digest": "d3490e95c572cc41eea5a168688cca37", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 4180, "upload_time": "2018-10-17T05:47:14", "url": "https://files.pythonhosted.org/packages/f9/68/27a61e6585be42c45a1ec9de512ec858466a3198330f28e97510c716f284/app_state-0.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "abc3db289a98ee66d8b1828165f8ca99", "sha256": "cdb3ed4dc9f52857409da252d762232d02cbb6e794dacf38fb06ba3e1f63a46e" }, "downloads": -1, "filename": "app_state-0.1.tar.gz", "has_sig": false, "md5_digest": "abc3db289a98ee66d8b1828165f8ca99", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 2987, "upload_time": "2018-10-17T05:47:16", "url": "https://files.pythonhosted.org/packages/e2/36/e7050d95597948780b04ef062ac1102fb316162d1f064f63ba3dc7959119/app_state-0.1.tar.gz" } ], "0.2": [ { "comment_text": "", "digests": { "md5": "dbd9c7b2dce1a8b0104cb945b5bb0589", "sha256": "b9a668101760ff1dc77cd7f51c5fc231b9fbc62c4d649e7289b72216b407e2b7" }, "downloads": -1, "filename": "app_state-0.2-py3-none-any.whl", "has_sig": false, "md5_digest": "dbd9c7b2dce1a8b0104cb945b5bb0589", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 5697, "upload_time": "2019-03-25T17:41:40", "url": "https://files.pythonhosted.org/packages/d4/4d/4256a2aea1a545e8c2d21d55600ac365c1d7190623e9e309de39642fc827/app_state-0.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "17a18171fd7227895b292b314209b863", "sha256": "b028d93a7cfe8a5faca1ef921ca49b25ffd5e6877fb4861800fbfa03d558e96c" }, "downloads": -1, "filename": "app_state-0.2.tar.gz", "has_sig": false, "md5_digest": "17a18171fd7227895b292b314209b863", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4768, "upload_time": "2019-03-25T17:41:42", "url": "https://files.pythonhosted.org/packages/72/b7/f10373c1b4cb2270a7fa7d37470703f0b17414dcea09d1a599ef8082225c/app_state-0.2.tar.gz" } ], "0.3": [ { "comment_text": "", "digests": { "md5": "a4fe02d11d4e3c222bb3079836f7e85c", "sha256": "6e87580e299129b00cb2c8f12ff883453227d38bb5117d4190b6cdda0f80b381" }, "downloads": -1, "filename": "app_state-0.3-py3-none-any.whl", "has_sig": false, "md5_digest": "a4fe02d11d4e3c222bb3079836f7e85c", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 6338, "upload_time": "2019-04-03T18:36:17", "url": "https://files.pythonhosted.org/packages/e1/fa/ac51eb6b8940140b435e6213ea658ecd2364246c2b42b2775cb3f177dde0/app_state-0.3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "72a5b350b915d98dcc56d0044c9feb8f", "sha256": "b63bcad68fc13930c54c423358dd32fc2f49113324326b3037ee2bb531ab6595" }, "downloads": -1, "filename": "app_state-0.3.tar.gz", "has_sig": false, "md5_digest": "72a5b350b915d98dcc56d0044c9feb8f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5597, "upload_time": "2019-04-03T18:36:18", "url": "https://files.pythonhosted.org/packages/2e/ab/79d57980b992cb6b27fa67c9fabcedf99557f8f4665c487d85a88978eddb/app_state-0.3.tar.gz" } ], "0.4": [ { "comment_text": "", "digests": { "md5": "29d27494e232db3e665ead6595c53102", "sha256": "6f7d43ad2798ef5c32d07e5a93ff0f3568281ccc9cb982fc2bbdaaa065e71632" }, "downloads": -1, "filename": "app_state-0.4-py3-none-any.whl", "has_sig": false, "md5_digest": "29d27494e232db3e665ead6595c53102", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 6448, "upload_time": "2019-04-25T13:52:38", "url": "https://files.pythonhosted.org/packages/81/41/bcbefed4f34314d2334f68c5ef1f76e6dc9c2686b8ea2fd63259727c5c98/app_state-0.4-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "8befe802d9ae003aad97383a6d9a5f6a", "sha256": "d74a538df89657dc9e005f997b84ad94aa55c41d93488fc8e921aab3b0ba1830" }, "downloads": -1, "filename": "app_state-0.4.tar.gz", "has_sig": false, "md5_digest": "8befe802d9ae003aad97383a6d9a5f6a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5695, "upload_time": "2019-04-25T13:52:40", "url": "https://files.pythonhosted.org/packages/90/be/07f8c036302ee85611c7834b192c0075e6481f4e555b5f2c2c2cfefb87a0/app_state-0.4.tar.gz" } ], "0.5": [ { "comment_text": "", "digests": { "md5": "7e085e83f5e00c97c8f15618fc443fd0", "sha256": "239dcd8912356eaa43ccf856eec35eeff240f4708c8ad4b9154a3b90a8fd4b01" }, "downloads": -1, "filename": "app_state-0.5-py3-none-any.whl", "has_sig": false, "md5_digest": "7e085e83f5e00c97c8f15618fc443fd0", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 6718, "upload_time": "2019-08-09T17:34:44", "url": "https://files.pythonhosted.org/packages/65/ed/624dffddae175a414f3c8774b90a8347ace68ebf7669857de60395e067a4/app_state-0.5-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "102833e1ca18525390c6d55c21e096df", "sha256": "340058e07f655e0ce77366e2843b8b1acdcf291b544924433c500300aaa44714" }, "downloads": -1, "filename": "app_state-0.5.tar.gz", "has_sig": false, "md5_digest": "102833e1ca18525390c6d55c21e096df", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5985, "upload_time": "2019-08-09T17:34:46", "url": "https://files.pythonhosted.org/packages/e4/cb/fd2ab25819a3edab79223e609cc25d7d901160bc16a26df50a5dc8aeac96/app_state-0.5.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "7e085e83f5e00c97c8f15618fc443fd0", "sha256": "239dcd8912356eaa43ccf856eec35eeff240f4708c8ad4b9154a3b90a8fd4b01" }, "downloads": -1, "filename": "app_state-0.5-py3-none-any.whl", "has_sig": false, "md5_digest": "7e085e83f5e00c97c8f15618fc443fd0", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 6718, "upload_time": "2019-08-09T17:34:44", "url": "https://files.pythonhosted.org/packages/65/ed/624dffddae175a414f3c8774b90a8347ace68ebf7669857de60395e067a4/app_state-0.5-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "102833e1ca18525390c6d55c21e096df", "sha256": "340058e07f655e0ce77366e2843b8b1acdcf291b544924433c500300aaa44714" }, "downloads": -1, "filename": "app_state-0.5.tar.gz", "has_sig": false, "md5_digest": "102833e1ca18525390c6d55c21e096df", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5985, "upload_time": "2019-08-09T17:34:46", "url": "https://files.pythonhosted.org/packages/e4/cb/fd2ab25819a3edab79223e609cc25d7d901160bc16a26df50a5dc8aeac96/app_state-0.5.tar.gz" } ] }