dataconf 2.2.1__tar.gz → 2.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dataconf
3
- Version: 2.2.1
3
+ Version: 2.2.2
4
4
  Summary: Simple dataclasses configuration management for Python with hocon/json/yaml/properties/env-vars/dict support.
5
5
  Home-page: https://github.com/zifeo/dataconf
6
6
  License: MPL-2.0
@@ -15,8 +15,8 @@ Classifier: Programming Language :: Python :: 3.10
15
15
  Classifier: Programming Language :: Python :: 3.11
16
16
  Classifier: Programming Language :: Python :: 3.8
17
17
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
- Requires-Dist: PyYAML (>=6.0,<7.0)
19
- Requires-Dist: pyhocon (==0.3.60)
18
+ Requires-Dist: PyYAML (>=6.0.1,<7.0.0)
19
+ Requires-Dist: pyhocon (==0.3.59)
20
20
  Requires-Dist: python-dateutil (>=2.8.2,<3.0.0)
21
21
  Project-URL: Repository, https://github.com/zifeo/dataconf
22
22
  Description-Content-Type: text/markdown
@@ -6,6 +6,7 @@ from datetime import datetime
6
6
  from enum import Enum
7
7
  from enum import IntEnum
8
8
  from inspect import isclass
9
+
9
10
  from typing import Any
10
11
  from typing import Dict
11
12
  from typing import get_args
@@ -28,6 +29,12 @@ from pyhocon.config_tree import ConfigList
28
29
  from pyhocon.config_tree import ConfigTree
29
30
  import pyparsing
30
31
 
32
+ from dataconf.version import PY310up
33
+
34
+
35
+ if PY310up:
36
+ from types import UnionType
37
+
31
38
 
32
39
  NoneType = type(None)
33
40
 
@@ -42,9 +49,13 @@ def __parse_type(value: Any, clazz: Type, path: str, check: bool):
42
49
  raise TypeConfigException(f"expected type {clazz} at {path}, got {type(value)}")
43
50
 
44
51
 
52
+ def is_union(origin):
53
+ return origin is Union or (PY310up and origin is UnionType)
54
+
55
+
45
56
  def is_optional(type: Type):
46
57
  # Optional = Union[T, NoneType]
47
- return get_origin(type) is Union and NoneType in get_args(type)
58
+ return is_union(get_origin(type)) and NoneType in get_args(type)
48
59
 
49
60
 
50
61
  def __parse(value: any, clazz: Type, path: str, strict: bool, ignore_unexpected: bool):
@@ -123,33 +134,29 @@ def __parse(value: any, clazz: Type, path: str, strict: bool, ignore_unexpected:
123
134
  }
124
135
  return None
125
136
 
126
- if is_optional(clazz):
127
- left, right = args
128
- try:
129
- return __parse(
130
- value,
131
- left if right is NoneType else right,
132
- path,
133
- strict,
134
- ignore_unexpected,
135
- )
136
- except TypeConfigException:
137
- # cannot parse Optional
138
- return None
139
-
140
- if origin is Union:
137
+ if is_union(origin):
138
+ # Optional = Union[T, NoneType]
139
+ has_none = False
141
140
  for parse_candidate in args:
142
- try:
143
- return __parse(value, parse_candidate, path, strict, ignore_unexpected)
144
- except TypeConfigException:
145
- continue
141
+ if parse_candidate is NoneType:
142
+ has_none = True
143
+ else:
144
+ try:
145
+ return __parse(
146
+ value, parse_candidate, path, strict, ignore_unexpected
147
+ )
148
+ except TypeConfigException:
149
+ continue
150
+
151
+ if has_none:
152
+ return None
146
153
 
147
154
  raise TypeConfigException(
148
155
  f"expected one of {', '.join(map(str, args))} at {path}, got {type(value)}"
149
156
  )
150
157
 
151
158
  if clazz is bool:
152
- if not strict:
159
+ if not strict and value is not None:
153
160
  try:
154
161
  value = bool(value)
155
162
  except ValueError:
@@ -157,7 +164,7 @@ def __parse(value: any, clazz: Type, path: str, strict: bool, ignore_unexpected:
157
164
  return __parse_type(value, clazz, path, isinstance(value, bool))
158
165
 
159
166
  if clazz is int:
160
- if not strict:
167
+ if not strict and value is not None:
161
168
  try:
162
169
  value = int(value)
163
170
  except ValueError:
@@ -165,7 +172,7 @@ def __parse(value: any, clazz: Type, path: str, strict: bool, ignore_unexpected:
165
172
  return __parse_type(value, clazz, path, isinstance(value, int))
166
173
 
167
174
  if clazz is float:
168
- if not strict:
175
+ if not strict and value is not None:
169
176
  try:
170
177
  value = float(value)
171
178
  except ValueError:
@@ -0,0 +1,6 @@
1
+ import sys
2
+
3
+ __version__ = "2.2.2"
4
+
5
+ PY310up = sys.version_info >= (3, 10)
6
+ PY311up = sys.version_info >= (3, 11)
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "dataconf"
3
- version = "2.2.1"
3
+ version = "2.2.2"
4
4
  description = "Simple dataclasses configuration management for Python with hocon/json/yaml/properties/env-vars/dict support."
5
5
  authors = []
6
6
  license = "MPL-2.0"
@@ -30,20 +30,20 @@ dataconf = 'dataconf.cli:run'
30
30
 
31
31
  [tool.poetry.dependencies]
32
32
  python = "^3.8"
33
- pyhocon = "0.3.60"
33
+ pyhocon = "0.3.59"
34
34
  python-dateutil = "^2.8.2"
35
- PyYAML = "^6.0"
35
+ PyYAML = "^6.0.1"
36
36
 
37
37
  [tool.poetry.group.dev.dependencies]
38
- pytest = "^7.3.1"
38
+ pytest = "^7.4.2"
39
39
  pre-commit = ">=2.21,<4.0"
40
40
  commitizen = ">=2.42.1,<4.0.0"
41
- pytest-httpserver = "^1.0.6"
42
- ruff = ">=0.0.247,<0.0.264"
41
+ pytest-httpserver = "^1.0.8"
42
+ ruff = ">=0.0.247,<0.0.287"
43
43
 
44
44
  [tool.commitizen]
45
45
  name = "cz_conventional_commits"
46
- version = "2.2.1"
46
+ version = "2.2.2"
47
47
  tag_format = "v$major.$minor.$patch$prerelease"
48
48
  version_files = [
49
49
  "pyproject.toml:version",
@@ -8,14 +8,14 @@ package_data = \
8
8
  {'': ['*']}
9
9
 
10
10
  install_requires = \
11
- ['PyYAML>=6.0,<7.0', 'pyhocon==0.3.60', 'python-dateutil>=2.8.2,<3.0.0']
11
+ ['PyYAML>=6.0.1,<7.0.0', 'pyhocon==0.3.59', 'python-dateutil>=2.8.2,<3.0.0']
12
12
 
13
13
  entry_points = \
14
14
  {'console_scripts': ['dataconf = dataconf.cli:run']}
15
15
 
16
16
  setup_kwargs = {
17
17
  'name': 'dataconf',
18
- 'version': '2.2.1',
18
+ 'version': '2.2.2',
19
19
  'description': 'Simple dataclasses configuration management for Python with hocon/json/yaml/properties/env-vars/dict support.',
20
20
  'long_description': '# Dataconf\n\n[![Actions Status](https://github.com/zifeo/dataconf/workflows/CI/badge.svg)](https://github.com/zifeo/dataconf/actions)\n[![PyPI version](https://badge.fury.io/py/dataconf.svg)](https://badge.fury.io/py/dataconf)\n\nSimple dataclasses configuration management for Python with\nhocon/json/yaml/properties/env-vars/dict/cli support.\n\n## Getting started\n\nRequires at least Python 3.8.\n\n```bash\n# pypi\npip install dataconf\npoetry add dataconf\n\n# remote master\npip install --upgrade git+https://github.com/zifeo/dataconf.git\npoetry add git+https://github.com/zifeo/dataconf.git\n\n# local repo/dev\npoetry install\npre-commit install\n```\n\n## Usage\n\n```python\nimport os\nfrom dataclasses import dataclass, field\nfrom typing import List, Dict, Text, Union\nfrom dateutil.relativedelta import relativedelta\nfrom datetime import datetime\nimport dataconf\n\nconf = """\nstr_name = test\nstr_name = ${?HOME}\ndash-to-underscore = true\nfloat_num = 2.2\niso_datetime = "2000-01-01T20:00:00"\n# this is a comment\nlist_data = [\n a\n b\n]\nnested {\n a = test\n b : 1\n}\nnested_list = [\n {\n a = test1\n b : 2.5\n }\n]\nduration = 2s\nunion = 1\npeople {\n name = Thailand\n}\nzone {\n area_code = 42\n}\n"""\n\nclass AbstractBaseClass:\n pass\n \n@dataclass\nclass Person(AbstractBaseClass):\n name: Text\n \n@dataclass\nclass Zone(AbstractBaseClass):\n area_code: int\n\n@dataclass\nclass Nested:\n a: Text\n b: float\n\n@dataclass\nclass Config:\n str_name: Text\n dash_to_underscore: bool\n float_num: float\n iso_datetime: datetime\n list_data: List[Text]\n nested: Nested\n nested_list: List[Nested]\n duration: relativedelta\n union: Union[Text, int]\n people: AbstractBaseClass\n zone: AbstractBaseClass\n default: Text = \'hello\'\n default_factory: Dict[Text, Text] = field(default_factory=dict)\n\nprint(dataconf.string(conf, Config))\n# Config(\n# str_name=\'/users/root\',\n# dash_to_underscore=True,\n# float_num=2.2,\n# list_data=[\'a\', \'b\'],\n# nested=Nested(a=\'test\'),\n# nested_list=[Nested(a=\'test1\', b=2.5)],\n# duration=relativedelta(seconds=+2), \n# union=1, \n# people=Person(name=\'Thailand\'), \n# zone=Zone(area_code=42),\n# default=\'hello\', \n# default_factory={}\n# )\n\n@dataclass\nclass Example:\n hello: str\n world: str\n foo: List[str]\n\nos.environ[\'DC_WORLD\'] = \'monde\'\n\nprint(\n dataconf\n .multi\n .url(\'https://raw.githubusercontent.com/zifeo/dataconf/main/confs/simple.hocon\')\n .env(\'DC\')\n .on(Example)\n)\n# Example(hello=\'bonjour\',world=\'monde\')\n```\n\n## API\n\n```python\nimport dataconf\n\nconf = dataconf.string(\'{ name: Test }\', Config)\nconf = dataconf.string(\'name:\\n\\tvalue: Test\', Config, loader=dataconf.YAML) # dataconf.HOCON by default\nconf = dataconf.env(\'PREFIX_\', Config)\nconf = dataconf.dict({\'name\': \'Test\'}, Config)\nconf = dataconf.url(\'https://raw.githubusercontent.com/zifeo/dataconf/master/confs/test.hocon\', Config) # hocon, json, yaml, properties\nconf = dataconf.file(\'confs/test.hocon\', Config) # hocon, json, yaml, properties\nconf = dataconf.cli(sys.argv, Config)\n\n# Aggregation\nconf = dataconf.multi.string(...).env(...).url(...).file(...).dict(...).cli(...).on(Config)\n\n# Same api as Python json/yaml packages (e.g. `load`, `loads`, `dump`, `dumps`)\nconf = dataconf.load(\'confs/test.hocon\', Config) # hocon, json, yaml, properties\nconf = dataconf.load(\'confs/test.yaml\', Config, loader=dataconf.YAML) # dataconf.HOCON by default\ndataconf.dump(\'confs/test.hocon\', conf, out=\'hocon\')\ndataconf.dump(\'confs/test.json\', conf, out=\'json\')\ndataconf.dump(\'confs/test.yaml\', conf, out=\'yaml\')\ndataconf.dump(\'confs/test.properties\', conf, out=\'properties\')\n```\n\nFor full HOCON capabilities see\n[here](https://github.com/chimpler/pyhocon/#example-of-hocon-file).\n\n## Parse env vars\n\n```bash\nPREFIX_VAR=a\nPREFIX_VAR_NAME=b\nPREFIX_TEST__NAME=c\nPREFIX_LS_0=d\nPREFIX_LS_1=e\nPREFIX_LSLS_0_0=f\nPREFIX_LSOB_0__NAME=g\nPREFIX_NESTED_="{ name: Test }"\nPREFIX_SUB_="{ value: ${PREFIX_VAR} }"\n```\n\nis equivalent to\n\n```\n{\n var = a\n var_name = b\n test {\n name = c\n }\n ls = [\n d\n e\n ]\n lsls = [\n [\n f\n ]\n ]\n lsob = [\n {\n name = g\n }\n ]\n nested {\n # parse nested config by suffixing env var with `_`\n name: Test\n }\n sub {\n # will have value "a" at parsing, useful for aliases\n value = ${PREFIX_VAR}\n }\n}\n```\n\nNote that when using `.env` source, the strict mode is disabled and value might\nbe casted.\n\n## Parse CLI arguments\n\nSame as env vars parse (dashes are converted to underscore, e.g. `TEST_A` →\n`--test-a`).\n\n## CLI usage\n\nCan be used for validation or converting between supported file formats (`-o`).\n\n```shell\ndataconf -c confs/test.hocon -m tests.configs -d TestConf -o hocon\n# dataconf.exceptions.TypeConfigException: expected type <class \'datetime.timedelta\'> at .duration, got <class \'int\'>\n```\n',
21
21
  'author': 'None',
@@ -1 +0,0 @@
1
- __version__ = "2.2.1"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes