Metadata-Version: 1.1
Name: app_state
Version: 0.4
Summary: app_state
Home-page: https://github.com/Fak3/app_state
Author: Roman Evstifeev
Author-email: someuniquename@gmail.com
License: MIT
Description: Appstate
        ========
        
        Minimalistic reactive local application state toolkit.
        
        This package provides a way to store application state in a form of
        single-rooted recursive key-value tree, and means to subscribe to the
        changes made to the branches of interest.
        
        Introduction
        ------------
        
        Let’s consider a common application which has a “screen” for user to
        change configuration and another “screen” which allows to perform
        something useful, depending on the current configuration.
        
        If we organize our application into separate “configuration screen”
        module and “main screen” module, we would have to ensure the “main
        screen” reacts accordingly when user changes values on “configuration
        screen”.
        
        Traditional methods to compose the app from the modules together
        includes direct function calling, “callbacks” pattern,
        “signal:raw-latex:`\slot`” pattern and some others. The approach
        provided by this package may be considered as a mix of
        “signal:raw-latex:`\slot`” pattern and “reactive programming”.
        
        To address our app case, we can make configuration screen module write
        any setting to the state:
        
        .. code:: python
        
           from app_state import state
        
           # This should likely happen in 'OK' button click callback, not displayed here.
           state.username = 'value'  
        
        And we let the main screen module to subscribe to the setting by
        decorating a function wich will read changed value from state and update
        main screen display:
        
        .. code:: python
        
           from app_state import state, on
        
           @on('state.username')
           def change_user():
               title.text = 'Hello, ' + state.username
        
        Installation
        ------------
        
        ::
        
           pip install app_state
        
        Usage
        -----
        
        .. code:: python
        
           from app_state import state
        
           state["some_data"] = 42  # Alternatively: state.some_data = 42
        
        State is a recursive dictionary-like object. For covenience, branches
        can also be accessed with ``.`` as attributes.
        
        Listen for state changes
        ~~~~~~~~~~~~~~~~~~~~~~~~
        
        ``@on(*patterns)`` decorator makes the decorated function or method to
        be called each time when the state subtree changes. Each ``pattern`` is
        a dot-separated string, representing state subtree path.
        
        .. code:: python
        
           from app_state import state, on
        
           @on('state.countries')
           def countries():
               print(f'countries changed to: {state.countries}')
               
           @on('state.countries.Australia.population')
           def au_population():
               population = state.get('countries', {}).get('Australia', {}).get('population')
               print(f'Australia population now: {population}')
               
           state.countries = {'Australia': {'code': 'AU'}, 'Brazil': {}}
           state.countries.Australia.population = 4500000
               
        
        will print:
        
        ::
        
           countries changed to: {'Australia': {'code': 'AU'}, 'Brazil': {}}
           Australia population now: None
           countries changed to: {'Australia': {'code': 'AU', 'population': 4500000}, 'Brazil': {}}
           Australia population now: 4500000
        
        ``@on()`` can wrap a method of a class. When state changes, that method
        will be called for every instance of this class.
        
        .. code:: python
        
           from app_state import state, on
        
           class MainWindow:
               @on('state.user')
               def on_user(self):
                   self.settext(f'Welcome, {state.user.name}')
        
           mainwindow = MainWindow()
        
           state.user = {'name': 'Alice'}  # mainwindow.on_user() will be called.
        
        Persistence
        ~~~~~~~~~~~
        
        By default the state is stored in memory. But it is possible to
        automatically store the state to a file when it is changed. Call
        ``state.autopersist('myfile')`` to enable persistence. This function
        will load the state from the file, and turn on automatic storage of the
        state to this file.
        
        If you want to exclude some branches from persistence, then you should
        store them as attributes, starting with underscore:
        
        .. code:: python
        
           # `_temp_peers` will never be stored to a file
           state.countries.Australia._temp_peers = [{'ip': '8.8.8.8'}]
        
        API
        ---
        
        .. code:: python
        
           state.autopersist(filepath, timeout=3, nursery=None)
        
        Enable automatic state persistence, create a shelve with a given
        filepath. If file already exists, read state from it.
        
        ``timeout`` - how many seconds to wait before writing to the file after
        each state change. This parameter helps to reduce frequent writes to
        disk, grouping changes together. Only works when state changes happen in
        a thread with ``asyncio`` or ``trio`` event loop.
        
        ``nursery`` - required if ``trio`` is used.
        
        .. code:: python
        
           class DictNode
        
        ``app_state.state`` and every its subtree is an instance of
        ``DictNode``. Normally you don’t need to use this class explicitly.
        Instance of ``DictNode`` is a dict-like object which emit signal when it
        is changed, so that functions decorated with ``on()`` decorator get
        called appropriately. When you create a dictionary and assign it to any
        state branch, it will be implicitly converted to ``DictNode``:
        
        .. code:: python
        
           from app_state import state, DictNode
           state.countries = {}
           assert isinstance(state.countries, DictNode)  # True
        
        ``as_dict(full=False)``
        
        This method returns regular dictionary, converting ``DictNode`` and all
        subnodes.
        
        If ``full`` is True, then all attributes, starting with underscore will
        also be included in the dictionary as keys.
        
        .. code:: python
        
           state.config = {'name': 'user1'}
           state.config._session_start = '16:35'
           print(state.config.as_dict(full=True))
           # prints {'name': 'user1', '_session_start': '16:35'}
        
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: OS Independent
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: MacOS :: MacOS X
Classifier: Operating System :: Android
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development
Classifier: Topic :: Utilities
