structtype 0.1.0__tar.gz → 0.3.0__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.
- {structtype-0.1.0 → structtype-0.3.0}/AGENTS.md +12 -10
- {structtype-0.1.0 → structtype-0.3.0}/MANIFEST.in +0 -1
- {structtype-0.1.0 → structtype-0.3.0}/Makefile +9 -2
- {structtype-0.1.0/src/structtype.egg-info → structtype-0.3.0}/PKG-INFO +1 -1
- {structtype-0.1.0 → structtype-0.3.0}/pyproject.toml +9 -16
- {structtype-0.1.0 → structtype-0.3.0}/setup.py +15 -9
- {structtype-0.1.0 → structtype-0.3.0}/src/structtype/__init__.py +2 -2
- {structtype-0.1.0 → structtype-0.3.0}/src/structtype/__init__.pyi +35 -46
- structtype-0.3.0/src/structtype/_adapter.py +128 -0
- {structtype-0.1.0 → structtype-0.3.0}/src/structtype/_core.c +648 -1086
- {structtype-0.1.0 → structtype-0.3.0}/src/structtype/_inspect.py +120 -31
- {structtype-0.1.0 → structtype-0.3.0}/src/structtype/_json_schema.py +12 -7
- {structtype-0.1.0 → structtype-0.3.0}/src/structtype/_utils.py +29 -1
- {structtype-0.1.0 → structtype-0.3.0}/src/structtype/_version.py +2 -2
- {structtype-0.1.0 → structtype-0.3.0}/src/structtype/common.h +2 -0
- {structtype-0.1.0 → structtype-0.3.0}/src/structtype/ryu.h +1 -1
- {structtype-0.1.0 → structtype-0.3.0/src/structtype.egg-info}/PKG-INFO +1 -1
- {structtype-0.1.0 → structtype-0.3.0}/src/structtype.egg-info/SOURCES.txt +1 -1
- {structtype-0.1.0 → structtype-0.3.0}/tests/unit/test_JSONTestSuite.py +3 -3
- {structtype-0.1.0 → structtype-0.3.0}/tests/unit/test_check.py +21 -58
- {structtype-0.1.0 → structtype-0.3.0}/tests/unit/test_constraints.py +3 -3
- {structtype-0.1.0 → structtype-0.3.0}/tests/unit/test_inspect.py +19 -0
- {structtype-0.1.0 → structtype-0.3.0}/tests/unit/test_json.py +252 -359
- {structtype-0.1.0 → structtype-0.3.0}/tests/unit/test_msgspec.py +2 -3
- {structtype-0.1.0 → structtype-0.3.0}/tests/unit/test_pydantic.py +1 -1
- {structtype-0.1.0 → structtype-0.3.0}/tests/unit/test_schema.py +123 -0
- {structtype-0.1.0 → structtype-0.3.0}/tests/unit/test_struct.py +7 -23
- {structtype-0.1.0 → structtype-0.3.0}/tests/unit/test_struct_meta.py +13 -13
- structtype-0.3.0/uv.lock +1490 -0
- structtype-0.1.0/.cibuildwheel.toml +0 -4
- structtype-0.1.0/src/structtype/_adapter.py +0 -34
- {structtype-0.1.0 → structtype-0.3.0}/LICENSE +0 -0
- {structtype-0.1.0 → structtype-0.3.0}/README.md +0 -0
- {structtype-0.1.0 → structtype-0.3.0}/setup.cfg +0 -0
- {structtype-0.1.0 → structtype-0.3.0}/src/structtype/atof.h +0 -0
- {structtype-0.1.0 → structtype-0.3.0}/src/structtype/atof_consts.h +0 -0
- {structtype-0.1.0 → structtype-0.3.0}/src/structtype/itoa.h +0 -0
- {structtype-0.1.0 → structtype-0.3.0}/src/structtype/py.typed +0 -0
- {structtype-0.1.0 → structtype-0.3.0}/src/structtype.egg-info/dependency_links.txt +0 -0
- {structtype-0.1.0 → structtype-0.3.0}/src/structtype.egg-info/top_level.txt +0 -0
- {structtype-0.1.0 → structtype-0.3.0}/tests/__init__.py +0 -0
- {structtype-0.1.0 → structtype-0.3.0}/tests/unit/__init__.py +0 -0
- {structtype-0.1.0 → structtype-0.3.0}/tests/unit/conftest.py +0 -0
- {structtype-0.1.0 → structtype-0.3.0}/tests/unit/test_adapter.py +0 -0
- {structtype-0.1.0 → structtype-0.3.0}/tests/unit/test_cpylint.py +0 -0
- {structtype-0.1.0 → structtype-0.3.0}/tests/unit/test_free_threading.py +0 -0
- {structtype-0.1.0 → structtype-0.3.0}/tests/unit/test_raw.py +0 -0
- {structtype-0.1.0 → structtype-0.3.0}/tests/unit/test_utils.py +0 -0
- {structtype-0.1.0 → structtype-0.3.0}/tests/unit/utils.py +0 -0
|
@@ -41,22 +41,24 @@ All commands go through `make`.
|
|
|
41
41
|
- `structtype.Struct` — base class with config options (frozen, tag, rename, etc.)
|
|
42
42
|
- `structtype.Field` — field constraints (gt, ge, lt, le, min_length, etc.)
|
|
43
43
|
- `structtype.Raw` — lazy JSON passthrough
|
|
44
|
+
- `structtype.fields(type_or_instance)` — get FieldInfo tuple for a struct type/instance
|
|
44
45
|
- `structtype._inspect.type_info()` / `multi_type_info()` — type introspection
|
|
45
46
|
|
|
46
47
|
### Struct Methods
|
|
47
48
|
|
|
48
|
-
- `obj.struct_dump_json()` — serialize to JSON bytes
|
|
49
|
-
- `obj.struct_dump()` — convert to built-in Python types
|
|
50
|
-
- `obj.struct_to_dict()` — shallow field dict
|
|
51
|
-
- `obj.struct_to_tuple()` — shallow field tuple
|
|
49
|
+
- `obj.struct_dump_json(*, enc_hook=None, decimal_format=None, uuid_format=None, order=None)` — serialize to JSON bytes
|
|
50
|
+
- `obj.struct_dump()` — convert to built-in Python types (uses `encode_name` for keys)
|
|
52
51
|
- `obj.struct_force_setattr(name, value)` — set attr on frozen struct
|
|
53
|
-
- `obj.
|
|
54
|
-
- `cls.struct_validate_json(buf)` — deserialize from JSON
|
|
55
|
-
- `cls.
|
|
56
|
-
|
|
57
|
-
|
|
52
|
+
- `obj.struct_validate_self()` — validate field values against types + constraints
|
|
53
|
+
- `cls.struct_validate_json(buf, *, strict=True, dec_hook=None)` — deserialize from JSON
|
|
54
|
+
- `cls.struct_validate(obj, *, strict=True, from_attributes=False, dec_hook=None)` — convert built-in types to struct
|
|
55
|
+
|
|
56
|
+
### Dict & Iteration Protocol
|
|
57
|
+
|
|
58
|
+
Struct instances support the mapping protocol:
|
|
59
|
+
- `dict(p)` — shallow dict of Python field names to values (iterates `(name, value)` pairs)
|
|
60
|
+
- `list(p)` / `iter(p)` — iterate `(name, value)` 2-tuples in declaration order
|
|
58
61
|
|
|
59
62
|
## Gotchas
|
|
60
63
|
|
|
61
|
-
- `pytest-randomly` shuffles test order
|
|
62
64
|
- `make test-lf` reinstalls the C extension before running (last-failed first)
|
|
@@ -13,6 +13,10 @@ docs: ## build docs
|
|
|
13
13
|
rm -rf .doctrees site
|
|
14
14
|
uv run --group docs sphinx-build -d .doctrees -b html docs site --fail-on-warning
|
|
15
15
|
|
|
16
|
+
.PHONY: wheels
|
|
17
|
+
wheels: ## build wheels
|
|
18
|
+
uvx --from cibuildwheel==4.1.1 cibuildwheel
|
|
19
|
+
|
|
16
20
|
##@ Quality
|
|
17
21
|
.PHONY: test-cov
|
|
18
22
|
test-cov: ## Run tests with coverage
|
|
@@ -22,6 +26,10 @@ test-cov: ## Run tests with coverage
|
|
|
22
26
|
test-lf: ## Run tests in current Python
|
|
23
27
|
uv run --reinstall pytest --lf
|
|
24
28
|
|
|
29
|
+
.PHONY: test-doc
|
|
30
|
+
test-doc: ## Run doctests
|
|
31
|
+
uv run pytest --doctest-modules --pyargs structtype
|
|
32
|
+
|
|
25
33
|
.PHONY: test-all
|
|
26
34
|
test-all: ## Run tests in all supporte Python versions
|
|
27
35
|
for py_v in $(PY_VERSIONS); do \
|
|
@@ -49,8 +57,7 @@ format: ## Format files using ruff format
|
|
|
49
57
|
##@ Benchmark
|
|
50
58
|
.PHONY: bench
|
|
51
59
|
bench: ## run benchmarks
|
|
52
|
-
uv run
|
|
53
|
-
uv run --group bench benchmarks/bench_libs.py
|
|
60
|
+
uv run benchmarks/bench_libs.py
|
|
54
61
|
|
|
55
62
|
##@ Utility
|
|
56
63
|
.PHONY: clean
|
|
@@ -46,17 +46,6 @@ dev = [
|
|
|
46
46
|
"pytest>=9",
|
|
47
47
|
"pytest-coverage>=0.0",
|
|
48
48
|
]
|
|
49
|
-
bench = [
|
|
50
|
-
"cattrs==25.3.0",
|
|
51
|
-
"mashumaro==3.17",
|
|
52
|
-
"msgspec",
|
|
53
|
-
"orjson==3.11.4",
|
|
54
|
-
"pydantic==2.12.4",
|
|
55
|
-
"pysimdjson==7.0.2",
|
|
56
|
-
"python-rapidjson==1.22",
|
|
57
|
-
"requests",
|
|
58
|
-
"ujson==5.11.0",
|
|
59
|
-
]
|
|
60
49
|
docs = [
|
|
61
50
|
"furo",
|
|
62
51
|
"ipython",
|
|
@@ -65,11 +54,6 @@ docs = [
|
|
|
65
54
|
"sphinx-copybutton",
|
|
66
55
|
"sphinx-design",
|
|
67
56
|
]
|
|
68
|
-
hooks = [
|
|
69
|
-
"codespell==2.4.1",
|
|
70
|
-
"prek>=0.2.13",
|
|
71
|
-
"ruff==0.15.16",
|
|
72
|
-
]
|
|
73
57
|
|
|
74
58
|
[build-system]
|
|
75
59
|
requires = [
|
|
@@ -96,3 +80,12 @@ parentdir_prefix_version = "structtype-"
|
|
|
96
80
|
|
|
97
81
|
[tool.uv.config-settings]
|
|
98
82
|
editable_mode = "compat"
|
|
83
|
+
|
|
84
|
+
[tool.cibuildwheel]
|
|
85
|
+
build = "cp3*"
|
|
86
|
+
skip = ["pp*", "*-manylinux_i686", "*-musllinux*", "*-win32"]
|
|
87
|
+
enable = ["cpython-prerelease"]
|
|
88
|
+
test-command = "pip install pytest>=9 && pytest {project}/tests"
|
|
89
|
+
|
|
90
|
+
[tool.ruff]
|
|
91
|
+
target-version = "py310"
|
|
@@ -36,6 +36,12 @@ if DEBUG:
|
|
|
36
36
|
extra_compile_args.extend(["-O0", "-g", "-UNDEBUG"])
|
|
37
37
|
elif sys.platform != "win32":
|
|
38
38
|
extra_compile_args.extend(["-g0"])
|
|
39
|
+
extra_compile_args.extend([
|
|
40
|
+
"-Wextra",
|
|
41
|
+
"-Wno-unused-parameter",
|
|
42
|
+
"-Wno-missing-field-initializers",
|
|
43
|
+
"-Wno-cast-function-type",
|
|
44
|
+
])
|
|
39
45
|
if sys.platform == "darwin" and platform.machine().lower() == "arm64":
|
|
40
46
|
extra_compile_args.extend(["-flto=thin"])
|
|
41
47
|
extra_link_args.extend(["-flto=thin"])
|
|
@@ -53,15 +59,15 @@ libraries = []
|
|
|
53
59
|
if sys.platform != "win32":
|
|
54
60
|
libraries.append("m")
|
|
55
61
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
ext_modules = [
|
|
63
|
+
Extension(
|
|
64
|
+
"structtype._core",
|
|
65
|
+
[os.path.join("src", "structtype", "_core.c")],
|
|
66
|
+
libraries=libraries,
|
|
67
|
+
extra_compile_args=extra_compile_args,
|
|
68
|
+
extra_link_args=extra_link_args,
|
|
69
|
+
)
|
|
70
|
+
]
|
|
65
71
|
|
|
66
72
|
setup(
|
|
67
73
|
ext_modules=ext_modules,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from ._adapter import StrAdapter, StructAdapter
|
|
1
2
|
from ._core import (
|
|
2
3
|
NODEFAULT,
|
|
3
4
|
UNSET,
|
|
@@ -11,7 +12,6 @@ from ._core import (
|
|
|
11
12
|
UnsetType,
|
|
12
13
|
ValidationError,
|
|
13
14
|
)
|
|
14
|
-
from ._adapter import StructAdapter
|
|
15
15
|
from ._inspect import FieldInfo, fields
|
|
16
|
-
from ._json_schema import json_schema,
|
|
16
|
+
from ._json_schema import json_schema, json_schema_components, json_schema_dump
|
|
17
17
|
from ._version import __version__
|
|
@@ -1,23 +1,11 @@
|
|
|
1
1
|
import enum
|
|
2
|
-
from collections.abc import Callable, Iterable, Mapping
|
|
2
|
+
from collections.abc import Callable, Iterable, Iterator, Mapping
|
|
3
3
|
from inspect import Signature
|
|
4
|
-
from typing import
|
|
5
|
-
Any,
|
|
6
|
-
ClassVar,
|
|
7
|
-
Final,
|
|
8
|
-
Literal,
|
|
9
|
-
Optional,
|
|
10
|
-
Tuple,
|
|
11
|
-
Type,
|
|
12
|
-
TypeVar,
|
|
13
|
-
Union,
|
|
14
|
-
final,
|
|
15
|
-
overload,
|
|
16
|
-
)
|
|
4
|
+
from typing import Any, ClassVar, Final, Literal, TypeAlias, TypeVar, final, overload
|
|
17
5
|
|
|
18
|
-
from typing_extensions import Buffer, Self,
|
|
6
|
+
from typing_extensions import Buffer, Self, dataclass_transform
|
|
19
7
|
|
|
20
|
-
from . import
|
|
8
|
+
from . import StructConfig
|
|
21
9
|
|
|
22
10
|
# PEP 673 explicitly rejects using Self in metaclass definitions:
|
|
23
11
|
# https://peps.python.org/pep-0673/#valid-locations-for-self
|
|
@@ -34,7 +22,7 @@ class StructMeta(type):
|
|
|
34
22
|
@property
|
|
35
23
|
def __signature__(self) -> Signature: ...
|
|
36
24
|
@property
|
|
37
|
-
def __struct_config__(self) ->
|
|
25
|
+
def __struct_config__(self) -> StructConfig: ...
|
|
38
26
|
def __new__(
|
|
39
27
|
mcls: type[_SM],
|
|
40
28
|
name: str,
|
|
@@ -85,6 +73,7 @@ class Struct(metaclass=StructMeta):
|
|
|
85
73
|
__struct_fields__: ClassVar[tuple[str, ...]]
|
|
86
74
|
__struct_config__: ClassVar[StructConfig]
|
|
87
75
|
__struct_encode_fields__: ClassVar[tuple[str, ...]]
|
|
76
|
+
__struct_defaults__: ClassVar[tuple[Any, ...]]
|
|
88
77
|
__match_args__: ClassVar[tuple[str, ...]]
|
|
89
78
|
# A default __init__ so that Structs with unknown field types
|
|
90
79
|
# won't error on every call to `__init__`
|
|
@@ -114,25 +103,30 @@ class Struct(metaclass=StructMeta):
|
|
|
114
103
|
validate_on_init: bool = False,
|
|
115
104
|
) -> None: ...
|
|
116
105
|
def __rich_repr__(self) -> list[tuple[str, Any]]: ...
|
|
106
|
+
def __copy__(self) -> Self: ...
|
|
107
|
+
def __reduce__(self) -> tuple: ...
|
|
117
108
|
def __replace__(self, **changes: Any) -> Self: ...
|
|
109
|
+
def __iter__(self) -> Iterator[tuple[str, Any]]: ...
|
|
118
110
|
def struct_dump_json(
|
|
119
111
|
self,
|
|
120
112
|
*,
|
|
121
113
|
enc_hook: Callable[[Any], Any] | None = None,
|
|
122
|
-
decimal_format: Literal["string", "number"]
|
|
114
|
+
decimal_format: Literal["string", "number"]
|
|
115
|
+
| Callable[[Any], Any]
|
|
116
|
+
| None = None,
|
|
123
117
|
uuid_format: Literal["canonical", "hex"] | None = None,
|
|
124
118
|
order: Literal["deterministic", "sorted"] | None = None,
|
|
125
119
|
) -> bytes: ...
|
|
126
|
-
def struct_dump(
|
|
127
|
-
def struct_to_dict(self) -> dict[str, Any]: ...
|
|
128
|
-
def struct_to_tuple(self) -> tuple[Any, ...]: ...
|
|
129
|
-
def struct_force_setattr(self, name: str, value: Any) -> None: ...
|
|
130
|
-
def struct_check(
|
|
120
|
+
def struct_dump(
|
|
131
121
|
self,
|
|
132
122
|
*,
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
123
|
+
enc_hook: Callable[[Any], Any] | None = None,
|
|
124
|
+
order: Literal["deterministic", "sorted"] | None = None,
|
|
125
|
+
str_keys: bool = False,
|
|
126
|
+
builtin_types: Iterable[type] | None = None,
|
|
127
|
+
) -> dict[str, Any] | list[Any]: ...
|
|
128
|
+
def struct_force_setattr(self, name: str, value: Any) -> None: ...
|
|
129
|
+
def struct_validate_self(self) -> None: ...
|
|
136
130
|
@classmethod
|
|
137
131
|
def struct_validate_json(
|
|
138
132
|
cls: type[_T],
|
|
@@ -150,24 +144,6 @@ class Struct(metaclass=StructMeta):
|
|
|
150
144
|
from_attributes: bool = False,
|
|
151
145
|
dec_hook: Callable[[type[Any], Any], Any] | None = None,
|
|
152
146
|
) -> _T: ...
|
|
153
|
-
@classmethod
|
|
154
|
-
def struct_validate_jsonln(
|
|
155
|
-
cls: type[_T],
|
|
156
|
-
buf: str | Buffer,
|
|
157
|
-
*,
|
|
158
|
-
strict: bool = True,
|
|
159
|
-
dec_hook: Callable[[type[Any], Any], Any] | None = None,
|
|
160
|
-
) -> list[_T]: ...
|
|
161
|
-
@classmethod
|
|
162
|
-
def struct_dump_jsonln(
|
|
163
|
-
cls,
|
|
164
|
-
items: Iterable[Any],
|
|
165
|
-
*,
|
|
166
|
-
enc_hook: Callable[[Any], Any] | None = None,
|
|
167
|
-
decimal_format: Literal["string", "number"] | Callable[[Any], Any] | None = None,
|
|
168
|
-
uuid_format: Literal["canonical", "hex"] | None = None,
|
|
169
|
-
order: Literal["deterministic", "sorted"] | None = None,
|
|
170
|
-
) -> bytes: ...
|
|
171
147
|
|
|
172
148
|
# Lie and say `Raw` is a subclass of `bytes`, so mypy will accept it in most
|
|
173
149
|
# places where an object that implements the buffer protocol is valid
|
|
@@ -340,7 +316,9 @@ class StructAdapter:
|
|
|
340
316
|
obj: Any,
|
|
341
317
|
*,
|
|
342
318
|
enc_hook: Callable[[Any], Any] | None = None,
|
|
343
|
-
decimal_format: Literal["string", "number"]
|
|
319
|
+
decimal_format: Literal["string", "number"]
|
|
320
|
+
| Callable[[Any], Any]
|
|
321
|
+
| None = None,
|
|
344
322
|
uuid_format: Literal["canonical", "hex"] | None = None,
|
|
345
323
|
order: Literal["deterministic", "sorted"] | None = None,
|
|
346
324
|
) -> bytes: ...
|
|
@@ -352,7 +330,18 @@ class StructAdapter:
|
|
|
352
330
|
dec_hook: Callable[[type[Any], Any], Any] | None = None,
|
|
353
331
|
from_attributes: bool = False,
|
|
354
332
|
) -> Any: ...
|
|
355
|
-
def struct_dump(
|
|
333
|
+
def struct_dump(
|
|
334
|
+
self,
|
|
335
|
+
obj: Any,
|
|
336
|
+
*,
|
|
337
|
+
enc_hook: Callable[[Any], Any] | None = None,
|
|
338
|
+
order: Literal["deterministic", "sorted"] | None = None,
|
|
339
|
+
str_keys: bool = False,
|
|
340
|
+
builtin_types: Iterable[type] | None = None,
|
|
341
|
+
) -> Any: ...
|
|
342
|
+
|
|
343
|
+
class StrAdapter:
|
|
344
|
+
def __new__(cls, type: type[Any]) -> type[str]: ...
|
|
356
345
|
|
|
357
346
|
class EncodeError(ValueError): ...
|
|
358
347
|
class DecodeError(ValueError): ...
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from ._core import _dump, _json_decode, _json_encode, _validate
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class StructAdapter:
|
|
7
|
+
"""Adapter for validating and serializing types without subclassing ``Struct``.
|
|
8
|
+
|
|
9
|
+
Useful when you want to validate or serialize plain Python types
|
|
10
|
+
(e.g. ``list[int]``) without defining a full ``Struct`` subclass.
|
|
11
|
+
|
|
12
|
+
>>> from structtype import StructAdapter
|
|
13
|
+
>>> adapter = StructAdapter(list[int])
|
|
14
|
+
>>> adapter.struct_validate_json(b"[1, 2, 3]")
|
|
15
|
+
[1, 2, 3]
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
__slots__ = ("_type",)
|
|
19
|
+
|
|
20
|
+
def __init__(self, type: Any):
|
|
21
|
+
self._type = type
|
|
22
|
+
|
|
23
|
+
def struct_validate_json(self, buf, *, strict=True, dec_hook=None):
|
|
24
|
+
"""Validate JSON bytes and decode into the adapter's type.
|
|
25
|
+
|
|
26
|
+
Parameters
|
|
27
|
+
----------
|
|
28
|
+
buf : str or bytes
|
|
29
|
+
The JSON message to decode.
|
|
30
|
+
strict : bool, optional
|
|
31
|
+
If True (default), unmatched fields cause an error.
|
|
32
|
+
dec_hook : callable, optional
|
|
33
|
+
A callback for customizing decoding of specific types.
|
|
34
|
+
"""
|
|
35
|
+
return _json_decode(buf, type=self._type, strict=strict, dec_hook=dec_hook)
|
|
36
|
+
|
|
37
|
+
def struct_dump_json(
|
|
38
|
+
self, obj, *, enc_hook=None, decimal_format=None, uuid_format=None, order=None
|
|
39
|
+
):
|
|
40
|
+
"""Encode a validated object to JSON bytes.
|
|
41
|
+
|
|
42
|
+
Parameters
|
|
43
|
+
----------
|
|
44
|
+
obj : Any
|
|
45
|
+
A value to encode. Must match the adapter's type.
|
|
46
|
+
enc_hook : callable, optional
|
|
47
|
+
A callback for customizing encoding of specific types.
|
|
48
|
+
decimal_format : str or callable, optional
|
|
49
|
+
Controls how ``Decimal`` values are encoded.
|
|
50
|
+
uuid_format : str, optional
|
|
51
|
+
Controls how ``UUID`` values are encoded.
|
|
52
|
+
order : str, optional
|
|
53
|
+
Determines key ordering in JSON objects.
|
|
54
|
+
"""
|
|
55
|
+
return _json_encode(
|
|
56
|
+
obj,
|
|
57
|
+
enc_hook=enc_hook,
|
|
58
|
+
decimal_format=decimal_format,
|
|
59
|
+
uuid_format=uuid_format,
|
|
60
|
+
order=order,
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
def struct_validate(
|
|
64
|
+
self, obj, *, strict=True, dec_hook=None, from_attributes=False
|
|
65
|
+
):
|
|
66
|
+
"""Validate a Python object against the adapter's type.
|
|
67
|
+
|
|
68
|
+
Parameters
|
|
69
|
+
----------
|
|
70
|
+
obj : Any
|
|
71
|
+
A Python object to validate and convert.
|
|
72
|
+
strict : bool, optional
|
|
73
|
+
If True (default), unmatched fields cause an error.
|
|
74
|
+
dec_hook : callable, optional
|
|
75
|
+
A callback for customizing decoding of specific types.
|
|
76
|
+
from_attributes : bool, optional
|
|
77
|
+
If True, accept objects with attributes instead of dict keys.
|
|
78
|
+
"""
|
|
79
|
+
return _validate(
|
|
80
|
+
obj,
|
|
81
|
+
self._type,
|
|
82
|
+
strict=strict,
|
|
83
|
+
dec_hook=dec_hook,
|
|
84
|
+
from_attributes=from_attributes,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
def struct_dump(
|
|
88
|
+
self, obj, *, enc_hook=None, order=None, str_keys=False, builtin_types=None
|
|
89
|
+
):
|
|
90
|
+
"""Convert a validated object to built-in Python types (``dict``, ``list``, etc.)."""
|
|
91
|
+
return _dump(
|
|
92
|
+
obj,
|
|
93
|
+
builtin_types=builtin_types,
|
|
94
|
+
str_keys=str_keys,
|
|
95
|
+
enc_hook=enc_hook,
|
|
96
|
+
order=order,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class StrAdapter:
|
|
101
|
+
"""Create a ``str`` subclass wrapper for validating a type during
|
|
102
|
+
structtype serialization.
|
|
103
|
+
|
|
104
|
+
Wraps a type that has a single-argument string constructor
|
|
105
|
+
(e.g. ``HttpUrl``, ``EmailStr``, ``IPv4Address``) into a ``str``
|
|
106
|
+
subclass. The wrapped value is stored as a string but validated by
|
|
107
|
+
calling ``typ(value)`` on construction. During structtype
|
|
108
|
+
validation and serialization, the wrapper is treated as a native
|
|
109
|
+
``str``.
|
|
110
|
+
|
|
111
|
+
>>> from structtype import StrAdapter, Struct
|
|
112
|
+
>>> from ipaddress import IPv4Address
|
|
113
|
+
>>>
|
|
114
|
+
>>> class Config(Struct):
|
|
115
|
+
... ip: StrAdapter(IPv4Address)
|
|
116
|
+
"""
|
|
117
|
+
|
|
118
|
+
__slots__ = ()
|
|
119
|
+
|
|
120
|
+
def __new__(cls, typ):
|
|
121
|
+
return type(
|
|
122
|
+
f"_Wrapped_{typ.__name__}",
|
|
123
|
+
(str,),
|
|
124
|
+
{
|
|
125
|
+
"__slots__": (),
|
|
126
|
+
"__new__": lambda self, v: str.__new__(self, str(typ(v))),
|
|
127
|
+
},
|
|
128
|
+
)
|