confit 0.13.0.dev0__tar.gz → 0.13.0.dev1__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.
- {confit-0.13.0.dev0 → confit-0.13.0.dev1}/PKG-INFO +1 -1
- {confit-0.13.0.dev0 → confit-0.13.0.dev1}/confit/_version.py +1 -1
- {confit-0.13.0.dev0 → confit-0.13.0.dev1}/confit/registry.py +7 -3
- {confit-0.13.0.dev0 → confit-0.13.0.dev1}/confit/typing.py +18 -5
- {confit-0.13.0.dev0 → confit-0.13.0.dev1}/confit.egg-info/PKG-INFO +1 -1
- {confit-0.13.0.dev0 → confit-0.13.0.dev1}/tests/test_validate.py +44 -0
- {confit-0.13.0.dev0 → confit-0.13.0.dev1}/LICENSE +0 -0
- {confit-0.13.0.dev0 → confit-0.13.0.dev1}/README.md +0 -0
- {confit-0.13.0.dev0 → confit-0.13.0.dev1}/confit/__init__.py +0 -0
- {confit-0.13.0.dev0 → confit-0.13.0.dev1}/confit/cli.py +0 -0
- {confit-0.13.0.dev0 → confit-0.13.0.dev1}/confit/config.py +0 -0
- {confit-0.13.0.dev0 → confit-0.13.0.dev1}/confit/draft.py +0 -0
- {confit-0.13.0.dev0 → confit-0.13.0.dev1}/confit/errors.py +0 -0
- {confit-0.13.0.dev0 → confit-0.13.0.dev1}/confit/utils/__init__.py +0 -0
- {confit-0.13.0.dev0 → confit-0.13.0.dev1}/confit/utils/collections.py +0 -0
- {confit-0.13.0.dev0 → confit-0.13.0.dev1}/confit/utils/eval.py +0 -0
- {confit-0.13.0.dev0 → confit-0.13.0.dev1}/confit/utils/random.py +0 -0
- {confit-0.13.0.dev0 → confit-0.13.0.dev1}/confit/utils/settings.py +0 -0
- {confit-0.13.0.dev0 → confit-0.13.0.dev1}/confit/utils/xjson.py +0 -0
- {confit-0.13.0.dev0 → confit-0.13.0.dev1}/confit.egg-info/SOURCES.txt +0 -0
- {confit-0.13.0.dev0 → confit-0.13.0.dev1}/confit.egg-info/dependency_links.txt +0 -0
- {confit-0.13.0.dev0 → confit-0.13.0.dev1}/confit.egg-info/requires.txt +0 -0
- {confit-0.13.0.dev0 → confit-0.13.0.dev1}/confit.egg-info/top_level.txt +0 -0
- {confit-0.13.0.dev0 → confit-0.13.0.dev1}/pyproject.toml +0 -0
- {confit-0.13.0.dev0 → confit-0.13.0.dev1}/setup.cfg +0 -0
- {confit-0.13.0.dev0 → confit-0.13.0.dev1}/tests/test_as_list.py +0 -0
- {confit-0.13.0.dev0 → confit-0.13.0.dev1}/tests/test_cli.py +0 -0
- {confit-0.13.0.dev0 → confit-0.13.0.dev1}/tests/test_config_instance.py +0 -0
- {confit-0.13.0.dev0 → confit-0.13.0.dev1}/tests/test_draft.py +0 -0
- {confit-0.13.0.dev0 → confit-0.13.0.dev1}/tests/test_registry.py +0 -0
- {confit-0.13.0.dev0 → confit-0.13.0.dev1}/tests/test_typing.py +0 -0
- {confit-0.13.0.dev0 → confit-0.13.0.dev1}/tests/test_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: confit
|
|
3
|
-
Version: 0.13.0.
|
|
3
|
+
Version: 0.13.0.dev1
|
|
4
4
|
Summary: Smart configuration framework
|
|
5
5
|
Author-email: Perceval Wajsburt <perceval.wajsburt@aphp.fr>, Thomas Petit-Jean <thomas.petitjean@aphp.fr>, Adam Remaki <adam.remaki@aphp.fr>, Alice Calliger <alice.calliger@aphp.fr>
|
|
6
6
|
License: Copyright 2023 Assistance Publique - Hôpitaux de Paris
|
|
@@ -26,6 +26,7 @@ from confit.errors import (
|
|
|
26
26
|
SignatureError,
|
|
27
27
|
remove_lib_from_traceback,
|
|
28
28
|
)
|
|
29
|
+
from confit.typing import legacy_validator_schema
|
|
29
30
|
from confit.utils.settings import is_debug
|
|
30
31
|
|
|
31
32
|
# Reuse evaluated annotations, evaluating AsList[int] again can create a different class
|
|
@@ -48,7 +49,11 @@ def make_wrapper(raw_function, callee, config, invoker):
|
|
|
48
49
|
extras_name = next(
|
|
49
50
|
(name for name, p in parameters.items() if p.kind == p.VAR_KEYWORD), None
|
|
50
51
|
)
|
|
51
|
-
callee_name =
|
|
52
|
+
callee_name = (
|
|
53
|
+
f"{callee.__module__}.{callee.__qualname__}"
|
|
54
|
+
if callee.__module__
|
|
55
|
+
else callee.__qualname__
|
|
56
|
+
)
|
|
52
57
|
# Keep Field defaults, ordinary defaults stay omitted through stacked decorators
|
|
53
58
|
omitted_defaults = {
|
|
54
59
|
name
|
|
@@ -252,8 +257,7 @@ def validate_arguments(
|
|
|
252
257
|
steps.append(old_get_pydantic_core_schema(*args, **kwargs))
|
|
253
258
|
elif old_get_validators is not None:
|
|
254
259
|
steps.extend(
|
|
255
|
-
|
|
256
|
-
for fn in old_get_validators()
|
|
260
|
+
legacy_validator_schema(fn) for fn in old_get_validators()
|
|
257
261
|
)
|
|
258
262
|
steps.append(
|
|
259
263
|
core_schema.no_info_plain_validator_function(post_validate)
|
|
@@ -4,12 +4,28 @@ from typing import TypeVar
|
|
|
4
4
|
|
|
5
5
|
from pydantic import BaseModel
|
|
6
6
|
from pydantic.type_adapter import ConfigDict, TypeAdapter
|
|
7
|
-
from pydantic_core import core_schema
|
|
7
|
+
from pydantic_core import PydanticCustomError, core_schema
|
|
8
8
|
from typing_extensions import is_typeddict
|
|
9
9
|
|
|
10
10
|
T = TypeVar("T")
|
|
11
11
|
|
|
12
12
|
|
|
13
|
+
def legacy_validator_schema(validator):
|
|
14
|
+
"""
|
|
15
|
+
Keep TypeError as a validation failure for custom get_validators hooks
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def validate(value):
|
|
19
|
+
try:
|
|
20
|
+
return validator(value)
|
|
21
|
+
except TypeError as error:
|
|
22
|
+
raise PydanticCustomError(
|
|
23
|
+
"type_error", "{error}", {"error": error}
|
|
24
|
+
) from error
|
|
25
|
+
|
|
26
|
+
return core_schema.no_info_plain_validator_function(validate)
|
|
27
|
+
|
|
28
|
+
|
|
13
29
|
class Validatable:
|
|
14
30
|
@classmethod
|
|
15
31
|
def __get_validators__(cls):
|
|
@@ -18,10 +34,7 @@ class Validatable:
|
|
|
18
34
|
@classmethod
|
|
19
35
|
def __get_pydantic_core_schema__(cls, source, handler):
|
|
20
36
|
return core_schema.chain_schema(
|
|
21
|
-
[
|
|
22
|
-
core_schema.no_info_plain_validator_function(v)
|
|
23
|
-
for v in cls.__get_validators__()
|
|
24
|
-
]
|
|
37
|
+
[legacy_validator_schema(v) for v in cls.__get_validators__()]
|
|
25
38
|
)
|
|
26
39
|
|
|
27
40
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: confit
|
|
3
|
-
Version: 0.13.0.
|
|
3
|
+
Version: 0.13.0.dev1
|
|
4
4
|
Summary: Smart configuration framework
|
|
5
5
|
Author-email: Perceval Wajsburt <perceval.wajsburt@aphp.fr>, Thomas Petit-Jean <thomas.petitjean@aphp.fr>, Adam Remaki <adam.remaki@aphp.fr>, Alice Calliger <alice.calliger@aphp.fr>
|
|
6
6
|
License: Copyright 2023 Assistance Publique - Hôpitaux de Paris
|
|
@@ -60,6 +60,13 @@ def test_validate_decorator():
|
|
|
60
60
|
validated = validate_arguments()(GoodModel)
|
|
61
61
|
assert validated("3").value == 3
|
|
62
62
|
|
|
63
|
+
scope = {"validate_arguments": validate_arguments}
|
|
64
|
+
exec("@validate_arguments\ndef fn(value: int): return value", scope)
|
|
65
|
+
assert scope["fn"]("3") == 3
|
|
66
|
+
with pytest.raises(ConfitValidationError) as exc:
|
|
67
|
+
scope["fn"]("invalid")
|
|
68
|
+
assert str(exc.value).startswith("1 validation error for fn()\n-> value\n")
|
|
69
|
+
|
|
63
70
|
|
|
64
71
|
def test_custom_validators_v1():
|
|
65
72
|
@validate_arguments()
|
|
@@ -151,6 +158,43 @@ def test_custom_validators_validatable():
|
|
|
151
158
|
)
|
|
152
159
|
|
|
153
160
|
|
|
161
|
+
@pytest.mark.parametrize("base", [Validatable, object])
|
|
162
|
+
def test_custom_validator_type_error(base):
|
|
163
|
+
error = TypeError("Invalid value")
|
|
164
|
+
|
|
165
|
+
@validate_arguments
|
|
166
|
+
class Model(base):
|
|
167
|
+
def __init__(self, value: int):
|
|
168
|
+
self.value = value
|
|
169
|
+
|
|
170
|
+
@classmethod
|
|
171
|
+
def __get_validators__(cls):
|
|
172
|
+
yield cls.validate
|
|
173
|
+
|
|
174
|
+
@classmethod
|
|
175
|
+
def validate(cls, value):
|
|
176
|
+
raise error
|
|
177
|
+
|
|
178
|
+
@validate_arguments
|
|
179
|
+
def fn(values: list[Model]):
|
|
180
|
+
raise error
|
|
181
|
+
|
|
182
|
+
with pytest.raises(ConfitValidationError) as exc:
|
|
183
|
+
fn([1])
|
|
184
|
+
assert exc.value.errors() == [
|
|
185
|
+
{
|
|
186
|
+
"loc": ("values", 0),
|
|
187
|
+
"msg": "Invalid value",
|
|
188
|
+
"type": "type_error",
|
|
189
|
+
"input": 1,
|
|
190
|
+
"ctx": {"error": error},
|
|
191
|
+
}
|
|
192
|
+
]
|
|
193
|
+
with pytest.raises(TypeError) as exc:
|
|
194
|
+
fn([])
|
|
195
|
+
assert exc.value is error
|
|
196
|
+
|
|
197
|
+
|
|
154
198
|
def test_literals():
|
|
155
199
|
@validate_arguments()
|
|
156
200
|
def test(val: Literal["ok", "ko"]):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|