Skip to main content

configuration with click builder

Project description

Cock

Github actions status for master branch Codecov coverage for master branch Pypi version Pypi downloads count

Cock stands for «configuration file with click». It is a configuration aggregator, which stands on shiny click library.

Reason

No module for click with flat configuration file, which will mimic actual click options. There are click-config and click-config-file, but they targets another goals.

Features

  • Aggregate configuration file and cli options into flat configuration object.
  • Respect all click checks and conversions (required attribute forbidden, since it breaks internal logic).
  • dict-like, flat, sorted, dot-accessed configuration object.
  • Entrypoint builder.

License

cock is offered under MIT license.

Requirements

  • python 3.7+

Usage

from cock import build_entrypoint, Config, Option


def main(config: Config):
    print(config)


options = [
    Option("a_b_c", default="foo"),
    Option("b_c_d", default="bar"),
]
entrypoint = build_entrypoint(main, options, auto_envvar_prefix="EXAMPLE", show_default=True)

if __name__ == "__main__":
    entrypoint(prog_name="example")

This is almost pure click setup:

$ python example.py --help
Usage: example [OPTIONS] [CONFIGURATION_FILE]

Options:
  --a-b-c TEXT  [default: foo]
  --b-c-d TEXT  [default: bar]
  --help        Show this message and exit.  [default: False]

But there is a CONFIGURATION_FILE argument. Lets see use cases.

All deafults

$ python example.py
{'configuration_file': None, 'a_b_c': 'foo', 'b_c_d': 'bar'}

From environment variable

$ EXAMPLE_A_B_C=foo-env python example.py
{'configuration_file': None, 'a_b_c': 'foo-env', 'b_c_d': 'bar'}

From cli arguments

$ EXAMPLE_A_B_C=foo-env python example.py --a-b-c foo-cli
{'a_b_c': 'foo-cli', 'configuration_file': None, 'b_c_d': 'bar'}

From configuration yaml file

a-b-c: foo-file
$ EXAMPLE_A_B_C=foo-env python example.py --a-b-c foo-cli config-example.yml
{'a_b_c': 'foo-file', 'configuration_file': '/absolute/path/to/config-example.yml', 'b_c_d': 'bar'}

Priority is obvious: file > cli arguments > env variables

Note: for file a-b-c is the same as a_b_c or a-b_c. Use whatever you prefer.

As described in features paragraph, configuration is flattened before chaining with click options. So all configuration files listed below are equal:

a_b_c: foo-file
a:
  b:
    c: foo-file
a-b:
  c: foo-file

If provided file have key crossings:

a-b_c: foo-file1
a:
  b-c: foo-file2

Then RuntimeError will be raised.

cock uses pyyaml library for config loading, so it supports yaml and json formats, but this can be improved later if someone will need more configuration file types.

Configuration can be defined as dictionary too:

from cock import build_entrypoint, Option, Config


def main(config: Config):
    print(config)


options = {
    "a": {
        "b": {
            "c": Option(default="foo"),
        },
    },
    "a-b_d": Option(default="bar"),
}
entrypoint = build_entrypoint(main, options, auto_envvar_prefix="EXAMPLE", show_default=True)

if __name__ == "__main__":
    entrypoint(prog_name="example")

Note: for dictionaries you can use same rules in naming and structure as for files.

Configuration can be defined as multiple sources:

from cock import build_entrypoint, Option, Config


def main(config: Config):
    print(config)


dict_options = {"a-b-c": Option(default="foo")}
list_options = [Option("b_c-d", default="bar")]
entrypoint = build_entrypoint(main, dict_options, list_options,
                              auto_envvar_prefix="EXAMPLE", show_default=True)

if __name__ == "__main__":
    entrypoint(prog_name="example")

You can also gather all defaults from options as a Config:

from cock import get_options_defaults, Option

options = {
    "a": {
        "b": {
            "c": Option(default="foo"),
        },
    },
}
config = get_options_defaults(options)
assert config == {"a_b_c": "foo"}
assert config.a_b_c == "foo"

Config is an extended (with dot-access) version of sortedcontainers.SortedDict:

>>> from cock import Config
>>> c = Config(b=1, a=2)
Config({'a': 2, 'b': 1})
>>> c["a"], c.b
(2, 1)
>>> c.z
...
KeyError: 'z'
>>> c.items()
SortedItemsView(Config({'a': 2, 'b': 1}))
>>> c["0"] = 0
>>> c
Config({'0': 0, 'a': 2, 'b': 1})

API

def build_entrypoint(
    main: Callable[[Config], Any],
    *options_stack: Union[dict, List[Union[Option, click.option]]],
    **context_settings
) -> Callable[..., Any]:
  • main is a user-space function of exactly one argument, a dot-accessed config wrapper.
  • *options_stack is a sequence of dicts and/or lists described above.
  • **context_settings propagated to click.command decorator.
def get_options_defaults(
    *options_stack: Union[dict, List[Union[Option, click.option]]]
) -> Config:
  • *options_stack is a sequence of dicts and/or lists described above.
class Option(
    name: Optional[str] = None,
    **attributes)
  • name is a name in resulting Config object, which passed to main.
    • name can be set only once, further set will lead to exception.
    • name field will be converted to «underscore» view (e.g. a-b_c internaly will be converted to a_b_c).
  • **attributes propagated to click.option decorator.
    • required attribute forbidden, since it breaks internal logic.

Deprecations and removals

0.11.0

Deprecations:

  • Usage of click.option as option.
  • build_options_from_dict function, since it is obsolete with new api.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cock-0.11.0.tar.gz (5.6 kB view details)

Uploaded Source

Built Distribution

cock-0.11.0-py3-none-any.whl (5.9 kB view details)

Uploaded Python 3

File details

Details for the file cock-0.11.0.tar.gz.

File metadata

  • Download URL: cock-0.11.0.tar.gz
  • Upload date:
  • Size: 5.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.10.7

File hashes

Hashes for cock-0.11.0.tar.gz
Algorithm Hash digest
SHA256 1e2f1a171013b187043baa8dcd99c5ef757c58b4d08dbe83c36c45e15813da8e
MD5 1139beaf0b4bc816cf2deea18b9681bf
BLAKE2b-256 a19e319ae8aa6101ba8c5f5f7d0af9828070719d151e1eadb02a47c16f143b5d

See more details on using hashes here.

File details

Details for the file cock-0.11.0-py3-none-any.whl.

File metadata

  • Download URL: cock-0.11.0-py3-none-any.whl
  • Upload date:
  • Size: 5.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.10.7

File hashes

Hashes for cock-0.11.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d983fdea27556c66e17154ca883e7b3ca2af2d0058fc07b9fea3bb66ba9c3363
MD5 70dfb2ef27e9df28195aedab1783f202
BLAKE2b-256 ebccc9147eaa8c2083c37a54e9455b838a5933671ab723a2c02488b575a537df

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page