thatway


Namethatway JSON
Version 0.6.0 PyPI version JSON
download
home_page
Summary
upload_time2023-08-09 12:04:56
maintainer
docs_urlNone
authorJustin Lorieau
requires_python>=3.8
license
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            ThatWay
=======
.. image:: https://img.shields.io/pypi/v/thatway.svg
    :target: https://pypi.org/project/thatway/
    :alt: PyPI version

.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
    :target: https://github.com/psf/black
    :alt: Black formatted

Thatway is a simple, decentralized configuration manager.

Place your configuration settings throughout your application--not in a
centralized file or submodule--and thatway collects them and allows you to
modify them through configurations files. Decentralized configuration reduces
the complexity of submodules and the coupling between submodules.

Quickstart
----------

1. Create a package with settings.

`examples/mypkg/moduleA/file.py <examples/mypkg/moduleA/file.py>`_

.. code-block:: python

    from thatway import Setting


    class FirstClass:
        my_attribute = Setting(True, desc="Whether 'my_attribute' is an attribute")

        max_instances = Setting(3, desc="Maximum number of instances")

`examples/mypkg/moduleB/file.py <examples/mypkg/moduleB/file.py>`_

.. code-block:: python

    from thatway import config, Setting

    config.moduleB.msg = Setting("This is my message")

2. View settings:

.. code-block:: python

    import examples.mypkg
    from thatway import config
    print(config.dumps_yaml())
    FirstClass:
      my_attribute: true  # Whether 'my_attribute' is an antribue
      max_instances: 3  # Maximum number of instances
    moduleB:
      msg: This is my message

3. Load different settings:

`examples/mypkg/new_settings.yaml <examples/mypkg/new_settings.yaml>`_

.. code-block:: yaml

    FirstClass:
      my_attribute: false
      max_instances: 2

with python:

.. code-block:: python

    from pathlib import Path
    import examples.mypkg
    from thatway import config
    config.load_yaml(str(Path("examples") / "mypkg" / "new_settings.yaml"))
    print(config.dumps_yaml())
    FirstClass:
      my_attribute: false  # Whether 'my_attribute' is an antribue
      max_instances: 2  # Maximum number of instances
    moduleB:
      msg: This is my message

Rules
-----

The following are design decisions on the behavior of thatway's configuration
manager.

1. Configure directly
~~~~~~~~~~~~~~~~~~~~~

Settings can be set directly on the config object.

.. code-block:: python

    >>> from thatway import config, Setting
    >>> config.a = Setting(3)
    >>> config.a
    3
    >>> config.nested.b = Setting("nested")
    >>> config.nested.b
    'nested'

Trying to set an entry in the config without a setting raises an exception.

.. code-block:: python

    >>> from thatway import config
    >>> config.new_value = 3
    Traceback (most recent call last):
    ...
    thatway.base.ConfigException: Only Settings can be inserted in the Config

2. Configure object attributes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Settings can be set as object attributes.

.. code-block:: python

    >>> from thatway import Setting
    >>> class Obj:
    ...     attribute = Setting("my value")
    >>> obj = Obj()
    >>> obj.attribute
    'my value'

3. Configuration locking
~~~~~~~~~~~~~~~~~~~~~~~~

Settings cannot be accidentally modified. Once they're set, they're set until
the config's ``update`` or ``load`` methods are used.

.. code-block:: python

    >>> from thatway import Setting
    >>> config.b = Setting(3)
    >>> config.b
    3
    >>> config.b = Setting(5)  # oops!
    Traceback (most recent call last):
    ...
    thatway.base.ConfigException: Entry 'b' already in the Config--use a Config.update or load method to change its value.
    >>> config.b = 5  # oops!
    Traceback (most recent call last):
    ...
    thatway.base.ConfigException: Only Settings can be inserted in the Config
    >>> config.update({'b': 5})
    >>> config.b
    5

The one exception is that settings defined on a class can be replaced on the
class itself--not a class instance. This is because settings act as
descriptors for classes.

4. Type Enforcement
~~~~~~~~~~~~~~~~~~~

Setting types are checked and maintained with either the setting's value type,
or the ``allowed_types`` optional argument.

.. code-block:: python

    >>> from thatway import Setting
    >>> config.c = Setting(5, allowed_types=(int, str))
    >>> config.update({'c': 'my new c value'})
    >>> config.c
    'my new c value'
    >>> config.d = Setting(6)
    >>> config.update({'d': 'my new d value'})
    Traceback (most recent call last):
    ...
    ValueError: Could not convert 'my new d value' into any of the following types: [<class 'int'>]

6. Missing Settings
~~~~~~~~~~~~~~~~~~~

Trying to update a setting that doesn't exist is not possible. This behavior
is designed to avoid trying to change a setting but using an incorrect setting
name and location.

.. code-block:: python

    >>> from thatway import Setting
    >>> config.update({'e': 'unassigned'})  # 'f' doesn't exist in config
    Traceback (most recent call last):
    ...
    KeyError: "Tried assigning setting with name 'e' which does not exist in the Config"

7. Immutable Settings Values
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Setting values can only be immutable objects.

.. code-block::

    >>> from thatway import Setting
    >>> config.cli.color = Setting(True)
    >>> config.cli.default_filenames = Setting(('a.html', 'b.html'))
    >>> config.cli.value_list = Setting([1, 2])  # lists are mutable
    Traceback (most recent call last):
    ...
    thatway.base.ConfigException: Setting value '[1, 2]' must be immutable

Features
--------

1. Setting descriptions
~~~~~~~~~~~~~~~~~~~~~~~~~

Settings can include descriptions.

.. code-block:: python

    >>> from thatway import Setting
    >>> config.e = Setting(4, desc="The 'e' attribute")

2. Yaml processing
~~~~~~~~~~~~~~~~~~

Settings can be dumped in `yaml <https://yaml.org>`_.

``config.dumps_yaml()``

.. code-block:: yaml

    Obj:
      a: 1
    b: name  # The 'b' setting
    nested:
      c: true

And `yaml <https://yaml.org>`_ strings or files can be loaded with
``config.loads_yaml(string)`` and ``config.load_yaml(filepath)``, respectively.

3. Toml processing
~~~~~~~~~~~~~~~~~~

Settings can be dumped in `toml <https://toml.io/en/>`_.

``config.dumps_toml()``

.. code-block:: toml

    [Obj]
      a = 1
    b = "name"  # The 'b' setting
    [nested]
      c = true

And `toml <https://toml.io/en/>`_ strings or files can be loaded with
``config.loads_toml(string)`` and ``config.load_toml(filepath)``, respectively.

            

Raw data

            {
    "_id": null,
    "home_page": "",
    "name": "thatway",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": "",
    "keywords": "",
    "author": "Justin Lorieau",
    "author_email": "",
    "download_url": "https://files.pythonhosted.org/packages/59/08/4c0f5f17cf9a6cdb6c68189871f5bf0cc1eacf4d446dae671d29e756c0a5/thatway-0.6.0.tar.gz",
    "platform": null,
    "description": "ThatWay\n=======\n.. image:: https://img.shields.io/pypi/v/thatway.svg\n    :target: https://pypi.org/project/thatway/\n    :alt: PyPI version\n\n.. image:: https://img.shields.io/badge/code%20style-black-000000.svg\n    :target: https://github.com/psf/black\n    :alt: Black formatted\n\nThatway is a simple, decentralized configuration manager.\n\nPlace your configuration settings throughout your application--not in a\ncentralized file or submodule--and thatway collects them and allows you to\nmodify them through configurations files. Decentralized configuration reduces\nthe complexity of submodules and the coupling between submodules.\n\nQuickstart\n----------\n\n1. Create a package with settings.\n\n`examples/mypkg/moduleA/file.py <examples/mypkg/moduleA/file.py>`_\n\n.. code-block:: python\n\n    from thatway import Setting\n\n\n    class FirstClass:\n        my_attribute = Setting(True, desc=\"Whether 'my_attribute' is an attribute\")\n\n        max_instances = Setting(3, desc=\"Maximum number of instances\")\n\n`examples/mypkg/moduleB/file.py <examples/mypkg/moduleB/file.py>`_\n\n.. code-block:: python\n\n    from thatway import config, Setting\n\n    config.moduleB.msg = Setting(\"This is my message\")\n\n2. View settings:\n\n.. code-block:: python\n\n    import examples.mypkg\n    from thatway import config\n    print(config.dumps_yaml())\n    FirstClass:\n      my_attribute: true  # Whether 'my_attribute' is an antribue\n      max_instances: 3  # Maximum number of instances\n    moduleB:\n      msg: This is my message\n\n3. Load different settings:\n\n`examples/mypkg/new_settings.yaml <examples/mypkg/new_settings.yaml>`_\n\n.. code-block:: yaml\n\n    FirstClass:\n      my_attribute: false\n      max_instances: 2\n\nwith python:\n\n.. code-block:: python\n\n    from pathlib import Path\n    import examples.mypkg\n    from thatway import config\n    config.load_yaml(str(Path(\"examples\") / \"mypkg\" / \"new_settings.yaml\"))\n    print(config.dumps_yaml())\n    FirstClass:\n      my_attribute: false  # Whether 'my_attribute' is an antribue\n      max_instances: 2  # Maximum number of instances\n    moduleB:\n      msg: This is my message\n\nRules\n-----\n\nThe following are design decisions on the behavior of thatway's configuration\nmanager.\n\n1. Configure directly\n~~~~~~~~~~~~~~~~~~~~~\n\nSettings can be set directly on the config object.\n\n.. code-block:: python\n\n    >>> from thatway import config, Setting\n    >>> config.a = Setting(3)\n    >>> config.a\n    3\n    >>> config.nested.b = Setting(\"nested\")\n    >>> config.nested.b\n    'nested'\n\nTrying to set an entry in the config without a setting raises an exception.\n\n.. code-block:: python\n\n    >>> from thatway import config\n    >>> config.new_value = 3\n    Traceback (most recent call last):\n    ...\n    thatway.base.ConfigException: Only Settings can be inserted in the Config\n\n2. Configure object attributes\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nSettings can be set as object attributes.\n\n.. code-block:: python\n\n    >>> from thatway import Setting\n    >>> class Obj:\n    ...     attribute = Setting(\"my value\")\n    >>> obj = Obj()\n    >>> obj.attribute\n    'my value'\n\n3. Configuration locking\n~~~~~~~~~~~~~~~~~~~~~~~~\n\nSettings cannot be accidentally modified. Once they're set, they're set until\nthe config's ``update`` or ``load`` methods are used.\n\n.. code-block:: python\n\n    >>> from thatway import Setting\n    >>> config.b = Setting(3)\n    >>> config.b\n    3\n    >>> config.b = Setting(5)  # oops!\n    Traceback (most recent call last):\n    ...\n    thatway.base.ConfigException: Entry 'b' already in the Config--use a Config.update or load method to change its value.\n    >>> config.b = 5  # oops!\n    Traceback (most recent call last):\n    ...\n    thatway.base.ConfigException: Only Settings can be inserted in the Config\n    >>> config.update({'b': 5})\n    >>> config.b\n    5\n\nThe one exception is that settings defined on a class can be replaced on the\nclass itself--not a class instance. This is because settings act as\ndescriptors for classes.\n\n4. Type Enforcement\n~~~~~~~~~~~~~~~~~~~\n\nSetting types are checked and maintained with either the setting's value type,\nor the ``allowed_types`` optional argument.\n\n.. code-block:: python\n\n    >>> from thatway import Setting\n    >>> config.c = Setting(5, allowed_types=(int, str))\n    >>> config.update({'c': 'my new c value'})\n    >>> config.c\n    'my new c value'\n    >>> config.d = Setting(6)\n    >>> config.update({'d': 'my new d value'})\n    Traceback (most recent call last):\n    ...\n    ValueError: Could not convert 'my new d value' into any of the following types: [<class 'int'>]\n\n6. Missing Settings\n~~~~~~~~~~~~~~~~~~~\n\nTrying to update a setting that doesn't exist is not possible. This behavior\nis designed to avoid trying to change a setting but using an incorrect setting\nname and location.\n\n.. code-block:: python\n\n    >>> from thatway import Setting\n    >>> config.update({'e': 'unassigned'})  # 'f' doesn't exist in config\n    Traceback (most recent call last):\n    ...\n    KeyError: \"Tried assigning setting with name 'e' which does not exist in the Config\"\n\n7. Immutable Settings Values\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nSetting values can only be immutable objects.\n\n.. code-block::\n\n    >>> from thatway import Setting\n    >>> config.cli.color = Setting(True)\n    >>> config.cli.default_filenames = Setting(('a.html', 'b.html'))\n    >>> config.cli.value_list = Setting([1, 2])  # lists are mutable\n    Traceback (most recent call last):\n    ...\n    thatway.base.ConfigException: Setting value '[1, 2]' must be immutable\n\nFeatures\n--------\n\n1. Setting descriptions\n~~~~~~~~~~~~~~~~~~~~~~~~~\n\nSettings can include descriptions.\n\n.. code-block:: python\n\n    >>> from thatway import Setting\n    >>> config.e = Setting(4, desc=\"The 'e' attribute\")\n\n2. Yaml processing\n~~~~~~~~~~~~~~~~~~\n\nSettings can be dumped in `yaml <https://yaml.org>`_.\n\n``config.dumps_yaml()``\n\n.. code-block:: yaml\n\n    Obj:\n      a: 1\n    b: name  # The 'b' setting\n    nested:\n      c: true\n\nAnd `yaml <https://yaml.org>`_ strings or files can be loaded with\n``config.loads_yaml(string)`` and ``config.load_yaml(filepath)``, respectively.\n\n3. Toml processing\n~~~~~~~~~~~~~~~~~~\n\nSettings can be dumped in `toml <https://toml.io/en/>`_.\n\n``config.dumps_toml()``\n\n.. code-block:: toml\n\n    [Obj]\n      a = 1\n    b = \"name\"  # The 'b' setting\n    [nested]\n      c = true\n\nAnd `toml <https://toml.io/en/>`_ strings or files can be loaded with\n``config.loads_toml(string)`` and ``config.load_toml(filepath)``, respectively.\n",
    "bugtrack_url": null,
    "license": "",
    "summary": "",
    "version": "0.6.0",
    "project_urls": {
        "Homepage": "https://github.com/jlorieau/thatway"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "b5bb993dab3ae29aa834c6863287da971b7da6071c6a89aae9ba1f8158b39dc7",
                "md5": "9285db2e84007e0ff3a1b5761b8970aa",
                "sha256": "d16403381f802f00eadd96612b8ee8756411d5826c004ae378ac43266ec77ba9"
            },
            "downloads": -1,
            "filename": "thatway-0.6.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "9285db2e84007e0ff3a1b5761b8970aa",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 8089,
            "upload_time": "2023-08-09T12:04:54",
            "upload_time_iso_8601": "2023-08-09T12:04:54.754710Z",
            "url": "https://files.pythonhosted.org/packages/b5/bb/993dab3ae29aa834c6863287da971b7da6071c6a89aae9ba1f8158b39dc7/thatway-0.6.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "59084c0f5f17cf9a6cdb6c68189871f5bf0cc1eacf4d446dae671d29e756c0a5",
                "md5": "04da424929dde8bf592207a906477a0f",
                "sha256": "dbab86a53182cfe0fc71ca0b9c57540a46e4f6670add17e4f5f6db7ec4b6cf58"
            },
            "downloads": -1,
            "filename": "thatway-0.6.0.tar.gz",
            "has_sig": false,
            "md5_digest": "04da424929dde8bf592207a906477a0f",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 11211,
            "upload_time": "2023-08-09T12:04:56",
            "upload_time_iso_8601": "2023-08-09T12:04:56.197772Z",
            "url": "https://files.pythonhosted.org/packages/59/08/4c0f5f17cf9a6cdb6c68189871f5bf0cc1eacf4d446dae671d29e756c0a5/thatway-0.6.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-08-09 12:04:56",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "jlorieau",
    "github_project": "thatway",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "thatway"
}
        
Elapsed time: 0.09667s