Metadata-Version: 2.5
Name: s3ttings
Version: 0.0.7
Summary: Lightweight settings library
Author-email: Quentin Bouget <ypsah@devyard.org>
License: MIT
License-File: LICENSE
Keywords: configuration
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Python: >=3.10
Requires-Dist: simple-git-versioning>=0.3.7
Requires-Dist: typing-extensions; python_version < '3.11'
Description-Content-Type: text/x-rst

Settings
========

A basic library to manage collections of knobs and toggles

============
Installation
============

.. code:: bash

    pip install s3ttings

=====
Usage
=====

``Setting``
-----------

.. code:: python
   :number-lines:

    import asyncio
    from settings import Setting

    timeout = Setting(f"{__name__}.io.timeout", default=5)

    async def main():
        with asyncio.timeout(timeout.value):
            await long_running_task()

Settings can be tweaked:

.. code:: python
   :number-lines:

    from settings import Setting

    timeout = Setting(f"{__name__}.io.timeout", default=5)

    if __name__ == "__main__":
        assert timeout.value == 5

        timeout.value = 3
        assert timeout.value = 3

        with timeout(10):
            assert timeout.value == 10
        assert timeout.value == 3

        del timeout.value
        assert timeout.value == 5

        timeout.default = 6
        assert timeout.value == 6

        del timeout.default
        timeout.value  # raises `settings.NoDefaultValueError(timeout)`

They can transparently use other settings as their default:

.. code:: python
   :number-lines:

    from settings import Setting

    timeout = Setting(f"{__name__}.io.timeout", default=5)
    load_timeout = Setting(f"{__name__}.io.load.timeout", default=timeout)
    dump_timeout = Setting(f"{__name__}.io.dump.timeout", default=timeout)

    if __name__ == "__main__":
        assert load_timeout.value == dump_timeout.value == timeout.value == 5

Finally, ``Setting`` implements the multiton_ pattern:

.. code:: python
   :number-lines:

    from settings import Setting

    timeout = Setting(f"{__name__}.io.timeout", default=5)

    if __name__ == "__main__":
        assert Setting(f"{__name__}.io.timeout") is timeout

.. _multiton: https://en.wikipedia.org/wiki/Multiton_pattern

``SettingTree``
---------------

Collections of settings can be grouped in setting trees:

.. code:: python
   :number-lines:

    from settings import Setting, SettingTree

    options = SettingTree(
        Setting(f"{__name__}.io.timeout", default=5),
        Setting(
            f"{__name__}.io.load.timeout", default=Setting(f"{__name__}.io.timeout")
        ),
        Setting(
            f"{__name__}.io.dump.timeout", default=Setting(f"{__name__}.io.timeout")
        ),
        prefix=__name__,
    )

    if __name__ == "__main__":
        assert options.io.timeout.value == 5

For large projects with many settings, a common practice is to define multiple trees
and merge them together in the top-level module:

.. code:: python
   :number-lines:

    from settings import SettingTree

    from .a import options as _options_a
    from .b import options as _options_b

    options = SettingTree(*_options_a, *_options_b, prefix=__name__)

``EnvSetting``
--------------

A subclass of ``Setting``, ``EnvSetting`` can source default values from environment
variables:

.. code:: python
   :number-lines:

    import os
    from settings import EnvSetting

    timeout = EnvSetting("my.project.io.timeout", default=5, envparse=int)

    if __name__ == "__main__":
        assert timeout.value == 5

        os.environ["my.project.io.timeout"] = "10"
        assert timeout.value == 10
