dataconf 3.6.0__tar.gz → 3.7.1__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.
- {dataconf-3.6.0 → dataconf-3.7.1}/PKG-INFO +9 -7
- {dataconf-3.6.0 → dataconf-3.7.1}/README.md +1 -1
- {dataconf-3.6.0 → dataconf-3.7.1}/dataconf/exceptions.py +0 -16
- {dataconf-3.6.0 → dataconf-3.7.1}/dataconf/main.py +24 -27
- {dataconf-3.6.0 → dataconf-3.7.1}/dataconf/utils.py +60 -52
- dataconf-3.7.1/dataconf/version.py +5 -0
- {dataconf-3.6.0 → dataconf-3.7.1}/pyproject.toml +8 -6
- dataconf-3.6.0/dataconf/version.py +0 -6
- {dataconf-3.6.0 → dataconf-3.7.1}/LICENSE +0 -0
- {dataconf-3.6.0 → dataconf-3.7.1}/dataconf/__init__.py +11 -11
- {dataconf-3.6.0 → dataconf-3.7.1}/dataconf/cli.py +0 -0
- {dataconf-3.6.0 → dataconf-3.7.1}/dataconf/py.typed +0 -0
|
@@ -1,24 +1,26 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: dataconf
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.7.1
|
|
4
4
|
Summary: Simple dataclasses configuration management for Python with hocon/json/yaml/properties/env-vars/dict support.
|
|
5
|
-
Home-page: https://github.com/zifeo/dataconf
|
|
6
5
|
License: MPL-2.0
|
|
6
|
+
License-File: LICENSE
|
|
7
7
|
Keywords: configuration,dataclasses,yaml,hocon,json,properties,cli,environment variables
|
|
8
|
-
Requires-Python: >=3.
|
|
8
|
+
Requires-Python: >=3.10,<4.0
|
|
9
9
|
Classifier: License :: OSI Approved
|
|
10
10
|
Classifier: Programming Language :: Python
|
|
11
11
|
Classifier: Programming Language :: Python :: 3
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
13
12
|
Classifier: Programming Language :: Python :: 3.10
|
|
14
13
|
Classifier: Programming Language :: Python :: 3.11
|
|
15
14
|
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
16
18
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
17
19
|
Requires-Dist: PyYAML (>=6.0.2,<7.0.0)
|
|
18
20
|
Requires-Dist: isodate (>=0.7.2,<0.8.0)
|
|
19
21
|
Requires-Dist: pyhocon (>=0.3.61,<0.4.0)
|
|
20
22
|
Requires-Dist: pyparsing (>=3.2.3,<4.0.0)
|
|
21
|
-
Requires-Dist: python-dateutil (>=
|
|
23
|
+
Requires-Dist: python-dateutil (>=3.0.0,<4.0.0)
|
|
22
24
|
Project-URL: Repository, https://github.com/zifeo/dataconf
|
|
23
25
|
Description-Content-Type: text/markdown
|
|
24
26
|
|
|
@@ -32,7 +34,7 @@ hocon/json/yaml/properties/env-vars/dict/cli support.
|
|
|
32
34
|
|
|
33
35
|
## Getting started
|
|
34
36
|
|
|
35
|
-
Requires at least Python 3.
|
|
37
|
+
Requires at least Python 3.10.
|
|
36
38
|
|
|
37
39
|
```bash
|
|
38
40
|
# pypi
|
|
@@ -1,46 +1,30 @@
|
|
|
1
1
|
class TypeConfigException(Exception):
|
|
2
2
|
"""Type mismatch exception."""
|
|
3
3
|
|
|
4
|
-
pass
|
|
5
|
-
|
|
6
4
|
|
|
7
5
|
class MissingTypeException(Exception):
|
|
8
6
|
"""Missing type exception (e.g. List instead of List[int]."""
|
|
9
7
|
|
|
10
|
-
pass
|
|
11
|
-
|
|
12
8
|
|
|
13
9
|
class AmbiguousSubclassException(Exception):
|
|
14
10
|
"""Multiple subclasses match the the given parameters. Use '_type' field to disambiguate"""
|
|
15
11
|
|
|
16
|
-
pass
|
|
17
|
-
|
|
18
12
|
|
|
19
13
|
class MalformedConfigException(Exception):
|
|
20
14
|
"""Missing values exception."""
|
|
21
15
|
|
|
22
|
-
pass
|
|
23
|
-
|
|
24
16
|
|
|
25
17
|
class UnexpectedKeysException(Exception):
|
|
26
18
|
"""Unexpected keys exception."""
|
|
27
19
|
|
|
28
|
-
pass
|
|
29
|
-
|
|
30
20
|
|
|
31
21
|
class EnvListOrderException(Exception):
|
|
32
22
|
"""Ordering exception."""
|
|
33
23
|
|
|
34
|
-
pass
|
|
35
|
-
|
|
36
24
|
|
|
37
25
|
class EnvListFormatException(Exception):
|
|
38
26
|
"""Format exception."""
|
|
39
27
|
|
|
40
|
-
pass
|
|
41
|
-
|
|
42
28
|
|
|
43
29
|
class ParseException(Exception):
|
|
44
30
|
"""Parsing exception."""
|
|
45
|
-
|
|
46
|
-
pass
|
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
import contextlib
|
|
2
2
|
import os
|
|
3
|
-
from typing import Any
|
|
4
|
-
from typing import Dict
|
|
5
|
-
from typing import List
|
|
6
|
-
from typing import Type
|
|
3
|
+
from typing import Any
|
|
7
4
|
from urllib.parse import urlparse
|
|
8
5
|
from urllib.request import urlopen
|
|
9
6
|
|
|
10
|
-
|
|
11
|
-
from dataconf.exceptions import MalformedConfigException
|
|
7
|
+
import pyparsing
|
|
12
8
|
from pyhocon import ConfigFactory
|
|
13
9
|
from pyhocon import HOCONConverter
|
|
14
10
|
from pyhocon.config_parser import ConfigTree
|
|
15
|
-
import pyparsing
|
|
16
11
|
from yaml import safe_load
|
|
17
12
|
|
|
13
|
+
from dataconf import utils
|
|
14
|
+
from dataconf.exceptions import MalformedConfigException
|
|
15
|
+
|
|
18
16
|
HOCON = 1
|
|
19
17
|
YAML = 2
|
|
20
18
|
|
|
@@ -39,19 +37,20 @@ def cli_parse(*args, **kwargs):
|
|
|
39
37
|
|
|
40
38
|
|
|
41
39
|
class Multi:
|
|
42
|
-
def __init__(self, confs:
|
|
40
|
+
def __init__(self, confs: list[ConfigTree], strict: bool = True, **kwargs) -> None:
|
|
43
41
|
self.confs = confs
|
|
44
42
|
self.strict = strict
|
|
45
43
|
self.kwargs = kwargs
|
|
46
44
|
|
|
47
45
|
def env(self, prefix: str, **kwargs) -> "Multi":
|
|
48
|
-
self.strict = False
|
|
49
46
|
data = env_vars_parse(prefix, os.environ)
|
|
50
|
-
|
|
47
|
+
strict = kwargs.pop("strict", False)
|
|
48
|
+
return self.dict(data, strict=strict, **kwargs)
|
|
51
49
|
|
|
52
|
-
def dict(self, obj:
|
|
50
|
+
def dict(self, obj: dict[str, Any], **kwargs) -> "Multi":
|
|
53
51
|
conf = ConfigFactory.from_dict(obj)
|
|
54
|
-
|
|
52
|
+
strict = kwargs.pop("strict", self.strict)
|
|
53
|
+
return Multi(self.confs + [conf], strict, **kwargs)
|
|
55
54
|
|
|
56
55
|
def string(self, s: str, loader: str = HOCON, **kwargs) -> "Multi":
|
|
57
56
|
if loader == YAML:
|
|
@@ -63,7 +62,7 @@ class Multi:
|
|
|
63
62
|
|
|
64
63
|
def url(self, uri: str, timeout: int = 10, **kwargs) -> "Multi":
|
|
65
64
|
path = urlparse(uri).path
|
|
66
|
-
if path.endswith(".yaml"
|
|
65
|
+
if path.endswith((".yaml", ".yml")):
|
|
67
66
|
with contextlib.closing(urlopen(uri, timeout=timeout)) as fd:
|
|
68
67
|
s = fd.read().decode("utf-8")
|
|
69
68
|
return self.string(s, loader=YAML, **kwargs)
|
|
@@ -74,16 +73,14 @@ class Multi:
|
|
|
74
73
|
def file(
|
|
75
74
|
self,
|
|
76
75
|
path: str,
|
|
77
|
-
loader:
|
|
76
|
+
loader: str | None = None,
|
|
78
77
|
allow_missing: bool = False,
|
|
79
78
|
**kwargs,
|
|
80
79
|
) -> "Multi":
|
|
81
80
|
if allow_missing and not os.path.exists(path):
|
|
82
81
|
return self.dict({}, **kwargs)
|
|
83
82
|
|
|
84
|
-
if loader == YAML or (
|
|
85
|
-
loader is None and (path.endswith(".yaml") or path.endswith(".yml"))
|
|
86
|
-
):
|
|
83
|
+
if loader == YAML or (loader is None and path.endswith((".yaml", ".yml"))):
|
|
87
84
|
with open(path, "r") as f:
|
|
88
85
|
data = safe_load(f)
|
|
89
86
|
return self.dict(data, **kwargs)
|
|
@@ -91,11 +88,11 @@ class Multi:
|
|
|
91
88
|
conf = ConfigFactory.parse_file(path)
|
|
92
89
|
return Multi(self.confs + [conf], self.strict, **kwargs)
|
|
93
90
|
|
|
94
|
-
def cli(self, argv:
|
|
91
|
+
def cli(self, argv: list[str], **kwargs) -> "Multi":
|
|
95
92
|
data = cli_parse(argv)
|
|
96
93
|
return self.dict(data, **kwargs)
|
|
97
94
|
|
|
98
|
-
def on(self, clazz:
|
|
95
|
+
def on(self, clazz: type):
|
|
99
96
|
conf, *nxts = self.confs
|
|
100
97
|
for nxt in nxts:
|
|
101
98
|
conf = ConfigTree.merge_configs(conf, nxt)
|
|
@@ -105,35 +102,35 @@ class Multi:
|
|
|
105
102
|
multi = Multi([])
|
|
106
103
|
|
|
107
104
|
|
|
108
|
-
def env(prefix: str, clazz:
|
|
105
|
+
def env(prefix: str, clazz: type, **kwargs):
|
|
109
106
|
return multi.env(prefix, **kwargs).on(clazz)
|
|
110
107
|
|
|
111
108
|
|
|
112
|
-
def dict(obj:
|
|
109
|
+
def dict(obj: dict[str, Any], clazz: type, **kwargs):
|
|
113
110
|
return multi.dict(obj, **kwargs).on(clazz)
|
|
114
111
|
|
|
115
112
|
|
|
116
|
-
def string(s: str, clazz:
|
|
113
|
+
def string(s: str, clazz: type, **kwargs):
|
|
117
114
|
return multi.string(s, **kwargs).on(clazz)
|
|
118
115
|
|
|
119
116
|
|
|
120
|
-
def url(uri: str, clazz:
|
|
117
|
+
def url(uri: str, clazz: type, **kwargs):
|
|
121
118
|
return multi.url(uri, **kwargs).on(clazz)
|
|
122
119
|
|
|
123
120
|
|
|
124
|
-
def file(path: str, clazz:
|
|
121
|
+
def file(path: str, clazz: type, **kwargs):
|
|
125
122
|
return multi.file(path, **kwargs).on(clazz)
|
|
126
123
|
|
|
127
124
|
|
|
128
|
-
def cli(argv:
|
|
125
|
+
def cli(argv: list[str], clazz: type, **kwargs):
|
|
129
126
|
return multi.cli(argv, **kwargs).on(clazz)
|
|
130
127
|
|
|
131
128
|
|
|
132
|
-
def load(path: str, clazz:
|
|
129
|
+
def load(path: str, clazz: type, **kwargs):
|
|
133
130
|
return file(path, clazz, **kwargs)
|
|
134
131
|
|
|
135
132
|
|
|
136
|
-
def loads(s: str, clazz:
|
|
133
|
+
def loads(s: str, clazz: type, **kwargs):
|
|
137
134
|
return string(s, clazz, **kwargs)
|
|
138
135
|
|
|
139
136
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from dataclasses import
|
|
1
|
+
from dataclasses import MISSING
|
|
2
2
|
from dataclasses import asdict
|
|
3
3
|
from dataclasses import fields
|
|
4
4
|
from dataclasses import is_dataclass
|
|
@@ -8,42 +8,50 @@ from enum import Enum
|
|
|
8
8
|
from enum import IntEnum
|
|
9
9
|
from inspect import isclass
|
|
10
10
|
from pathlib import Path
|
|
11
|
-
|
|
12
|
-
from typing import Any
|
|
13
|
-
from typing import
|
|
11
|
+
from types import UnionType
|
|
12
|
+
from typing import Any
|
|
13
|
+
from typing import Literal
|
|
14
|
+
from typing import Union
|
|
14
15
|
from typing import get_args
|
|
15
16
|
from typing import get_origin
|
|
16
|
-
from typing import List
|
|
17
|
-
from typing import Type
|
|
18
|
-
from typing import Union
|
|
19
17
|
|
|
20
|
-
|
|
21
|
-
from dataconf.exceptions import EnvListOrderException
|
|
22
|
-
from dataconf.exceptions import MalformedConfigException
|
|
23
|
-
from dataconf.exceptions import MissingTypeException
|
|
24
|
-
from dataconf.exceptions import ParseException
|
|
25
|
-
from dataconf.exceptions import TypeConfigException
|
|
26
|
-
from dataconf.exceptions import UnexpectedKeysException
|
|
18
|
+
import pyparsing
|
|
27
19
|
from dateutil.parser import isoparse
|
|
28
20
|
from dateutil.relativedelta import relativedelta
|
|
21
|
+
from isodate import Duration
|
|
22
|
+
from isodate import parse_duration
|
|
29
23
|
from pyhocon import ConfigFactory
|
|
30
24
|
from pyhocon.config_tree import ConfigList
|
|
31
25
|
from pyhocon.config_tree import ConfigTree
|
|
32
|
-
from isodate import parse_duration
|
|
33
|
-
from isodate import Duration
|
|
34
|
-
import pyparsing
|
|
35
26
|
|
|
36
|
-
from dataconf.
|
|
27
|
+
from dataconf.exceptions import AmbiguousSubclassException
|
|
28
|
+
from dataconf.exceptions import EnvListFormatException
|
|
29
|
+
from dataconf.exceptions import EnvListOrderException
|
|
30
|
+
from dataconf.exceptions import MalformedConfigException
|
|
31
|
+
from dataconf.exceptions import MissingTypeException
|
|
32
|
+
from dataconf.exceptions import ParseException
|
|
33
|
+
from dataconf.exceptions import TypeConfigException
|
|
34
|
+
from dataconf.exceptions import UnexpectedKeysException
|
|
37
35
|
|
|
36
|
+
NoneType = type(None)
|
|
38
37
|
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
_BOOL_TRUE = {"true", "1", "yes", "on", "t", "y"}
|
|
39
|
+
_BOOL_FALSE = {"false", "0", "no", "off", "f", "n"}
|
|
41
40
|
|
|
42
41
|
|
|
43
|
-
|
|
42
|
+
def __parse_bool(value: Any):
|
|
43
|
+
if isinstance(value, bool):
|
|
44
|
+
return value
|
|
45
|
+
if isinstance(value, str):
|
|
46
|
+
normalised = value.strip().lower()
|
|
47
|
+
if normalised in _BOOL_TRUE:
|
|
48
|
+
return True
|
|
49
|
+
if normalised in _BOOL_FALSE:
|
|
50
|
+
return False
|
|
51
|
+
return None
|
|
44
52
|
|
|
45
53
|
|
|
46
|
-
def __parse_type(value: Any, clazz:
|
|
54
|
+
def __parse_type(value: Any, clazz: type, path: str, check: bool):
|
|
47
55
|
try:
|
|
48
56
|
if check:
|
|
49
57
|
return value
|
|
@@ -56,15 +64,15 @@ def __parse_type(value: Any, clazz: Type, path: str, check: bool):
|
|
|
56
64
|
|
|
57
65
|
|
|
58
66
|
def is_union(origin):
|
|
59
|
-
return origin is Union or
|
|
67
|
+
return origin is Union or origin is UnionType
|
|
60
68
|
|
|
61
69
|
|
|
62
|
-
def is_optional(type:
|
|
70
|
+
def is_optional(type: type | Any | str):
|
|
63
71
|
# Optional = Union[T, NoneType]
|
|
64
72
|
return is_union(get_origin(type)) and NoneType in get_args(type)
|
|
65
73
|
|
|
66
74
|
|
|
67
|
-
def __parse(value: any, clazz:
|
|
75
|
+
def __parse(value: any, clazz: type, path: str, strict: bool, ignore_unexpected: bool):
|
|
68
76
|
if is_dataclass(clazz):
|
|
69
77
|
if not isinstance(value, ConfigTree):
|
|
70
78
|
raise TypeConfigException(
|
|
@@ -89,7 +97,7 @@ def __parse(value: any, clazz: Type, path: str, strict: bool, ignore_unexpected:
|
|
|
89
97
|
# if val is a dataclass, convert to ConfigTree
|
|
90
98
|
val = ConfigFactory.from_dict(asdict(val))
|
|
91
99
|
|
|
92
|
-
if not
|
|
100
|
+
if val is not MISSING:
|
|
93
101
|
fs[f.name] = __parse(
|
|
94
102
|
val, f.type, f"{path}.{f.name}", strict, ignore_unexpected
|
|
95
103
|
)
|
|
@@ -100,8 +108,8 @@ def __parse(value: any, clazz: Type, path: str, strict: bool, ignore_unexpected:
|
|
|
100
108
|
|
|
101
109
|
elif is_dataclass(f.type):
|
|
102
110
|
if all(
|
|
103
|
-
|
|
104
|
-
or
|
|
111
|
+
field.default is not MISSING
|
|
112
|
+
or field.default_factory is not MISSING
|
|
105
113
|
or is_optional(field.type)
|
|
106
114
|
for field in fields(f.type)
|
|
107
115
|
):
|
|
@@ -122,7 +130,7 @@ def __parse(value: any, clazz: Type, path: str, strict: bool, ignore_unexpected:
|
|
|
122
130
|
f'expected type {clazz} at {path_to_str(path)}, no field "{f.name}" found'
|
|
123
131
|
)
|
|
124
132
|
|
|
125
|
-
unexpected_keys = value.keys() - {renamings.get(k, k) for k in fs
|
|
133
|
+
unexpected_keys = value.keys() - {renamings.get(k, k) for k in fs}
|
|
126
134
|
if len(unexpected_keys) > 0 and not ignore_unexpected:
|
|
127
135
|
raise UnexpectedKeysException(
|
|
128
136
|
f'unexpected key(s) "{", ".join(unexpected_keys)}" detected for type {clazz} at {path_to_str(path)}'
|
|
@@ -133,30 +141,30 @@ def __parse(value: any, clazz: Type, path: str, strict: bool, ignore_unexpected:
|
|
|
133
141
|
origin = get_origin(clazz)
|
|
134
142
|
args = get_args(clazz)
|
|
135
143
|
|
|
136
|
-
if origin is list:
|
|
144
|
+
if clazz is list or origin is list:
|
|
145
|
+
if len(args) != 1:
|
|
146
|
+
raise MissingTypeException("expected list with type information: List[?]")
|
|
147
|
+
|
|
137
148
|
if value is None:
|
|
138
149
|
raise MalformedConfigException(
|
|
139
150
|
f"expected list at {path_to_str(path)} but received None"
|
|
140
151
|
)
|
|
141
152
|
|
|
142
|
-
if len(args) != 1:
|
|
143
|
-
raise MissingTypeException("expected list with type information: List[?]")
|
|
144
|
-
|
|
145
153
|
parse_candidate = args[0]
|
|
146
154
|
return [
|
|
147
155
|
__parse(v, parse_candidate, f"{path}[]", strict, ignore_unexpected)
|
|
148
156
|
for v in value
|
|
149
157
|
]
|
|
150
158
|
|
|
151
|
-
if origin is tuple:
|
|
159
|
+
if clazz is tuple or origin is tuple:
|
|
160
|
+
if len(args) < 1:
|
|
161
|
+
raise MissingTypeException("expected tuple with type information: Tuple[?]")
|
|
162
|
+
|
|
152
163
|
if value is None:
|
|
153
164
|
raise MalformedConfigException(
|
|
154
165
|
f"expected tuple at {path_to_str(path)} but received None"
|
|
155
166
|
)
|
|
156
167
|
|
|
157
|
-
if len(args) < 1:
|
|
158
|
-
raise MissingTypeException("expected tuple with type information: Tuple[?]")
|
|
159
|
-
|
|
160
168
|
has_ellipsis = args[-1] == Ellipsis
|
|
161
169
|
if has_ellipsis and len(args) != 2:
|
|
162
170
|
raise MissingTypeException(
|
|
@@ -172,7 +180,7 @@ def __parse(value: any, clazz: Type, path: str, strict: bool, ignore_unexpected:
|
|
|
172
180
|
for v, arg in zip(value, _args)
|
|
173
181
|
)
|
|
174
182
|
|
|
175
|
-
if origin is dict:
|
|
183
|
+
if clazz is dict or origin is dict:
|
|
176
184
|
if len(args) != 2:
|
|
177
185
|
raise MissingTypeException(
|
|
178
186
|
"expected dict with type information: Dict[?, ?]"
|
|
@@ -208,14 +216,14 @@ def __parse(value: any, clazz: Type, path: str, strict: bool, ignore_unexpected:
|
|
|
208
216
|
)
|
|
209
217
|
|
|
210
218
|
if clazz is bool:
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
pass
|
|
216
|
-
return __parse_type(value, clazz, path, isinstance(value, bool))
|
|
219
|
+
parsed = __parse_bool(value)
|
|
220
|
+
if parsed is not None:
|
|
221
|
+
return parsed
|
|
222
|
+
return __parse_type(value, clazz, path, False)
|
|
217
223
|
|
|
218
224
|
if clazz is int:
|
|
225
|
+
if isinstance(value, bool):
|
|
226
|
+
return __parse_type(value, clazz, path, False)
|
|
219
227
|
if not strict and value is not None:
|
|
220
228
|
try:
|
|
221
229
|
value = int(value)
|
|
@@ -224,14 +232,14 @@ def __parse(value: any, clazz: Type, path: str, strict: bool, ignore_unexpected:
|
|
|
224
232
|
return __parse_type(value, clazz, path, isinstance(value, int))
|
|
225
233
|
|
|
226
234
|
if clazz is float:
|
|
235
|
+
if isinstance(value, bool):
|
|
236
|
+
return __parse_type(value, clazz, path, False)
|
|
227
237
|
if not strict and value is not None:
|
|
228
238
|
try:
|
|
229
239
|
value = float(value)
|
|
230
240
|
except ValueError:
|
|
231
241
|
pass
|
|
232
|
-
return __parse_type(
|
|
233
|
-
value, clazz, path, isinstance(value, float) or isinstance(value, int)
|
|
234
|
-
)
|
|
242
|
+
return __parse_type(value, clazz, path, isinstance(value, (float, int)))
|
|
235
243
|
|
|
236
244
|
if clazz is str:
|
|
237
245
|
return __parse_type(value, clazz, path, isinstance(value, str))
|
|
@@ -243,7 +251,7 @@ def __parse(value: any, clazz: Type, path: str, strict: bool, ignore_unexpected:
|
|
|
243
251
|
return value
|
|
244
252
|
|
|
245
253
|
if isclass(clazz) and (issubclass(clazz, Enum) or issubclass(clazz, IntEnum)):
|
|
246
|
-
if isinstance(value, int):
|
|
254
|
+
if isinstance(value, int) and not isinstance(value, bool):
|
|
247
255
|
return clazz.__call__(value)
|
|
248
256
|
elif issubclass(clazz, str):
|
|
249
257
|
return clazz(value)
|
|
@@ -315,7 +323,7 @@ def __parse(value: any, clazz: Type, path: str, strict: bool, ignore_unexpected:
|
|
|
315
323
|
if len(child_successes) == 1:
|
|
316
324
|
return child_successes[0][1]
|
|
317
325
|
elif len(child_successes) > 1:
|
|
318
|
-
matching_classes = "\n- ".join(
|
|
326
|
+
matching_classes = "\n- ".join(x[0].__name__ for x in child_successes)
|
|
319
327
|
raise AmbiguousSubclassException(
|
|
320
328
|
f"""multiple subtypes of {clazz} matched at {path_to_str(path)}, use '_type' to disambiguate:\n- {matching_classes}"""
|
|
321
329
|
)
|
|
@@ -352,7 +360,7 @@ def __generate(value: object, path: str):
|
|
|
352
360
|
return value
|
|
353
361
|
|
|
354
362
|
|
|
355
|
-
def __env_vars_parse(prefix: str, obj:
|
|
363
|
+
def __env_vars_parse(prefix: str, obj: dict[str, Any]):
|
|
356
364
|
ret = {}
|
|
357
365
|
|
|
358
366
|
def set_lens(p, focus, v):
|
|
@@ -430,11 +438,11 @@ def path_to_str(path: str) -> str:
|
|
|
430
438
|
return path if len(path) > 0 else "root"
|
|
431
439
|
|
|
432
440
|
|
|
433
|
-
def __cli_parse(argv:
|
|
441
|
+
def __cli_parse(argv: list[str]):
|
|
434
442
|
kvs = {}
|
|
435
443
|
i = 0
|
|
436
444
|
|
|
437
|
-
if not argv[0].startswith("--"):
|
|
445
|
+
if argv and not argv[0].startswith("--"):
|
|
438
446
|
i += 1
|
|
439
447
|
|
|
440
448
|
while i < len(argv):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "dataconf"
|
|
3
|
-
version = "3.
|
|
3
|
+
version = "3.7.1"
|
|
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"
|
|
@@ -12,10 +12,12 @@ include = [
|
|
|
12
12
|
classifiers = [
|
|
13
13
|
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
14
14
|
"Programming Language :: Python",
|
|
15
|
-
"Programming Language :: Python :: 3.9",
|
|
16
15
|
"Programming Language :: Python :: 3.10",
|
|
17
16
|
"Programming Language :: Python :: 3.11",
|
|
18
|
-
"Programming Language :: Python :: 3.12"
|
|
17
|
+
"Programming Language :: Python :: 3.12",
|
|
18
|
+
"Programming Language :: Python :: 3.13",
|
|
19
|
+
"Programming Language :: Python :: 3.14",
|
|
20
|
+
"Programming Language :: Python :: 3.15",
|
|
19
21
|
]
|
|
20
22
|
keywords = [
|
|
21
23
|
"configuration",
|
|
@@ -32,8 +34,8 @@ keywords = [
|
|
|
32
34
|
dataconf = 'dataconf.cli:run'
|
|
33
35
|
|
|
34
36
|
[tool.poetry.dependencies]
|
|
35
|
-
python = "^3.
|
|
36
|
-
python-dateutil = "^
|
|
37
|
+
python = "^3.10"
|
|
38
|
+
python-dateutil = "^3.0.0"
|
|
37
39
|
PyYAML = "^6.0.2"
|
|
38
40
|
isodate = "^0.7.2"
|
|
39
41
|
pyhocon = "^0.3.61"
|
|
@@ -48,7 +50,7 @@ ruff = ">=0.12.7"
|
|
|
48
50
|
|
|
49
51
|
[tool.commitizen]
|
|
50
52
|
name = "cz_conventional_commits"
|
|
51
|
-
version = "3.
|
|
53
|
+
version = "3.7.1"
|
|
52
54
|
tag_format = "v$major.$minor.$patch$prerelease"
|
|
53
55
|
version_files = [
|
|
54
56
|
"pyproject.toml:version",
|
|
File without changes
|
|
@@ -1,33 +1,33 @@
|
|
|
1
|
+
from dataconf.main import HOCON
|
|
2
|
+
from dataconf.main import YAML
|
|
1
3
|
from dataconf.main import cli
|
|
2
4
|
from dataconf.main import dict
|
|
3
5
|
from dataconf.main import dump
|
|
4
6
|
from dataconf.main import dumps
|
|
5
7
|
from dataconf.main import env
|
|
6
8
|
from dataconf.main import file
|
|
7
|
-
from dataconf.main import HOCON
|
|
8
9
|
from dataconf.main import load
|
|
9
10
|
from dataconf.main import loads
|
|
10
11
|
from dataconf.main import multi
|
|
11
12
|
from dataconf.main import parse
|
|
12
13
|
from dataconf.main import string
|
|
13
14
|
from dataconf.main import url
|
|
14
|
-
from dataconf.main import YAML
|
|
15
15
|
from dataconf.version import __version__
|
|
16
16
|
|
|
17
17
|
__all__ = [
|
|
18
|
-
"
|
|
19
|
-
"
|
|
18
|
+
"HOCON",
|
|
19
|
+
"YAML",
|
|
20
|
+
"__version__",
|
|
21
|
+
"cli",
|
|
22
|
+
"dict",
|
|
20
23
|
"dump",
|
|
21
24
|
"dumps",
|
|
22
25
|
"env",
|
|
23
|
-
"url",
|
|
24
|
-
"dict",
|
|
25
26
|
"file",
|
|
26
|
-
"
|
|
27
|
-
"
|
|
27
|
+
"load",
|
|
28
|
+
"loads",
|
|
28
29
|
"multi",
|
|
29
30
|
"parse",
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"__version__",
|
|
31
|
+
"string",
|
|
32
|
+
"url",
|
|
33
33
|
]
|
|
File without changes
|
|
File without changes
|