Metadata-Version: 2.4
Name: kwconf
Version: 0.10.0
Summary: Typed, dependency-free configuration objects with CLI, environment, and file parsing (a scriptconfig successor).
Author-email: "Kitware Inc." <kitware@kitware.com>, Jon Crall <jon.crall@kitware.com>
License-Expression: Apache-2.0
Project-URL: Homepage, https://github.com/Erotemic/kwconf
Project-URL: Repository, https://github.com/Erotemic/kwconf
Project-URL: Documentation, https://kwconf.readthedocs.io
Project-URL: Issues, https://github.com/Erotemic/kwconf/issues
Keywords: configuration,config,cli,argparse,scriptconfig,yaml
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
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
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Utilities
Classifier: Typing :: Typed
Requires-Python: >=3.10
Description-Content-Type: text/x-rst
License-File: LICENSE
Provides-Extra: all
Requires-Dist: pytest>=8.1.1; (python_version < "4.0" and python_version >= "3.13") and extra == "all"
Requires-Dist: pytest>=8.1.1; (python_version < "3.13" and python_version >= "3.12") and extra == "all"
Requires-Dist: pytest>=8.1.1; (python_version < "3.12" and python_version >= "3.11") and extra == "all"
Requires-Dist: pytest>=6.2.5; (python_version < "3.11" and python_version >= "3.10") and extra == "all"
Requires-Dist: pytest>=6.2.5; (python_version < "3.10" and python_version >= "3.8") and extra == "all"
Requires-Dist: coverage>=6.1.1; python_version >= "3.10" and extra == "all"
Requires-Dist: coverage>=5.3.1; (python_version < "3.10" and python_version >= "3.9") and extra == "all"
Requires-Dist: coverage>=6.1.1; (python_version < "3.9" and python_version >= "3.8") and extra == "all"
Requires-Dist: pytest-cov; extra == "all"
Requires-Dist: xdoctest>=1.1.5; extra == "all"
Requires-Dist: ubelt>=1.3.6; extra == "all"
Requires-Dist: PyYAML>=6.0.1; (python_version < "4.0" and python_version >= "3.12") and extra == "all"
Requires-Dist: PyYAML>=6.0; (python_version < "3.12" and python_version >= "3.11") and extra == "all"
Requires-Dist: PyYAML>=6.0; (python_version < "3.11" and python_version >= "3.10") and extra == "all"
Requires-Dist: numpy>=2.1.0; (python_version < "4.0" and python_version >= "3.13") and extra == "all"
Requires-Dist: numpy>=1.26.0; (python_version < "3.13" and python_version >= "3.12") and extra == "all"
Requires-Dist: numpy>=1.23.2; (python_version < "3.12" and python_version >= "3.11") and extra == "all"
Requires-Dist: numpy>=1.21.6; (python_version < "3.11" and python_version >= "3.10") and extra == "all"
Requires-Dist: numpy>=1.19.3; (python_version < "3.10" and python_version >= "3.9") and extra == "all"
Requires-Dist: numpy>=1.19.2; (python_version < "3.9" and python_version >= "3.8") and extra == "all"
Requires-Dist: numpy>=1.14.5; (python_version < "3.8" and python_version >= "3.7") and extra == "all"
Requires-Dist: numpy>=1.12.0; (python_version < "3.7" and python_version >= "3.6") and extra == "all"
Requires-Dist: numpy>=1.11.1; (python_version < "3.6" and python_version >= "3.5") and extra == "all"
Requires-Dist: numpy>=1.11.1; (python_version < "3.5" and python_version >= "3.4") and extra == "all"
Requires-Dist: numpy>=1.11.1; (python_version < "3.4" and python_version >= "2.7") and extra == "all"
Requires-Dist: rich_argparse>=1.1.0; python_version >= "3.7" and extra == "all"
Requires-Dist: argcomplete>=3.6.3; python_version >= "3.13" and extra == "all"
Requires-Dist: argcomplete>=3.5.2; (python_version < "3.13" and python_version >= "3.12") and extra == "all"
Requires-Dist: argcomplete>=3.3.0; (python_version < "3.12" and python_version >= "3.11") and extra == "all"
Requires-Dist: argcomplete>=3.0.5; (python_version < "3.11" and python_version >= "3.8") and extra == "all"
Requires-Dist: sphinx>=5.0.1; extra == "all"
Requires-Dist: sphinx-autobuild>=2021.3.14; extra == "all"
Requires-Dist: sphinx_rtd_theme>=1.0.0; extra == "all"
Requires-Dist: sphinxcontrib-napoleon>=0.7; extra == "all"
Requires-Dist: sphinx-autoapi>=1.8.4; extra == "all"
Requires-Dist: Pygments>=2.9.0; extra == "all"
Requires-Dist: myst_parser>=0.18.0; extra == "all"
Requires-Dist: sphinx-reredirects>=0.0.1; extra == "all"
Requires-Dist: flake8>=5.0.0; extra == "all"
Requires-Dist: PyYAML>=6.0.1; (python_version < "4.0" and python_version >= "3.12") and extra == "all"
Requires-Dist: PyYAML>=6.0; (python_version < "3.12" and python_version >= "3.11") and extra == "all"
Requires-Dist: PyYAML>=6.0; (python_version < "3.11" and python_version >= "3.10") and extra == "all"
Requires-Dist: PyYAML>=5.4.1; (python_version < "3.10" and python_version >= "3.9") and extra == "all"
Requires-Dist: PyYAML>=5.4.1; (python_version < "3.9" and python_version >= "3.8") and extra == "all"
Requires-Dist: ubelt>=1.3.6; extra == "all"
Provides-Extra: docs
Requires-Dist: sphinx>=5.0.1; extra == "docs"
Requires-Dist: sphinx-autobuild>=2021.3.14; extra == "docs"
Requires-Dist: sphinx_rtd_theme>=1.0.0; extra == "docs"
Requires-Dist: sphinxcontrib-napoleon>=0.7; extra == "docs"
Requires-Dist: sphinx-autoapi>=1.8.4; extra == "docs"
Requires-Dist: Pygments>=2.9.0; extra == "docs"
Requires-Dist: myst_parser>=0.18.0; extra == "docs"
Requires-Dist: sphinx-reredirects>=0.0.1; extra == "docs"
Provides-Extra: linting
Requires-Dist: flake8>=5.0.0; extra == "linting"
Provides-Extra: optional
Requires-Dist: numpy>=2.1.0; (python_version < "4.0" and python_version >= "3.13") and extra == "optional"
Requires-Dist: numpy>=1.26.0; (python_version < "3.13" and python_version >= "3.12") and extra == "optional"
Requires-Dist: numpy>=1.23.2; (python_version < "3.12" and python_version >= "3.11") and extra == "optional"
Requires-Dist: numpy>=1.21.6; (python_version < "3.11" and python_version >= "3.10") and extra == "optional"
Requires-Dist: numpy>=1.19.3; (python_version < "3.10" and python_version >= "3.9") and extra == "optional"
Requires-Dist: numpy>=1.19.2; (python_version < "3.9" and python_version >= "3.8") and extra == "optional"
Requires-Dist: numpy>=1.14.5; (python_version < "3.8" and python_version >= "3.7") and extra == "optional"
Requires-Dist: numpy>=1.12.0; (python_version < "3.7" and python_version >= "3.6") and extra == "optional"
Requires-Dist: numpy>=1.11.1; (python_version < "3.6" and python_version >= "3.5") and extra == "optional"
Requires-Dist: numpy>=1.11.1; (python_version < "3.5" and python_version >= "3.4") and extra == "optional"
Requires-Dist: numpy>=1.11.1; (python_version < "3.4" and python_version >= "2.7") and extra == "optional"
Requires-Dist: rich_argparse>=1.1.0; python_version >= "3.7" and extra == "optional"
Requires-Dist: argcomplete>=3.6.3; python_version >= "3.13" and extra == "optional"
Requires-Dist: argcomplete>=3.5.2; (python_version < "3.13" and python_version >= "3.12") and extra == "optional"
Requires-Dist: argcomplete>=3.3.0; (python_version < "3.12" and python_version >= "3.11") and extra == "optional"
Requires-Dist: argcomplete>=3.0.5; (python_version < "3.11" and python_version >= "3.8") and extra == "optional"
Provides-Extra: tests
Requires-Dist: pytest>=8.1.1; (python_version < "4.0" and python_version >= "3.13") and extra == "tests"
Requires-Dist: pytest>=8.1.1; (python_version < "3.13" and python_version >= "3.12") and extra == "tests"
Requires-Dist: pytest>=8.1.1; (python_version < "3.12" and python_version >= "3.11") and extra == "tests"
Requires-Dist: pytest>=6.2.5; (python_version < "3.11" and python_version >= "3.10") and extra == "tests"
Requires-Dist: pytest>=6.2.5; (python_version < "3.10" and python_version >= "3.8") and extra == "tests"
Requires-Dist: coverage>=6.1.1; python_version >= "3.10" and extra == "tests"
Requires-Dist: coverage>=5.3.1; (python_version < "3.10" and python_version >= "3.9") and extra == "tests"
Requires-Dist: coverage>=6.1.1; (python_version < "3.9" and python_version >= "3.8") and extra == "tests"
Requires-Dist: pytest-cov; extra == "tests"
Requires-Dist: xdoctest>=1.1.5; extra == "tests"
Requires-Dist: ubelt>=1.3.6; extra == "tests"
Requires-Dist: PyYAML>=6.0.1; (python_version < "4.0" and python_version >= "3.12") and extra == "tests"
Requires-Dist: PyYAML>=6.0; (python_version < "3.12" and python_version >= "3.11") and extra == "tests"
Requires-Dist: PyYAML>=6.0; (python_version < "3.11" and python_version >= "3.10") and extra == "tests"
Provides-Extra: ubelt
Requires-Dist: ubelt>=1.3.6; extra == "ubelt"
Provides-Extra: yaml
Requires-Dist: PyYAML>=6.0.1; (python_version < "4.0" and python_version >= "3.12") and extra == "yaml"
Requires-Dist: PyYAML>=6.0; (python_version < "3.12" and python_version >= "3.11") and extra == "yaml"
Requires-Dist: PyYAML>=6.0; (python_version < "3.11" and python_version >= "3.10") and extra == "yaml"
Requires-Dist: PyYAML>=5.4.1; (python_version < "3.10" and python_version >= "3.9") and extra == "yaml"
Requires-Dist: PyYAML>=5.4.1; (python_version < "3.9" and python_version >= "3.8") and extra == "yaml"
Dynamic: license-file

The kwconf Module
=================

|Pypi| |PypiDownloads| |ReadTheDocs| |GithubActions| |Codecov| |GitlabCIPipeline| |GitlabCICoverage|

``kwconf`` provides typed, dependency-free configuration objects that parse
**consistently** from Python keyword arguments, the command line, the
environment, and config files. It is a successor to
`scriptconfig <https://pypi.org/project/scriptconfig>`_, keeping the useful
ergonomics while dropping the footguns (most notably, comma-strings no longer
silently split into lists).

+-----------------+-----------------------------------------+
| Read the Docs   | http://kwconf.readthedocs.io/en/latest/ |
+-----------------+-----------------------------------------+
| Github          | https://github.com/Erotemic/kwconf      |
+-----------------+-----------------------------------------+
| Pypi            | https://pypi.org/project/kwconf         |
+-----------------+-----------------------------------------+


Features
--------

* **One model, many inputs.** CLI, kwargs, env, and files map onto the same
  field model.
* **Trust at the Python boundary, parse at the text boundary.** ``Config(x='1')``
  keeps ``'1'``; ``--x=1`` parses it. Defaults are WYSIWYG.
* **Progressive typing.** Stays simple untyped; add annotations to harden.
  ``Value`` / ``Flag`` are typed so ``x: int = Value(None)`` is a *static* error
  on ty, mypy, and pyright. Ships ``py.typed``.
* **Zero required dependencies.** YAML and the ubelt-backed niceties are optional
  extras.
* Modal subcommand CLIs, nested configs with dotted overrides, argparse
  round-tripping, and YAML/JSON load/dump.


Installation
------------

.. code-block:: bash

    pip install kwconf

    # optional extras
    pip install kwconf[yaml]    # YAML config load/dump and parser='yaml'
    pip install kwconf[ubelt]   # rich repr, Config.__json__, port_to_argparse


Quickstart
----------

.. code-block:: python

    import kwconf as kw

    class DemoConfig(kw.Config):
        count: int = 1
        mode: str = kw.Value('fast', choices=['fast', 'safe'])
        tags: list[str] = kw.Value(default_factory=list, nargs='+')

    cfg = DemoConfig.cli(argv=['--count=3', '--mode=safe', '--tags', 'a', 'b'])
    assert cfg.count == 3
    assert cfg.mode == 'safe'
    assert cfg.tags == ['a', 'b']

See the `documentation <http://kwconf.readthedocs.io/en/latest/>`_ for the
coercion model, nested configs, modal CLIs, and a scriptconfig migration guide.


.. |Pypi| image:: https://img.shields.io/pypi/v/kwconf.svg
    :target: https://pypi.python.org/pypi/kwconf

.. |PypiDownloads| image:: https://img.shields.io/pypi/dm/kwconf.svg
    :target: https://pypistats.org/packages/kwconf

.. |ReadTheDocs| image:: https://readthedocs.org/projects/kwconf/badge/?version=latest
    :target: http://kwconf.readthedocs.io/en/latest/

.. |GithubActions| image:: https://github.com/Erotemic/kwconf/actions/workflows/tests.yml/badge.svg
    :target: https://github.com/Erotemic/kwconf/actions?query=branch%3Amain

.. |Codecov| image:: https://codecov.io/github/Erotemic/kwconf/badge.svg?branch=main&service=github
    :target: https://codecov.io/github/Erotemic/kwconf?branch=main

.. |GitlabCIPipeline| image:: https://gitlab.kitware.com/Erotemic/kwconf/badges/main/pipeline.svg
    :target: https://gitlab.kitware.com/Erotemic/kwconf/-/jobs

.. |GitlabCICoverage| image:: https://gitlab.kitware.com/Erotemic/kwconf/badges/main/coverage.svg
    :target: https://gitlab.kitware.com/Erotemic/kwconf/commits/main
