diff --git a/.flake8 b/.flake8 deleted file mode 100644 index 0bedae4..0000000 --- a/.flake8 +++ /dev/null @@ -1,3 +0,0 @@ -[flake8] -ignore = E501, E203, W503 -import-order-style = google diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..ec249ec --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,10 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: monthly + - package-ecosystem: pip + directory: / + schedule: + interval: monthly diff --git a/.github/workflows/pr-title-check.yaml b/.github/workflows/pr-title-check.yaml index e2121a2..503388a 100644 --- a/.github/workflows/pr-title-check.yaml +++ b/.github/workflows/pr-title-check.yaml @@ -12,7 +12,7 @@ jobs: name: Validate PR title runs-on: ubuntu-latest steps: - - uses: amannn/action-semantic-pull-request@v4 + - uses: amannn/action-semantic-pull-request@v5 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: diff --git a/.github/workflows/test-release.yaml b/.github/workflows/test-release.yaml index 29bcd54..aa0072b 100644 --- a/.github/workflows/test-release.yaml +++ b/.github/workflows/test-release.yaml @@ -10,9 +10,9 @@ jobs: test-release: uses: zifeo/workflows/.github/workflows/py-test-release.yml@main with: - python-matrix: '["3.8", "3.9", "3.10"]' - poetry-version: "1.1.12" - python-version: "3.10" + python-matrix: '["3.8", "3.9", "3.10", "3.11"]' + poetry-version: "1.3.2" + python-version: "3.11" publish-pypi: true secrets: pypi-token: ${{ secrets.PYPI_TOKEN }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 130470c..d986627 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,18 +1,14 @@ repos: -- repo: https://github.com/sqlalchemyorg/zimports/ - rev: v0.6.0 - hooks: - - id: zimports -- repo: https://github.com/psf/black - rev: 22.3.0 - hooks: - - id: black -- repo: https://gitlab.com/pycqa/flake8 - rev: 3.9.2 - hooks: - - id: flake8 -- repo: https://github.com/commitizen-tools/commitizen - rev: v2.27.1 - hooks: - - id: commitizen - stages: [commit-msg] + - repo: https://github.com/charliermarsh/ruff-pre-commit + rev: "v0.0.291" + hooks: + - id: ruff + - repo: https://github.com/psf/black + rev: 23.9.1 + hooks: + - id: black + - repo: https://github.com/commitizen-tools/commitizen + rev: 3.9.1 + hooks: + - id: commitizen + stages: [commit-msg] diff --git a/CHANGELOG.md b/CHANGELOG.md index d170b48..a01433b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,54 @@ +## v2.2.2 (2023-09-24) + +### Fix + +- union alternative syntax #112 (#113) + +## v2.2.1 (2023-05-26) + +### Fix + +- for issue with nested dataclasses that have default values #98 + +## v2.2.0 (2023-05-23) + +### Feat + +- support StrEnum from python 3.11 (#91) +- add support fro string enum (#88) +- dependabot (#69) +- upgrade deps and switch to ruff (#68) + +### Fix + +- union and yaml loader fixes (#92) +- license + +## v2.1.3 (2022-12-05) + +### Fix + +- typing for dict, close #64 (#65) + +## v2.1.2 (2022-10-22) + +### Fix + +- readme +- remote loading error, close #57 + +## v2.1.1 (2022-09-16) + +### Fix + +- dumps close #54 (#55) + +## v2.1.0 (2022-07-31) + +### Feat + +- add yaml source support (#51) + ## v2.0.0 (2022-06-28) ### Feat diff --git a/README.md b/README.md index 897a6b4..790ac0c 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,8 @@ [![Actions Status](https://github.com/zifeo/dataconf/workflows/CI/badge.svg)](https://github.com/zifeo/dataconf/actions) [![PyPI version](https://badge.fury.io/py/dataconf.svg)](https://badge.fury.io/py/dataconf) -Simple dataclasses configuration management for Python with hocon/json/yaml/properties/env-vars/dict/cli support, based on awesome and lightweight [pyhocon](https://github.com/chimpler/pyhocon) parsing library. +Simple dataclasses configuration management for Python with +hocon/json/yaml/properties/env-vars/dict/cli support. ## Getting started @@ -114,15 +115,16 @@ print(dataconf.string(conf, Config)) @dataclass class Example: - hello: string - world: string + hello: str + world: str + foo: List[str] os.environ['DC_WORLD'] = 'monde' print( dataconf .multi - .url('https://raw.githubusercontent.com/zifeo/dataconf/master/confs/simple.hocon') + .url('https://raw.githubusercontent.com/zifeo/dataconf/main/confs/simple.hocon') .env('DC') .on(Example) ) @@ -135,24 +137,27 @@ print( import dataconf conf = dataconf.string('{ name: Test }', Config) +conf = dataconf.string('name:\n\tvalue: Test', Config, loader=dataconf.YAML) # dataconf.HOCON by default conf = dataconf.env('PREFIX_', Config) conf = dataconf.dict({'name': 'Test'}, Config) -conf = dataconf.url('https://raw.githubusercontent.com/zifeo/dataconf/master/confs/test.hocon', Config) -conf = dataconf.file('confs/test.{hocon,json,yaml,properties}', Config) +conf = dataconf.url('https://raw.githubusercontent.com/zifeo/dataconf/master/confs/test.hocon', Config) # hocon, json, yaml, properties +conf = dataconf.file('confs/test.hocon', Config) # hocon, json, yaml, properties conf = dataconf.cli(sys.argv, Config) # Aggregation conf = dataconf.multi.string(...).env(...).url(...).file(...).dict(...).cli(...).on(Config) # Same api as Python json/yaml packages (e.g. `load`, `loads`, `dump`, `dumps`) -conf = dataconf.load('confs/test.{hocon,json,yaml,properties}', Config) +conf = dataconf.load('confs/test.hocon', Config) # hocon, json, yaml, properties +conf = dataconf.load('confs/test.yaml', Config, loader=dataconf.YAML) # dataconf.HOCON by default dataconf.dump('confs/test.hocon', conf, out='hocon') dataconf.dump('confs/test.json', conf, out='json') dataconf.dump('confs/test.yaml', conf, out='yaml') dataconf.dump('confs/test.properties', conf, out='properties') ``` -For full HOCON capabilities see [here](https://github.com/chimpler/pyhocon/#example-of-hocon-file). +For full HOCON capabilities see +[here](https://github.com/chimpler/pyhocon/#example-of-hocon-file). ## Parse env vars @@ -202,11 +207,13 @@ is equivalent to } ``` -Note that when using `.env` source, the strict mode is disabled and value might be casted. +Note that when using `.env` source, the strict mode is disabled and value might +be casted. ## Parse CLI arguments -Same as env vars parse (dashes are converted to underscore, e.g. `TEST_A` → `--test-a`). +Same as env vars parse (dashes are converted to underscore, e.g. `TEST_A` → +`--test-a`). ## CLI usage diff --git a/confs/simple.hocon b/confs/simple.hocon new file mode 100644 index 0000000..0912606 --- /dev/null +++ b/confs/simple.hocon @@ -0,0 +1,4 @@ +hello = bonjour +foo = [ + bar +] diff --git a/confs/simple.json b/confs/simple.json index 666eacb..c158e09 100644 --- a/confs/simple.json +++ b/confs/simple.json @@ -1,3 +1,4 @@ { - "hello": "bonjour" -} \ No newline at end of file + "hello": "bonjour", + "foo": ["bar"] +} diff --git a/confs/simple.yaml b/confs/simple.yaml new file mode 100644 index 0000000..212d2dd --- /dev/null +++ b/confs/simple.yaml @@ -0,0 +1,3 @@ +hello: bonjour +foo: + - bar diff --git a/dataconf/__init__.py b/dataconf/__init__.py index 3b1d909..4e148b9 100644 --- a/dataconf/__init__.py +++ b/dataconf/__init__.py @@ -4,12 +4,14 @@ from dataconf.main import dumps from dataconf.main import env from dataconf.main import file +from dataconf.main import HOCON from dataconf.main import load from dataconf.main import loads from dataconf.main import multi from dataconf.main import parse from dataconf.main import string from dataconf.main import url +from dataconf.main import YAML from dataconf.version import __version__ __all__ = [ @@ -25,5 +27,7 @@ "cli", "multi", "parse", + "YAML", + "HOCON", "__version__", ] diff --git a/dataconf/main.py b/dataconf/main.py index 8e3136e..9f1062e 100644 --- a/dataconf/main.py +++ b/dataconf/main.py @@ -1,7 +1,12 @@ import inspect +import contextlib import os +from typing import Any, Optional +from typing import Dict from typing import List from typing import Type +from urllib.parse import urlparse +from urllib.request import urlopen from dataconf import utils from dataconf.exceptions import MalformedConfigException @@ -9,6 +14,10 @@ from pyhocon import HOCONConverter from pyhocon.config_parser import ConfigTree import pyparsing +from yaml import safe_load + +HOCON = 1 +YAML = 2 def inject_callee_scope(func): @@ -41,7 +50,6 @@ def parse( globalns=None, localns=None, ): - try: return utils.__parse( conf, clazz, "", strict, ignore_unexpected, globalns, localns @@ -66,23 +74,39 @@ def __init__(self, confs: List[ConfigTree], strict: bool = True) -> None: self.strict = strict def env(self, prefix: str) -> "Multi": - self.strict = False data = env_vars_parse(prefix, os.environ) - return self.dict(data) + return Multi(self.confs, strict=False).dict(data) def dict(self, obj: str) -> "Multi": conf = ConfigFactory.from_dict(obj) return Multi(self.confs + [conf], self.strict) - def string(self, s: str) -> "Multi": + def string(self, s: str, loader: str = HOCON) -> "Multi": + if loader == YAML: + data = safe_load(s) + return self.dict(data) + conf = ConfigFactory.parse_string(s) return Multi(self.confs + [conf], self.strict) - def url(self, uri: str) -> "Multi": - conf = ConfigFactory.parse_URL(uri) + def url(self, uri: str, timeout: int = 10) -> "Multi": + path = urlparse(uri).path + if path.endswith(".yaml") or path.endswith(".yml"): + with contextlib.closing(urlopen(uri, timeout=timeout)) as fd: + s = fd.read().decode("utf-8") + return self.string(s, loader=YAML) + + conf = ConfigFactory.parse_URL(uri, timeout=timeout, required=True) return Multi(self.confs + [conf], self.strict) - def file(self, path: str) -> "Multi": + def file(self, path: str, loader: Optional[str] = None) -> "Multi": + if loader == YAML or ( + loader is None and (path.endswith(".yaml") or path.endswith(".yml")) + ): + with open(path, "r") as f: + data = safe_load(f) + return self.dict(data) + conf = ConfigFactory.parse_file(path) return Multi(self.confs + [conf], self.strict) @@ -107,13 +131,13 @@ def env(prefix: str, clazz: Type, **kwargs): @inject_callee_scope -def dict(obj: str, clazz: Type, **kwargs): +def dict(obj: Dict[str, Any], clazz: Type, **kwargs): return multi.dict(obj).on(clazz, **kwargs) @inject_callee_scope -def string(s: str, clazz: Type, **kwargs): - return multi.string(s).on(clazz, **kwargs) +def string(s: str, clazz: Type, loader: str = HOCON, **kwargs): + return multi.string(s, loader).on(clazz, **kwargs) @inject_callee_scope @@ -122,8 +146,8 @@ def url(uri: str, clazz: Type, **kwargs): @inject_callee_scope -def file(path: str, clazz: Type, **kwargs): - return multi.file(path).on(clazz, **kwargs) +def file(path: str, clazz: Type, loader: Optional[str] = None, **kwargs): + return multi.file(path, loader).on(clazz, **kwargs) @inject_callee_scope @@ -132,13 +156,13 @@ def cli(argv: List[str], clazz: Type, **kwargs): @inject_callee_scope -def load(path: str, clazz: Type, **kwargs): - return file(path, clazz, **kwargs) +def load(path: str, clazz: Type, loader: Optional[str] = None, **kwargs): + return file(path, clazz, loader, **kwargs) @inject_callee_scope -def loads(s: str, clazz: Type, **kwargs): - return string(s, clazz, **kwargs) +def loads(s: str, clazz: Type, loader: str = HOCON, **kwargs): + return string(s, clazz, loader, **kwargs) def dump(file: str, instance: object, out: str): @@ -147,7 +171,7 @@ def dump(file: str, instance: object, out: str): def dumps(instance: object, out: str): - conf = utils.generate(instance, "") + conf = utils.__generate(instance, "") if out: if out.lower() == "hocon": diff --git a/dataconf/utils.py b/dataconf/utils.py index d1663e1..7c5a63a 100644 --- a/dataconf/utils.py +++ b/dataconf/utils.py @@ -6,6 +6,7 @@ from enum import Enum from enum import IntEnum from inspect import isclass + from typing import Any from typing import Dict from typing import get_args @@ -29,6 +30,12 @@ from pyhocon.config_tree import ConfigTree import pyparsing +from dataconf.version import PY310up + + +if PY310up: + from types import UnionType + NoneType = type(None) @@ -43,9 +50,13 @@ def __parse_type(value: Any, clazz: Type, path: str, check: bool): raise TypeConfigException(f"expected type {clazz} at {path}, got {type(value)}") +def is_union(origin): + return origin is Union or (PY310up and origin is UnionType) + + def is_optional(type: Type): # Optional = Union[T, NoneType] - return get_origin(type) is Union and NoneType in get_args(type) + return is_union(get_origin(type)) and NoneType in get_args(type) def __parse( @@ -57,9 +68,7 @@ def __parse( globalns, localns, ): - if is_dataclass(clazz): - if not isinstance(value, ConfigTree): raise TypeConfigException( f"expected type {clazz} at {path}, got {type(value)}" @@ -70,7 +79,6 @@ def __parse( type_hints = get_type_hints(clazz, globalns, localns) for f in fields(clazz): - if f.name in value: val = value[f.name] elif f.name.replace("_", "-") in value: @@ -81,6 +89,9 @@ def __parse( val = f.default_factory() else: val = f.default + if is_dataclass(val): + # if val is a dataclass, convert to ConfigTree + val = ConfigTree(asdict(val)) if not isinstance(val, _MISSING_TYPE): fs[f.name] = __parse( @@ -116,7 +127,9 @@ def __parse( if origin is list: if len(args) != 1: raise MissingTypeException("expected list with type information: List[?]") + if value is not None: + parse_candidate = args[0] return [ __parse( v, @@ -137,6 +150,8 @@ def __parse( "expected dict with type information: Dict[?, ?]" ) if value is not None: + # ignore key type + parse_candidate = args[1] return { k: __parse( v, @@ -151,41 +166,35 @@ def __parse( } return None - if is_optional(clazz): - left, right = args - try: - return __parse( - value, - left if right is NoneType else right, - path, - strict, - ignore_unexpected, - globalns, - localns, - ) - except TypeConfigException: - # cannot parse Optional - return None + if is_union(origin): + # Optional = Union[T, NoneType] + has_none = False + for parse_candidate in args: + if parse_candidate is NoneType: + has_none = True + else: + try: + return __parse( + value, + parse_candidate, + path, + strict, + ignore_unexpected, + globalns, + localns, + ) + except TypeConfigException: + continue - if origin is Union: - left, right = args + if has_none: + return None - try: - return __parse( - value, left, path, strict, ignore_unexpected, globalns, localns - ) - except TypeConfigException as left_failure: - try: - return __parse( - value, right, path, strict, ignore_unexpected, globalns, localns - ) - except TypeConfigException as right_failure: - raise TypeConfigException( - f"expected type {clazz} at {path}, failed both:\n- {left_failure}\n- {right_failure}" - ) + raise TypeConfigException( + f"expected one of {', '.join(map(str, args))} at {path}, got {type(value)}" + ) if clazz is bool: - if not strict: + if not strict and isinstance(value, str): try: value = bool(value) except ValueError: @@ -193,15 +202,17 @@ def __parse( return __parse_type(value, clazz, path, isinstance(value, bool)) if clazz is int: - if not strict: + if not strict and isinstance(value, str): try: - value = int(value) + cast = int(value) + if float(cast) == float(value): + value = cast except ValueError: pass return __parse_type(value, clazz, path, isinstance(value, int)) if clazz is float: - if not strict: + if not strict and isinstance(value, str): try: value = float(value) except ValueError: @@ -222,12 +233,12 @@ def __parse( if isclass(clazz) and (issubclass(clazz, Enum) or issubclass(clazz, IntEnum)): if isinstance(value, int): return clazz.__call__(value) + elif issubclass(clazz, str): + return clazz(value) elif isinstance(value, str): return clazz.__getattr__(value) - else: - raise TypeConfigException( - f"expected str or int at {path}, got {type(value)}" - ) + + raise TypeConfigException(f"expected str or int at {path}, got {type(value)}") if clazz is datetime: dt = __parse_type(value, clazz, path, isinstance(value, str)) @@ -291,7 +302,6 @@ def __parse( def __generate(value: object, path: str): - if is_dataclass(value): tree = {k: __generate(v, f"{path}.{k}") for k, v in asdict(value).items()} return ConfigTree(tree) @@ -315,7 +325,6 @@ def __env_vars_parse(prefix: str, obj: Dict[str, Any]): ret = {} def set_lens(p, focus, v): - # value if len(p) == 1: # []x @@ -330,7 +339,6 @@ def set_lens(p, focus, v): # dict if p[1] == "": - if p[0] not in focus: # []{x} if isinstance(focus, list): @@ -345,7 +353,6 @@ def set_lens(p, focus, v): # list (only if the focus/value is already a list or if it starts with element 0) if isinstance(p[1], int) and (p[1] == 0 or isinstance(focus[p[0]], list)): - if p[0] not in focus: # [][x] if isinstance(focus, list): diff --git a/dataconf/version.py b/dataconf/version.py index 8c0d5d5..1a1f705 100644 --- a/dataconf/version.py +++ b/dataconf/version.py @@ -1 +1,6 @@ -__version__ = "2.0.0" +import sys + +__version__ = "2.2.2" + +PY310up = sys.version_info >= (3, 10) +PY311up = sys.version_info >= (3, 11) diff --git a/poetry.lock b/poetry.lock index 55932ce..174d420 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,126 +1,255 @@ +# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. + [[package]] name = "argcomplete" -version = "1.12.3" +version = "3.1.2" description = "Bash tab completion for argparse" -category = "dev" -optional = false -python-versions = "*" - -[package.extras] -test = ["coverage", "flake8", "pexpect", "wheel"] - -[[package]] -name = "atomicwrites" -version = "1.4.0" -description = "Atomic file writes." -category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" - -[[package]] -name = "attrs" -version = "21.4.0" -description = "Classes Without Boilerplate" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=3.6" +files = [ + {file = "argcomplete-3.1.2-py3-none-any.whl", hash = "sha256:d97c036d12a752d1079f190bc1521c545b941fda89ad85d15afa909b4d1b9a99"}, + {file = "argcomplete-3.1.2.tar.gz", hash = "sha256:d5d1e5efd41435260b8f85673b74ea2e883affcbec9f4230c582689e8e78251b"}, +] [package.extras] -dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope-interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"] -docs = ["furo", "sphinx", "zope-interface", "sphinx-notfound-page"] -tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope-interface", "cloudpickle"] -tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"] +test = ["coverage", "mypy", "pexpect", "ruff", "wheel"] [[package]] name = "cfgv" -version = "3.3.1" +version = "3.4.0" description = "Validate configuration and produce human readable error messages." -category = "dev" optional = false -python-versions = ">=3.6.1" +python-versions = ">=3.8" +files = [ + {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, + {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.2.0" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "charset-normalizer-3.2.0.tar.gz", hash = "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-win32.whl", hash = "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-win32.whl", hash = "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-win32.whl", hash = "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-win32.whl", hash = "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-win32.whl", hash = "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80"}, + {file = "charset_normalizer-3.2.0-py3-none-any.whl", hash = "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6"}, +] [[package]] name = "colorama" -version = "0.4.5" +version = "0.4.6" description = "Cross-platform colored terminal text." -category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] [[package]] name = "commitizen" -version = "2.27.1" +version = "3.9.1" description = "Python commitizen client tool" -category = "dev" optional = false -python-versions = ">=3.6.2,<4.0.0" +python-versions = ">=3.7,<4.0" +files = [ + {file = "commitizen-3.9.1-py3-none-any.whl", hash = "sha256:2d2133fb4798d156475f937e9f8950327ffa79ef663dee1a940229c791f3095e"}, + {file = "commitizen-3.9.1.tar.gz", hash = "sha256:30d756bd8ae669c4a1e641148d22069ef588713b0e437eb6012e7dacac370e1e"}, +] [package.dependencies] -argcomplete = ">=1.12.1,<2.0.0" +argcomplete = ">=1.12.1,<3.2" +charset-normalizer = ">=2.1.0,<4" colorama = ">=0.4.1,<0.5.0" -decli = ">=0.5.2,<0.6.0" +decli = ">=0.6.0,<0.7.0" +importlib_metadata = ">=4.13,<7" jinja2 = ">=2.10.3" -packaging = ">=19,<22" +packaging = ">=19" pyyaml = ">=3.08" questionary = ">=1.4.0,<2.0.0" -termcolor = ">=1.1,<2.0" +termcolor = ">=1.1,<3" tomlkit = ">=0.5.3,<1.0.0" -typing-extensions = ">=4.0.1,<5.0.0" [[package]] name = "decli" -version = "0.5.2" +version = "0.6.1" description = "Minimal, easy-to-use, declarative cli tool" -category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" +files = [ + {file = "decli-0.6.1-py3-none-any.whl", hash = "sha256:7815ac58617764e1a200d7cadac6315fcaacc24d727d182f9878dd6378ccf869"}, + {file = "decli-0.6.1.tar.gz", hash = "sha256:ed88ccb947701e8e5509b7945fda56e150e2ac74a69f25d47ac85ef30ab0c0f0"}, +] [[package]] name = "distlib" -version = "0.3.4" +version = "0.3.7" description = "Distribution utilities" -category = "dev" optional = false python-versions = "*" +files = [ + {file = "distlib-0.3.7-py2.py3-none-any.whl", hash = "sha256:2e24928bc811348f0feb63014e97aaae3037f2cf48712d51ae61df7fd6075057"}, + {file = "distlib-0.3.7.tar.gz", hash = "sha256:9dafe54b34a028eafd95039d5e5d4851a13734540f1331060d31c9916e7147a8"}, +] + +[[package]] +name = "exceptiongroup" +version = "1.1.3" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.1.3-py3-none-any.whl", hash = "sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3"}, + {file = "exceptiongroup-1.1.3.tar.gz", hash = "sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9"}, +] + +[package.extras] +test = ["pytest (>=6)"] [[package]] name = "filelock" -version = "3.7.1" +version = "3.12.4" description = "A platform independent file lock." -category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +files = [ + {file = "filelock-3.12.4-py3-none-any.whl", hash = "sha256:08c21d87ded6e2b9da6728c3dff51baf1dcecf973b768ef35bcbc3447edb9ad4"}, + {file = "filelock-3.12.4.tar.gz", hash = "sha256:2e6f249f1f3654291606e046b09f1fd5eac39b360664c27f5aad072012f8bcbd"}, +] [package.extras] -docs = ["furo (>=2021.8.17b43)", "sphinx (>=4.1)", "sphinx-autodoc-typehints (>=1.12)"] -testing = ["covdefaults (>=1.2.0)", "coverage (>=4)", "pytest (>=4)", "pytest-cov", "pytest-timeout (>=1.4.2)"] +docs = ["furo (>=2023.7.26)", "sphinx (>=7.1.2)", "sphinx-autodoc-typehints (>=1.24)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3)", "diff-cover (>=7.7)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)", "pytest-timeout (>=2.1)"] +typing = ["typing-extensions (>=4.7.1)"] [[package]] name = "identify" -version = "2.5.1" +version = "2.5.29" description = "File identification library for Python" -category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +files = [ + {file = "identify-2.5.29-py2.py3-none-any.whl", hash = "sha256:24437fbf6f4d3fe6efd0eb9d67e24dd9106db99af5ceb27996a5f7895f24bf1b"}, + {file = "identify-2.5.29.tar.gz", hash = "sha256:d43d52b86b15918c137e3a74fff5224f60385cd0e9c38e99d07c257f02f151a5"}, +] [package.extras] license = ["ukkonen"] +[[package]] +name = "importlib-metadata" +version = "6.8.0" +description = "Read metadata from Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "importlib_metadata-6.8.0-py3-none-any.whl", hash = "sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb"}, + {file = "importlib_metadata-6.8.0.tar.gz", hash = "sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743"}, +] + +[package.dependencies] +zipp = ">=0.5" + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +perf = ["ipython"] +testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] + [[package]] name = "iniconfig" -version = "1.1.1" -description = "iniconfig: brain-dead simple config-ini parsing" -category = "dev" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" optional = false -python-versions = "*" +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] [[package]] name = "jinja2" version = "3.1.2" description = "A very fast and expressive template engine." -category = "dev" optional = false python-versions = ">=3.7" +files = [ + {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, + {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, +] [package.dependencies] MarkupSafe = ">=2.0" @@ -130,53 +259,113 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "markupsafe" -version = "2.1.1" +version = "2.1.3" description = "Safely add untrusted strings to HTML/XML markup." -category = "dev" optional = false python-versions = ">=3.7" +files = [ + {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-win32.whl", hash = "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-win32.whl", hash = "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-win32.whl", hash = "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-win32.whl", hash = "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba"}, + {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"}, +] [[package]] name = "nodeenv" -version = "1.7.0" +version = "1.8.0" description = "Node.js virtual environment builder" -category = "dev" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" +files = [ + {file = "nodeenv-1.8.0-py2.py3-none-any.whl", hash = "sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec"}, + {file = "nodeenv-1.8.0.tar.gz", hash = "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2"}, +] [package.dependencies] setuptools = "*" [[package]] name = "packaging" -version = "21.3" +version = "23.1" description = "Core utilities for Python packages" -category = "dev" optional = false -python-versions = ">=3.6" - -[package.dependencies] -pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" +python-versions = ">=3.7" +files = [ + {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, + {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, +] [[package]] name = "platformdirs" -version = "2.5.2" -description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "dev" +version = "3.10.0" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." optional = false python-versions = ">=3.7" +files = [ + {file = "platformdirs-3.10.0-py3-none-any.whl", hash = "sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d"}, + {file = "platformdirs-3.10.0.tar.gz", hash = "sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d"}, +] [package.extras] -docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)", "sphinx (>=4)"] -test = ["appdirs (==1.4.4)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)", "pytest (>=6)"] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] [[package]] name = "pluggy" -version = "1.0.0" +version = "1.3.0" description = "plugin and hook calling mechanisms for python" -category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" +files = [ + {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, + {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, +] [package.extras] dev = ["pre-commit", "tox"] @@ -184,240 +373,332 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pre-commit" -version = "2.19.0" +version = "3.4.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." -category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +files = [ + {file = "pre_commit-3.4.0-py2.py3-none-any.whl", hash = "sha256:96d529a951f8b677f730a7212442027e8ba53f9b04d217c4c67dc56c393ad945"}, + {file = "pre_commit-3.4.0.tar.gz", hash = "sha256:6bbd5129a64cad4c0dfaeeb12cd8f7ea7e15b77028d985341478c8af3c759522"}, +] [package.dependencies] cfgv = ">=2.0.0" identify = ">=1.0.0" nodeenv = ">=0.11.1" pyyaml = ">=5.1" -toml = "*" -virtualenv = ">=20.0.8" +virtualenv = ">=20.10.0" [[package]] name = "prompt-toolkit" -version = "3.0.30" +version = "3.0.39" description = "Library for building powerful interactive command lines in Python" -category = "dev" optional = false -python-versions = ">=3.6.2" +python-versions = ">=3.7.0" +files = [ + {file = "prompt_toolkit-3.0.39-py3-none-any.whl", hash = "sha256:9dffbe1d8acf91e3de75f3b544e4842382fc06c6babe903ac9acb74dc6e08d88"}, + {file = "prompt_toolkit-3.0.39.tar.gz", hash = "sha256:04505ade687dc26dc4284b1ad19a83be2f2afe83e7a828ace0c72f3a1df72aac"}, +] [package.dependencies] wcwidth = "*" -[[package]] -name = "py" -version = "1.11.0" -description = "library with cross-python path, ini-parsing, io, code, log facilities" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" - [[package]] name = "pyhocon" version = "0.3.59" description = "HOCON parser for Python" -category = "main" optional = false python-versions = "*" +files = [ + {file = "pyhocon-0.3.59.tar.gz", hash = "sha256:bb0eee59b57ecea5c30d14efc7ee7e55c935d58f03025ccdfc49237e920aa48c"}, +] [package.dependencies] pyparsing = ">=2.0,<3.0" [package.extras] -Duration = ["python-dateutil (>=2.8.0)"] +duration = ["python-dateutil (>=2.8.0)"] [[package]] name = "pyparsing" version = "2.4.7" description = "Python parsing module" -category = "main" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, + {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, +] [[package]] name = "pytest" -version = "7.1.2" +version = "7.4.2" description = "pytest: simple powerful testing with Python" -category = "dev" optional = false python-versions = ">=3.7" +files = [ + {file = "pytest-7.4.2-py3-none-any.whl", hash = "sha256:1d881c6124e08ff0a1bb75ba3ec0bfd8b5354a01c194ddd5a0a870a48d99b002"}, + {file = "pytest-7.4.2.tar.gz", hash = "sha256:a766259cfab564a2ad52cb1aae1b881a75c3eb7e34ca3779697c23ed47c47069"}, +] [package.dependencies] -atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} -attrs = ">=19.2.0" colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" packaging = "*" pluggy = ">=0.12,<2.0" -py = ">=1.8.2" -tomli = ">=1.0.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} [package.extras] -testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytest-httpserver" +version = "1.0.8" +description = "pytest-httpserver is a httpserver for pytest" +optional = false +python-versions = ">=3.8,<4.0" +files = [ + {file = "pytest_httpserver-1.0.8-py3-none-any.whl", hash = "sha256:24cd3d9f6a0b927c7bfc400d0b3fda7442721b8267ce29942bf307b190f0bb09"}, + {file = "pytest_httpserver-1.0.8.tar.gz", hash = "sha256:e052f69bc8a9073db02484681e8e47004dd1fb3763b0ae833bd899e5895c559a"}, +] + +[package.dependencies] +Werkzeug = ">=2.0.0" [[package]] name = "python-dateutil" version = "2.8.2" description = "Extensions to the standard Python datetime module" -category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +files = [ + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, +] [package.dependencies] six = ">=1.5" [[package]] name = "pyyaml" -version = "6.0" +version = "6.0.1" description = "YAML parser and emitter for Python" -category = "dev" optional = false python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, +] [[package]] name = "questionary" version = "1.10.0" description = "Python library to build pretty command line user prompts ⭐️" -category = "dev" optional = false python-versions = ">=3.6,<4.0" +files = [ + {file = "questionary-1.10.0-py3-none-any.whl", hash = "sha256:fecfcc8cca110fda9d561cb83f1e97ecbb93c613ff857f655818839dac74ce90"}, + {file = "questionary-1.10.0.tar.gz", hash = "sha256:600d3aefecce26d48d97eee936fdb66e4bc27f934c3ab6dd1e292c4f43946d90"}, +] [package.dependencies] prompt_toolkit = ">=2.0,<4.0" [package.extras] -docs = ["Sphinx (>=3.3,<4.0)", "sphinx-rtd-theme (>=0.5.0,<0.6.0)", "sphinx-autobuild (>=2020.9.1,<2021.0.0)", "sphinx-copybutton (>=0.3.1,<0.4.0)", "sphinx-autodoc-typehints (>=1.11.1,<2.0.0)"] +docs = ["Sphinx (>=3.3,<4.0)", "sphinx-autobuild (>=2020.9.1,<2021.0.0)", "sphinx-autodoc-typehints (>=1.11.1,<2.0.0)", "sphinx-copybutton (>=0.3.1,<0.4.0)", "sphinx-rtd-theme (>=0.5.0,<0.6.0)"] + +[[package]] +name = "ruff" +version = "0.0.286" +description = "An extremely fast Python linter, written in Rust." +optional = false +python-versions = ">=3.7" +files = [ + {file = "ruff-0.0.286-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:8e22cb557e7395893490e7f9cfea1073d19a5b1dd337f44fd81359b2767da4e9"}, + {file = "ruff-0.0.286-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:68ed8c99c883ae79a9133cb1a86d7130feee0397fdf5ba385abf2d53e178d3fa"}, + {file = "ruff-0.0.286-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8301f0bb4ec1a5b29cfaf15b83565136c47abefb771603241af9d6038f8981e8"}, + {file = "ruff-0.0.286-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:acc4598f810bbc465ce0ed84417ac687e392c993a84c7eaf3abf97638701c1ec"}, + {file = "ruff-0.0.286-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88c8e358b445eb66d47164fa38541cfcc267847d1e7a92dd186dddb1a0a9a17f"}, + {file = "ruff-0.0.286-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:0433683d0c5dbcf6162a4beb2356e820a593243f1fa714072fec15e2e4f4c939"}, + {file = "ruff-0.0.286-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ddb61a0c4454cbe4623f4a07fef03c5ae921fe04fede8d15c6e36703c0a73b07"}, + {file = "ruff-0.0.286-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:47549c7c0be24c8ae9f2bce6f1c49fbafea83bca80142d118306f08ec7414041"}, + {file = "ruff-0.0.286-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:559aa793149ac23dc4310f94f2c83209eedb16908a0343663be19bec42233d25"}, + {file = "ruff-0.0.286-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d73cfb1c3352e7aa0ce6fb2321f36fa1d4a2c48d2ceac694cb03611ddf0e4db6"}, + {file = "ruff-0.0.286-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:3dad93b1f973c6d1db4b6a5da8690c5625a3fa32bdf38e543a6936e634b83dc3"}, + {file = "ruff-0.0.286-py3-none-musllinux_1_2_i686.whl", hash = "sha256:26afc0851f4fc3738afcf30f5f8b8612a31ac3455cb76e611deea80f5c0bf3ce"}, + {file = "ruff-0.0.286-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:9b6b116d1c4000de1b9bf027131dbc3b8a70507788f794c6b09509d28952c512"}, + {file = "ruff-0.0.286-py3-none-win32.whl", hash = "sha256:556e965ac07c1e8c1c2d759ac512e526ecff62c00fde1a046acb088d3cbc1a6c"}, + {file = "ruff-0.0.286-py3-none-win_amd64.whl", hash = "sha256:5d295c758961376c84aaa92d16e643d110be32add7465e197bfdaec5a431a107"}, + {file = "ruff-0.0.286-py3-none-win_arm64.whl", hash = "sha256:1d6142d53ab7f164204b3133d053c4958d4d11ec3a39abf23a40b13b0784e3f0"}, + {file = "ruff-0.0.286.tar.gz", hash = "sha256:f1e9d169cce81a384a26ee5bb8c919fe9ae88255f39a1a69fd1ebab233a85ed2"}, +] [[package]] name = "setuptools" -version = "62.6.0" +version = "68.2.2" description = "Easily download, build, install, upgrade, and uninstall Python packages" -category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +files = [ + {file = "setuptools-68.2.2-py3-none-any.whl", hash = "sha256:b454a35605876da60632df1a60f736524eb73cc47bbc9f3f1ef1b644de74fd2a"}, + {file = "setuptools-68.2.2.tar.gz", hash = "sha256:4ac1475276d2f1c48684874089fefcd83bd7162ddaafb81fac866ba0db282a87"}, +] [package.extras] -docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-reredirects", "sphinxcontrib-towncrier", "furo"] -testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-enabler (>=1.0.1)", "pytest-perf", "mock", "flake8-2020", "virtualenv (>=13.0.0)", "wheel", "pip (>=19.1)", "jaraco.envs (>=2.2)", "pytest-xdist", "jaraco.path (>=3.2.0)", "build", "filelock (>=3.4.0)", "pip-run (>=8.8)", "ini2toml[lite] (>=0.9)", "tomli-w (>=1.0.0)", "pytest-black (>=0.3.7)", "pytest-cov", "pytest-mypy (>=0.9.1)"] -testing-integration = ["pytest", "pytest-xdist", "pytest-enabler", "virtualenv (>=13.0.0)", "tomli", "wheel", "jaraco.path (>=3.2.0)", "jaraco.envs (>=2.2)", "build", "filelock (>=3.4.0)"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "six" version = "1.16.0" description = "Python 2 and 3 compatibility utilities" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] [[package]] name = "termcolor" -version = "1.1.0" -description = "ANSII Color formatting for output in terminal." -category = "dev" +version = "2.3.0" +description = "ANSI color formatting for output in terminal" optional = false -python-versions = "*" +python-versions = ">=3.7" +files = [ + {file = "termcolor-2.3.0-py3-none-any.whl", hash = "sha256:3afb05607b89aed0ffe25202399ee0867ad4d3cb4180d98aaf8eefa6a5f7d475"}, + {file = "termcolor-2.3.0.tar.gz", hash = "sha256:b5b08f68937f138fe92f6c089b99f1e2da0ae56c52b78bf7075fd95420fd9a5a"}, +] -[[package]] -name = "toml" -version = "0.10.2" -description = "Python Library for Tom's Obvious, Minimal Language" -category = "dev" -optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +[package.extras] +tests = ["pytest", "pytest-cov"] [[package]] name = "tomli" version = "2.0.1" description = "A lil' TOML parser" -category = "dev" optional = false python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] [[package]] name = "tomlkit" -version = "0.11.0" +version = "0.12.1" description = "Style preserving TOML library" -category = "dev" -optional = false -python-versions = ">=3.6,<4.0" - -[[package]] -name = "typing-extensions" -version = "4.2.0" -description = "Backported and Experimental Type Hints for Python 3.7+" -category = "dev" optional = false python-versions = ">=3.7" +files = [ + {file = "tomlkit-0.12.1-py3-none-any.whl", hash = "sha256:712cbd236609acc6a3e2e97253dfc52d4c2082982a88f61b640ecf0817eab899"}, + {file = "tomlkit-0.12.1.tar.gz", hash = "sha256:38e1ff8edb991273ec9f6181244a6a391ac30e9f5098e7535640ea6be97a7c86"}, +] [[package]] name = "virtualenv" -version = "20.15.0" +version = "20.24.5" description = "Virtual Python Environment builder" -category = "dev" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +python-versions = ">=3.7" +files = [ + {file = "virtualenv-20.24.5-py3-none-any.whl", hash = "sha256:b80039f280f4919c77b30f1c23294ae357c4c8701042086e3fc005963e4e537b"}, + {file = "virtualenv-20.24.5.tar.gz", hash = "sha256:e8361967f6da6fbdf1426483bfe9fca8287c242ac0bc30429905721cefbff752"}, +] [package.dependencies] -distlib = ">=0.3.1,<1" -filelock = ">=3.2,<4" -platformdirs = ">=2,<3" -six = ">=1.9.0,<2" +distlib = ">=0.3.7,<1" +filelock = ">=3.12.2,<4" +platformdirs = ">=3.9.1,<4" [package.extras] -docs = ["proselint (>=0.10.2)", "sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=21.3)"] -testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", "pytest (>=4)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.1)", "pytest-mock (>=2)", "pytest-randomly (>=1)", "pytest-timeout (>=1)", "packaging (>=20.0)"] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] [[package]] name = "wcwidth" -version = "0.2.5" +version = "0.2.6" description = "Measures the displayed width of unicode strings in a terminal" -category = "dev" optional = false python-versions = "*" +files = [ + {file = "wcwidth-0.2.6-py2.py3-none-any.whl", hash = "sha256:795b138f6875577cd91bba52baf9e445cd5118fd32723b460e30a0af30ea230e"}, + {file = "wcwidth-0.2.6.tar.gz", hash = "sha256:a5220780a404dbe3353789870978e472cfe477761f06ee55077256e509b156d0"}, +] + +[[package]] +name = "werkzeug" +version = "2.3.7" +description = "The comprehensive WSGI web application library." +optional = false +python-versions = ">=3.8" +files = [ + {file = "werkzeug-2.3.7-py3-none-any.whl", hash = "sha256:effc12dba7f3bd72e605ce49807bbe692bd729c3bb122a3b91747a6ae77df528"}, + {file = "werkzeug-2.3.7.tar.gz", hash = "sha256:2b8c0e447b4b9dbcc85dd97b6eeb4dcbaf6c8b6c3be0bd654e25553e0a2157d8"}, +] + +[package.dependencies] +MarkupSafe = ">=2.1.1" + +[package.extras] +watchdog = ["watchdog (>=2.3)"] + +[[package]] +name = "zipp" +version = "3.17.0" +description = "Backport of pathlib-compatible object wrapper for zip files" +optional = false +python-versions = ">=3.8" +files = [ + {file = "zipp-3.17.0-py3-none-any.whl", hash = "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31"}, + {file = "zipp-3.17.0.tar.gz", hash = "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] [metadata] -lock-version = "1.1" +lock-version = "2.0" python-versions = "^3.8" -content-hash = "ba6ced0f1f1bcf63330c044b3a6c63206a3a770af804bb65dcf11eb1763024be" - -[metadata.files] -argcomplete = [] -atomicwrites = [] -attrs = [] -cfgv = [] -colorama = [] -commitizen = [] -decli = [] -distlib = [] -filelock = [] -identify = [] -iniconfig = [] -jinja2 = [] -markupsafe = [] -nodeenv = [] -packaging = [] -platformdirs = [] -pluggy = [] -pre-commit = [] -prompt-toolkit = [] -py = [] -pyhocon = [] -pyparsing = [] -pytest = [] -python-dateutil = [] -pyyaml = [] -questionary = [] -setuptools = [] -six = [] -termcolor = [] -toml = [] -tomli = [] -tomlkit = [] -typing-extensions = [] -virtualenv = [] -wcwidth = [] +content-hash = "f31d123e605dd9285d86ce9635fa0a5eb32a0562e43af47e22a4aab77523defd" diff --git a/pyproject.toml b/pyproject.toml index 9065556..e89a761 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,9 +1,9 @@ [tool.poetry] name = "dataconf" -version = "2.0.0" +version = "2.2.2" description = "Simple dataclasses configuration management for Python with hocon/json/yaml/properties/env-vars/dict support." authors = [] -license = "Apache2" +license = "MPL-2.0" readme = "README.md" repository = "https://github.com/zifeo/dataconf" include = [ @@ -14,23 +14,36 @@ classifiers = [ "Programming Language :: Python", "Programming Language :: Python :: 3.8", ] +keywords = [ + "configuration", + "dataclasses", + "yaml", + "hocon", + "json", + "properties", + "cli", + "environment variables", +] [tool.poetry.scripts] dataconf = 'dataconf.cli:run' [tool.poetry.dependencies] python = "^3.8" -pyhocon = "^0.3.59" +pyhocon = "0.3.59" python-dateutil = "^2.8.2" +PyYAML = "^6.0.1" -[tool.poetry.dev-dependencies] -pytest = "^7.1.2" -pre-commit = "^2.19.0" -commitizen = "^2.27.1" +[tool.poetry.group.dev.dependencies] +pytest = "^7.4.2" +pre-commit = ">=2.21,<4.0" +commitizen = ">=2.42.1,<4.0.0" +pytest-httpserver = "^1.0.8" +ruff = ">=0.0.247,<0.0.287" [tool.commitizen] name = "cz_conventional_commits" -version = "2.0.0" +version = "2.2.2" tag_format = "v$major.$minor.$patch$prerelease" version_files = [ "pyproject.toml:version", diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 0000000..f419fc5 --- /dev/null +++ b/ruff.toml @@ -0,0 +1 @@ +ignore = ["E501"] diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..561fa5c --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,14 @@ +import mimetypes + +from werkzeug.wrappers import Request +from werkzeug.wrappers import Response + + +def file_handler(path: str): + with open("confs/simple.json", "r") as f: + data = f.read() + + def handler(request: Request): + return Response(data, mimetype=mimetypes.guess_type(path)[0]) + + return handler diff --git a/tests/test_multi.py b/tests/test_multi.py index 77ffdb4..cb56d3d 100644 --- a/tests/test_multi.py +++ b/tests/test_multi.py @@ -1,8 +1,10 @@ from dataclasses import dataclass import os from typing import Text +import urllib from dataconf import multi +import pytest class TestMulti: @@ -49,3 +51,14 @@ class A: os.environ.pop("DATACLASS_A") assert multi.string("b = 2").cli(["--a", "1"]).on(A) == A(a="1", b=2) + + def test_404(self) -> None: + @dataclass + class A: + hello: str + + with pytest.raises(urllib.error.URLError): + multi.url("http://doesnotexists/simple.hocon").on(A) + + with pytest.raises(urllib.error.URLError): + multi.url("http://doesnotexists/simple.yaml").on(A) diff --git a/tests/test_parse.py b/tests/test_parse.py index 30b03f1..24b81f7 100644 --- a/tests/test_parse.py +++ b/tests/test_parse.py @@ -12,6 +12,7 @@ from typing import Text from typing import Union +import dataconf from dataconf import load from dataconf import loads from dataconf.exceptions import AmbiguousSubclassException @@ -20,8 +21,13 @@ from dataconf.exceptions import ParseException from dataconf.exceptions import TypeConfigException from dataconf.exceptions import UnexpectedKeysException +from dataconf.main import file +from dataconf.main import url from dateutil.relativedelta import relativedelta import pytest +from pytest_httpserver import HTTPServer +from dataconf.version import PY311up +from tests.conftest import file_handler PARENT_DIR = os.path.normpath( os.path.dirname(os.path.realpath(__file__)) + os.sep + os.pardir @@ -148,7 +154,7 @@ class B: @dataclass class A: - b: Union[B, Text] + b: Union[B, Text, int] conf = """ b { @@ -162,6 +168,21 @@ class A: """ assert loads(conf, A) == A(b="test") + conf = """ + b = 1 + """ + assert loads(conf, A) == A(b=1) + + conf = """ + b = 1.1 + """ + with pytest.raises(TypeConfigException) as e: + loads(conf, A) + + assert e.value.args[0] == ( + "expected one of .B'>, , at .b, got " + ) + def test_optional(self) -> None: @dataclass class A: @@ -175,6 +196,39 @@ class A: """ assert loads(conf, A) == A(b="test") + def test_str_enum(self) -> None: + class Color(str, Enum): + RED = "red" + GREEN = "green" + BLUE = "blue" + + @dataclass + class A: + b: Color + + conf_value = """ + b = red + """ + assert loads(conf_value, A) == A(b=Color.RED) + + @pytest.mark.skipif(not PY311up, reason="Test only runs for version 3.11+") + def test_strenum_class(self) -> None: + from enum import StrEnum + + class Color(StrEnum): + RED = "red" + GREEN = "green" + BLUE = "blue" + + @dataclass + class A: + b: Color + + conf_value = """ + b = red + """ + assert loads(conf_value, A) == A(b=Color.RED) + def test_enum(self) -> None: class Color(Enum): RED = 1 @@ -271,16 +325,6 @@ class A: """ assert loads(conf, A) == A(b="c") - def test_yaml(self) -> None: - @dataclass - class A: - b: Text - - conf = """ - b: c - """ - assert loads(conf, A) == A(b="c") - def test_default_value(self) -> None: @dataclass class A: @@ -289,14 +333,12 @@ class A: assert loads("", A) == A(b="c") def test_root_dict(self) -> None: - conf = """ b: c """ assert loads(conf, Dict[Text, Text]) == dict(b="c") def test_missing_type(self) -> None: - with pytest.raises(MissingTypeException): loads("", Dict) @@ -317,7 +359,6 @@ class A: assert loads(conf, A) == A(b="c") def test_misformat(self) -> None: - conf = """ b {} c { @@ -335,7 +376,6 @@ class Clazz: loads(conf, Dict[Text, Clazz]) def test_ignore_unexpected(self) -> None: - conf = """ a = "hello" b = "world" @@ -585,3 +625,90 @@ class Base: } """ assert loads(conf, Base).foo == [{"a": 1}, [2]] + + def test_yaml(self) -> None: + @dataclass + class B: + c: Text + + @dataclass + class A: + b: B + + conf = """ + b: + c: test + """ + assert loads(conf, A, loader=dataconf.YAML) == A(b=B(c="test")) + + def test_yaml_file(self) -> None: + @dataclass + class A: + hello: Text + foo: List[str] + + expected = A(hello="bonjour", foo=["bar"]) + assert file("confs/simple.yaml", A) == expected + assert load("confs/simple.yaml", A) == expected + assert load("confs/simple.yaml", A, loader=dataconf.YAML) == expected + + def test_yaml_url(self, httpserver: HTTPServer) -> None: + @dataclass + class A: + hello: Text + foo: List[str] + + httpserver.expect_request("/simple.yaml").respond_with_handler( + file_handler("confs/simple.yaml") + ) + + assert url( + httpserver.url_for("/simple.yaml"), + A, + ) == A(hello="bonjour", foo=["bar"]) + + def test_json_file(self) -> None: + @dataclass + class A: + hello: Text + foo: List[str] + + assert file("confs/simple.json", A) == A(hello="bonjour", foo=["bar"]) + + def test_json_url(self, httpserver: HTTPServer) -> None: + @dataclass + class A: + hello: Text + foo: List[str] + + httpserver.expect_request("/simple.json").respond_with_handler( + file_handler("confs/simple.json") + ) + + assert url(httpserver.url_for("/simple.json"), A) == A( + hello="bonjour", foo=["bar"] + ) + + def test_nested_with_defaults(self): + @dataclass + class Nested: + nested_a: bool = False + nested_b: str = field(default="some default value") + + @dataclass + class TopLevel: + top_a: str + top_b: str = field(default="some other value") + top_c: Nested = field( + default_factory=Nested + ) # nested dataclass with a default factory + + config_string = """ + top_a: "some value" + """ + + assert loads(config_string, TopLevel, loader=dataconf.YAML) == TopLevel( + top_a="some value", + top_b="some other value", + top_c=Nested(nested_a=False, nested_b="some default value"), + ) diff --git a/tests/test_regression.py b/tests/test_regression.py index 98040f5..df429f1 100644 --- a/tests/test_regression.py +++ b/tests/test_regression.py @@ -3,15 +3,19 @@ from dataclasses import field from datetime import datetime import os +import tempfile from typing import Dict from typing import List from typing import Optional from typing import Text from typing import Union +import pytest import dataconf from dateutil.relativedelta import relativedelta +from dataconf.version import PY310up + PARENT_DIR = os.path.normpath( os.path.dirname(os.path.realpath(__file__)) + os.sep + os.pardir ) @@ -159,3 +163,34 @@ class Example: assert dataconf.env("DC", Example) == Example( hello=None, world="monde", float_num=1.3, int_num=2, bool_var=True ) + + def test_dump_fail_54(self): + @dataclass + class Config: + experiment_name: str + + original = Config("test_dump") + + with tempfile.NamedTemporaryFile() as f: + dataconf.dump(f.name, original, out="yaml") + validate = dataconf.file(f.name, Config) + + assert original == validate + + @pytest.mark.skipif(not PY310up, reason="Test only runs for version 3.10+") + def test_union_alt_syntax_112(self): + @dataclass + class Borked: + foo: str | int + + assert dataconf.dict({"foo": 123}, Borked) == Borked(foo=123) + assert dataconf.dict({"foo": "asdf"}, Borked) == Borked(foo="asdf") + + @dataclass + class BorkedOpt: + foo: Optional[str | int] + + assert dataconf.dict({"foo": None}, BorkedOpt) == BorkedOpt(foo=None) + assert dataconf.dict({}, BorkedOpt) == BorkedOpt(foo=None) + assert dataconf.dict({"foo": 123}, BorkedOpt) == BorkedOpt(foo=123) + assert dataconf.dict({"foo": "asdf"}, BorkedOpt) == BorkedOpt(foo="asdf")