serializable 1.2.0__tar.gz → 1.2.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.
- {serializable-1.2.0 → serializable-1.2.1}/PKG-INFO +5 -1
- {serializable-1.2.0 → serializable-1.2.1}/pyproject.toml +13 -0
- {serializable-1.2.0 → serializable-1.2.1}/serializable/dataclass_serializable.py +10 -6
- {serializable-1.2.0 → serializable-1.2.1}/serializable/helpers.py +13 -9
- serializable-1.2.1/serializable/py.typed +0 -0
- {serializable-1.2.0 → serializable-1.2.1}/serializable/serializable.py +21 -15
- {serializable-1.2.0 → serializable-1.2.1}/serializable/version.py +1 -1
- {serializable-1.2.0 → serializable-1.2.1}/serializable.egg-info/PKG-INFO +5 -1
- {serializable-1.2.0 → serializable-1.2.1}/serializable.egg-info/SOURCES.txt +3 -1
- {serializable-1.2.0 → serializable-1.2.1}/serializable.egg-info/requires.txt +1 -0
- serializable-1.2.1/tests/test_typing.py +48 -0
- {serializable-1.2.0 → serializable-1.2.1}/LICENSE +0 -0
- {serializable-1.2.0 → serializable-1.2.1}/README.md +0 -0
- {serializable-1.2.0 → serializable-1.2.1}/serializable/__init__.py +0 -0
- {serializable-1.2.0 → serializable-1.2.1}/serializable/primitive_types.py +0 -0
- {serializable-1.2.0 → serializable-1.2.1}/serializable.egg-info/dependency_links.txt +0 -0
- {serializable-1.2.0 → serializable-1.2.1}/serializable.egg-info/top_level.txt +0 -0
- {serializable-1.2.0 → serializable-1.2.1}/setup.cfg +0 -0
- {serializable-1.2.0 → serializable-1.2.1}/setup.py +0 -0
- {serializable-1.2.0 → serializable-1.2.1}/tests/test_class.py +0 -0
- {serializable-1.2.0 → serializable-1.2.1}/tests/test_dataclass_serializable.py +0 -0
- {serializable-1.2.0 → serializable-1.2.1}/tests/test_default_to_dict_implementation.py +0 -0
- {serializable-1.2.0 → serializable-1.2.1}/tests/test_function.py +0 -0
- {serializable-1.2.0 → serializable-1.2.1}/tests/test_keyword_aliases.py +0 -0
- {serializable-1.2.0 → serializable-1.2.1}/tests/test_namedtuple.py +0 -0
- {serializable-1.2.0 → serializable-1.2.1}/tests/test_nesting.py +0 -0
- {serializable-1.2.0 → serializable-1.2.1}/tests/test_object.py +0 -0
- {serializable-1.2.0 → serializable-1.2.1}/tests/test_pickle.py +0 -0
- {serializable-1.2.0 → serializable-1.2.1}/tests/test_primitive_values.py +0 -0
- {serializable-1.2.0 → serializable-1.2.1}/tests/test_set.py +0 -0
- {serializable-1.2.0 → serializable-1.2.1}/tests/test_tuple.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: serializable
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.1
|
|
4
4
|
Summary: Base class with serialization helpers for user-defined Python objects
|
|
5
5
|
Author-email: Alex Rubinsteyn <alex.rubinsteyn@unc.edu>
|
|
6
6
|
License: Apache License
|
|
@@ -217,6 +217,9 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
217
217
|
Classifier: Programming Language :: Python :: 3.10
|
|
218
218
|
Classifier: Programming Language :: Python :: 3.11
|
|
219
219
|
Classifier: Programming Language :: Python :: 3.12
|
|
220
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
221
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
222
|
+
Classifier: Typing :: Typed
|
|
220
223
|
Requires-Python: >=3.9
|
|
221
224
|
Description-Content-Type: text/markdown
|
|
222
225
|
License-File: LICENSE
|
|
@@ -226,6 +229,7 @@ Provides-Extra: dev
|
|
|
226
229
|
Requires-Dist: pytest; extra == "dev"
|
|
227
230
|
Requires-Dist: pytest-cov; extra == "dev"
|
|
228
231
|
Requires-Dist: ruff; extra == "dev"
|
|
232
|
+
Requires-Dist: mypy; extra == "dev"
|
|
229
233
|
Requires-Dist: coveralls; extra == "dev"
|
|
230
234
|
Requires-Dist: build; extra == "dev"
|
|
231
235
|
Requires-Dist: twine; extra == "dev"
|
|
@@ -22,6 +22,9 @@ classifiers = [
|
|
|
22
22
|
"Programming Language :: Python :: 3.10",
|
|
23
23
|
"Programming Language :: Python :: 3.11",
|
|
24
24
|
"Programming Language :: Python :: 3.12",
|
|
25
|
+
"Programming Language :: Python :: 3.13",
|
|
26
|
+
"Programming Language :: Python :: 3.14",
|
|
27
|
+
"Typing :: Typed",
|
|
25
28
|
]
|
|
26
29
|
requires-python = ">=3.9"
|
|
27
30
|
dependencies = [
|
|
@@ -34,6 +37,7 @@ dev = [
|
|
|
34
37
|
"pytest",
|
|
35
38
|
"pytest-cov",
|
|
36
39
|
"ruff",
|
|
40
|
+
"mypy",
|
|
37
41
|
"coveralls",
|
|
38
42
|
"build",
|
|
39
43
|
"twine",
|
|
@@ -49,6 +53,9 @@ version = {attr = "serializable.version.__version__"}
|
|
|
49
53
|
[tool.setuptools.packages.find]
|
|
50
54
|
include = ["serializable*"]
|
|
51
55
|
|
|
56
|
+
[tool.setuptools.package-data]
|
|
57
|
+
serializable = ["py.typed"]
|
|
58
|
+
|
|
52
59
|
[tool.ruff]
|
|
53
60
|
target-version = "py39"
|
|
54
61
|
line-length = 100
|
|
@@ -81,6 +88,7 @@ ignore = [
|
|
|
81
88
|
"B905", # zip() without explicit strict
|
|
82
89
|
"SIM108", # use ternary operator instead of if-else
|
|
83
90
|
"UP007", # use X | Y for type unions (need Python 3.10+)
|
|
91
|
+
"UP045", # use X | None for Optional (need Python 3.10+)
|
|
84
92
|
]
|
|
85
93
|
|
|
86
94
|
[tool.ruff.lint.per-file-ignores]
|
|
@@ -96,6 +104,11 @@ ignore = [
|
|
|
96
104
|
[tool.ruff.lint.isort]
|
|
97
105
|
known-first-party = ["serializable"]
|
|
98
106
|
|
|
107
|
+
[tool.mypy]
|
|
108
|
+
# Annotations are never evaluated at runtime (`from __future__ import annotations`),
|
|
109
|
+
# so checking them as 3.10 also covers 3.9, which mypy 2 can no longer target.
|
|
110
|
+
python_version = "3.10"
|
|
111
|
+
|
|
99
112
|
[tool.pytest.ini_options]
|
|
100
113
|
testpaths = ["tests"]
|
|
101
114
|
python_files = "test_*.py"
|
|
@@ -40,11 +40,14 @@ Example::
|
|
|
40
40
|
|
|
41
41
|
from __future__ import annotations
|
|
42
42
|
|
|
43
|
+
from collections.abc import Mapping
|
|
43
44
|
from dataclasses import fields
|
|
44
|
-
from typing import Any, ClassVar
|
|
45
|
+
from typing import Any, ClassVar, Optional, TypeVar
|
|
45
46
|
|
|
46
47
|
from .helpers import from_json, to_json
|
|
47
48
|
|
|
49
|
+
_T = TypeVar("_T", bound="DataclassSerializable")
|
|
50
|
+
|
|
48
51
|
|
|
49
52
|
class DataclassSerializable:
|
|
50
53
|
"""Mixin providing ``to_dict`` / ``from_dict`` / ``to_json`` / ``from_json``
|
|
@@ -57,16 +60,17 @@ class DataclassSerializable:
|
|
|
57
60
|
``Serializable``.
|
|
58
61
|
"""
|
|
59
62
|
|
|
60
|
-
_SERIALIZABLE_KEYWORD_ALIASES: ClassVar[dict[str, str
|
|
63
|
+
_SERIALIZABLE_KEYWORD_ALIASES: ClassVar[dict[str, Optional[str]]] = {}
|
|
61
64
|
|
|
62
65
|
def to_dict(self) -> dict[str, Any]:
|
|
63
66
|
"""Return a dict mapping each dataclass field name to its current
|
|
64
67
|
value. Keys match the ``__init__`` keyword arguments, so
|
|
65
68
|
``cls(**obj.to_dict())`` reconstructs an equal instance."""
|
|
66
|
-
|
|
69
|
+
# subclasses are dataclasses, the mixin itself isn't
|
|
70
|
+
return {f.name: getattr(self, f.name) for f in fields(self)} # type: ignore[arg-type]
|
|
67
71
|
|
|
68
72
|
@classmethod
|
|
69
|
-
def from_dict(cls, state_dict:
|
|
73
|
+
def from_dict(cls: type[_T], state_dict: Mapping[str, Any]) -> _T:
|
|
70
74
|
"""Reconstruct an instance from a ``to_dict``-shaped dictionary,
|
|
71
75
|
applying ``_SERIALIZABLE_KEYWORD_ALIASES`` for backwards compat."""
|
|
72
76
|
kwargs = dict(state_dict)
|
|
@@ -83,10 +87,10 @@ class DataclassSerializable:
|
|
|
83
87
|
return to_json(self)
|
|
84
88
|
|
|
85
89
|
@classmethod
|
|
86
|
-
def from_json(cls, json_string: str):
|
|
90
|
+
def from_json(cls: type[_T], json_string: str) -> _T:
|
|
87
91
|
return from_json(json_string)
|
|
88
92
|
|
|
89
|
-
def __reduce__(self):
|
|
93
|
+
def __reduce__(self) -> tuple[Any, ...]:
|
|
90
94
|
"""Pickle via the same to_dict / from_dict path used for JSON so
|
|
91
95
|
pickled objects round-trip even when field order or internal
|
|
92
96
|
representation changes between releases. Pickles written before
|
|
@@ -15,15 +15,18 @@ Helper functions for deconstructing classes, functions, and user-defined
|
|
|
15
15
|
objects into serializable types.
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
18
20
|
from functools import lru_cache
|
|
19
21
|
from types import BuiltinFunctionType, FunctionType
|
|
22
|
+
from typing import Any, Union
|
|
20
23
|
|
|
21
|
-
import simplejson as json
|
|
24
|
+
import simplejson as json # type: ignore[import-untyped]
|
|
22
25
|
|
|
23
26
|
from .primitive_types import PRIMITIVE_TYPES
|
|
24
27
|
|
|
25
28
|
|
|
26
|
-
def init_arg_names(obj):
|
|
29
|
+
def init_arg_names(obj: Any) -> tuple[str, ...]:
|
|
27
30
|
"""
|
|
28
31
|
Names of the positional arguments to the __init__ method of this
|
|
29
32
|
object's class (excluding self).
|
|
@@ -31,7 +34,8 @@ def init_arg_names(obj):
|
|
|
31
34
|
Keyword-only arguments are deliberately excluded, so a class can accept
|
|
32
35
|
constructor options which aren't part of its serialized state.
|
|
33
36
|
"""
|
|
34
|
-
|
|
37
|
+
# mypy doesn't consider classes Hashable
|
|
38
|
+
return _class_init_arg_names(type(obj)) # type: ignore[arg-type]
|
|
35
39
|
|
|
36
40
|
|
|
37
41
|
# Cached per class since this is called on every to_dict/__eq__/__hash__ of
|
|
@@ -53,7 +57,7 @@ def _class_init_arg_names(cls):
|
|
|
53
57
|
return init_code.co_varnames[1 : init_code.co_argcount]
|
|
54
58
|
|
|
55
59
|
|
|
56
|
-
def simple_object_to_dict(self):
|
|
60
|
+
def simple_object_to_dict(self: object) -> dict[str, Any]:
|
|
57
61
|
return {name: getattr(self, name) for name in init_arg_names(self)}
|
|
58
62
|
|
|
59
63
|
|
|
@@ -246,7 +250,7 @@ def list_to_serializable_repr(x):
|
|
|
246
250
|
return [to_serializable_repr(element) for element in x]
|
|
247
251
|
|
|
248
252
|
|
|
249
|
-
def to_dict(obj):
|
|
253
|
+
def to_dict(obj: Any) -> dict[str, Any]:
|
|
250
254
|
"""
|
|
251
255
|
If value isn't a primitive scalar or collection then it needs to
|
|
252
256
|
either implement to_dict (instances of Serializable) or have member
|
|
@@ -262,7 +266,7 @@ def to_dict(obj):
|
|
|
262
266
|
raise ValueError(f"Cannot convert {obj} : {type(obj)} to dictionary") from exc
|
|
263
267
|
|
|
264
268
|
|
|
265
|
-
def to_serializable_repr(x):
|
|
269
|
+
def to_serializable_repr(x: Any) -> Any:
|
|
266
270
|
"""
|
|
267
271
|
Convert an instance of Serializable or a primitive collection containing
|
|
268
272
|
such instances into serializable types.
|
|
@@ -288,7 +292,7 @@ def to_serializable_repr(x):
|
|
|
288
292
|
return state_dictionary
|
|
289
293
|
|
|
290
294
|
|
|
291
|
-
def from_serializable_repr(x):
|
|
295
|
+
def from_serializable_repr(x: Any) -> Any:
|
|
292
296
|
"""
|
|
293
297
|
Inverse of to_serializable_repr. Does not modify `x`.
|
|
294
298
|
"""
|
|
@@ -302,7 +306,7 @@ def from_serializable_repr(x):
|
|
|
302
306
|
raise TypeError(f"Cannot convert {x} : {type(x)} from serializable representation to object")
|
|
303
307
|
|
|
304
308
|
|
|
305
|
-
def to_json(x):
|
|
309
|
+
def to_json(x: Any) -> str:
|
|
306
310
|
"""
|
|
307
311
|
Returns JSON representation of a given Serializable instance or
|
|
308
312
|
other primitive object.
|
|
@@ -310,7 +314,7 @@ def to_json(x):
|
|
|
310
314
|
return json.dumps(to_serializable_repr(x))
|
|
311
315
|
|
|
312
316
|
|
|
313
|
-
def from_json(json_string):
|
|
317
|
+
def from_json(json_string: Union[str, bytes]) -> Any:
|
|
314
318
|
"""
|
|
315
319
|
Inverse of to_json. Objects are reconstructed bottom-up while parsing,
|
|
316
320
|
equivalent to (but faster than) from_serializable_repr(json.loads(...)).
|
|
File without changes
|
|
@@ -11,10 +11,16 @@
|
|
|
11
11
|
# limitations under the License.
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
from
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import os
|
|
17
|
+
from collections.abc import Mapping
|
|
18
|
+
from typing import Any, ClassVar, Optional, TypeVar, Union
|
|
15
19
|
|
|
16
20
|
from .helpers import from_json, simple_object_to_dict, to_json
|
|
17
21
|
|
|
22
|
+
_T = TypeVar("_T", bound="Serializable")
|
|
23
|
+
|
|
18
24
|
|
|
19
25
|
class Serializable:
|
|
20
26
|
"""
|
|
@@ -24,17 +30,17 @@ class Serializable:
|
|
|
24
30
|
Relies on the keys of to_dict() matching the arguments to __init__.
|
|
25
31
|
"""
|
|
26
32
|
|
|
27
|
-
def __str__(self):
|
|
33
|
+
def __str__(self) -> str:
|
|
28
34
|
fields = ", ".join(f"{k}={v}" for (k, v) in self.to_dict().items())
|
|
29
35
|
return f"{self.__class__.__name__}({fields})"
|
|
30
36
|
|
|
31
|
-
def __repr__(self):
|
|
37
|
+
def __repr__(self) -> str:
|
|
32
38
|
return str(self)
|
|
33
39
|
|
|
34
|
-
def __eq__(self, other):
|
|
40
|
+
def __eq__(self, other) -> bool:
|
|
35
41
|
return self.__class__ is other.__class__ and self.to_dict() == other.to_dict()
|
|
36
42
|
|
|
37
|
-
def to_dict(self):
|
|
43
|
+
def to_dict(self) -> dict[str, Any]:
|
|
38
44
|
"""
|
|
39
45
|
Returns a dictionary which can be used to reconstruct an instance
|
|
40
46
|
of a derived class (typically by matching args to __init__). The values
|
|
@@ -49,11 +55,11 @@ class Serializable:
|
|
|
49
55
|
"""
|
|
50
56
|
return simple_object_to_dict(self)
|
|
51
57
|
|
|
52
|
-
def __hash__(self):
|
|
58
|
+
def __hash__(self) -> int:
|
|
53
59
|
return hash(tuple(sorted(self.to_dict().items())))
|
|
54
60
|
|
|
55
61
|
@classmethod
|
|
56
|
-
def _reconstruct_nested_objects(cls, state_dict):
|
|
62
|
+
def _reconstruct_nested_objects(cls, state_dict: dict[str, Any]) -> dict[str, Any]:
|
|
57
63
|
"""
|
|
58
64
|
Nested serializable objects will be represented as dictionaries so we
|
|
59
65
|
allow manual reconstruction of those objects in this method.
|
|
@@ -64,10 +70,10 @@ class Serializable:
|
|
|
64
70
|
|
|
65
71
|
# dictionary mapping old keywords to either new names or
|
|
66
72
|
# None if the keyword has been removed from a class
|
|
67
|
-
_SERIALIZABLE_KEYWORD_ALIASES: ClassVar[dict] = {}
|
|
73
|
+
_SERIALIZABLE_KEYWORD_ALIASES: ClassVar[dict[str, Optional[str]]] = {}
|
|
68
74
|
|
|
69
75
|
@classmethod
|
|
70
|
-
def _update_kwargs(cls, kwargs):
|
|
76
|
+
def _update_kwargs(cls, kwargs: dict[str, Any]) -> dict[str, Any]:
|
|
71
77
|
"""
|
|
72
78
|
Rename any old keyword arguments to preserve backwards compatibility
|
|
73
79
|
"""
|
|
@@ -83,7 +89,7 @@ class Serializable:
|
|
|
83
89
|
return kwargs
|
|
84
90
|
|
|
85
91
|
@classmethod
|
|
86
|
-
def from_dict(cls, state_dict):
|
|
92
|
+
def from_dict(cls: type[_T], state_dict: Mapping[str, Any]) -> _T:
|
|
87
93
|
"""
|
|
88
94
|
Given a dictionary of flattened fields (result of calling to_dict()),
|
|
89
95
|
returns an instance. Does not modify `state_dict`.
|
|
@@ -91,20 +97,20 @@ class Serializable:
|
|
|
91
97
|
state_dict = cls._reconstruct_nested_objects(dict(state_dict))
|
|
92
98
|
return cls(**cls._update_kwargs(state_dict))
|
|
93
99
|
|
|
94
|
-
def to_json(self):
|
|
100
|
+
def to_json(self) -> str:
|
|
95
101
|
"""
|
|
96
102
|
Returns a string containing a JSON representation of this object.
|
|
97
103
|
"""
|
|
98
104
|
return to_json(self)
|
|
99
105
|
|
|
100
106
|
@classmethod
|
|
101
|
-
def from_json(cls, json_string):
|
|
107
|
+
def from_json(cls: type[_T], json_string: str) -> _T:
|
|
102
108
|
"""
|
|
103
109
|
Reconstruct an instance from a JSON string.
|
|
104
110
|
"""
|
|
105
111
|
return from_json(json_string)
|
|
106
112
|
|
|
107
|
-
def write_json_file(self, path):
|
|
113
|
+
def write_json_file(self, path: Union[str, os.PathLike[str]]) -> None:
|
|
108
114
|
"""
|
|
109
115
|
Serialize this object to JSON and write it to the text file at `path`.
|
|
110
116
|
"""
|
|
@@ -112,7 +118,7 @@ class Serializable:
|
|
|
112
118
|
f.write(self.to_json())
|
|
113
119
|
|
|
114
120
|
@classmethod
|
|
115
|
-
def read_json_file(cls, path):
|
|
121
|
+
def read_json_file(cls: type[_T], path: Union[str, os.PathLike[str]]) -> _T:
|
|
116
122
|
"""
|
|
117
123
|
Construct an instance of this class from the JSON file at `path`.
|
|
118
124
|
"""
|
|
@@ -120,7 +126,7 @@ class Serializable:
|
|
|
120
126
|
json_string = f.read()
|
|
121
127
|
return cls.from_json(json_string)
|
|
122
128
|
|
|
123
|
-
def __reduce__(self):
|
|
129
|
+
def __reduce__(self) -> tuple[Any, ...]:
|
|
124
130
|
"""
|
|
125
131
|
Overriding this method directs the default pickler to reconstruct
|
|
126
132
|
this object using our from_dict method, so pickles survive the same
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: serializable
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.1
|
|
4
4
|
Summary: Base class with serialization helpers for user-defined Python objects
|
|
5
5
|
Author-email: Alex Rubinsteyn <alex.rubinsteyn@unc.edu>
|
|
6
6
|
License: Apache License
|
|
@@ -217,6 +217,9 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
217
217
|
Classifier: Programming Language :: Python :: 3.10
|
|
218
218
|
Classifier: Programming Language :: Python :: 3.11
|
|
219
219
|
Classifier: Programming Language :: Python :: 3.12
|
|
220
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
221
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
222
|
+
Classifier: Typing :: Typed
|
|
220
223
|
Requires-Python: >=3.9
|
|
221
224
|
Description-Content-Type: text/markdown
|
|
222
225
|
License-File: LICENSE
|
|
@@ -226,6 +229,7 @@ Provides-Extra: dev
|
|
|
226
229
|
Requires-Dist: pytest; extra == "dev"
|
|
227
230
|
Requires-Dist: pytest-cov; extra == "dev"
|
|
228
231
|
Requires-Dist: ruff; extra == "dev"
|
|
232
|
+
Requires-Dist: mypy; extra == "dev"
|
|
229
233
|
Requires-Dist: coveralls; extra == "dev"
|
|
230
234
|
Requires-Dist: build; extra == "dev"
|
|
231
235
|
Requires-Dist: twine; extra == "dev"
|
|
@@ -6,6 +6,7 @@ serializable/__init__.py
|
|
|
6
6
|
serializable/dataclass_serializable.py
|
|
7
7
|
serializable/helpers.py
|
|
8
8
|
serializable/primitive_types.py
|
|
9
|
+
serializable/py.typed
|
|
9
10
|
serializable/serializable.py
|
|
10
11
|
serializable/version.py
|
|
11
12
|
serializable.egg-info/PKG-INFO
|
|
@@ -24,4 +25,5 @@ tests/test_object.py
|
|
|
24
25
|
tests/test_pickle.py
|
|
25
26
|
tests/test_primitive_values.py
|
|
26
27
|
tests/test_set.py
|
|
27
|
-
tests/test_tuple.py
|
|
28
|
+
tests/test_tuple.py
|
|
29
|
+
tests/test_typing.py
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
2
|
+
# you may not use this file except in compliance with the License.
|
|
3
|
+
# You may obtain a copy of the License at
|
|
4
|
+
#
|
|
5
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
+
#
|
|
7
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
8
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
9
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
10
|
+
# See the License for the specific language governing permissions and
|
|
11
|
+
# limitations under the License.
|
|
12
|
+
|
|
13
|
+
import inspect
|
|
14
|
+
import typing
|
|
15
|
+
from dataclasses import dataclass
|
|
16
|
+
|
|
17
|
+
import pytest
|
|
18
|
+
|
|
19
|
+
from serializable import DataclassSerializable, Serializable, helpers
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Point(Serializable):
|
|
23
|
+
def __init__(self, x):
|
|
24
|
+
self.x = x
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass
|
|
28
|
+
class DataclassPoint(DataclassSerializable):
|
|
29
|
+
x: int
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def annotated_objects():
|
|
33
|
+
yield Point
|
|
34
|
+
yield DataclassPoint
|
|
35
|
+
for cls in (Serializable, DataclassSerializable):
|
|
36
|
+
for _, method in inspect.getmembers(cls, callable):
|
|
37
|
+
if (getattr(method, "__module__", None) or "").startswith("serializable"):
|
|
38
|
+
yield method
|
|
39
|
+
for _, function in inspect.getmembers(helpers, inspect.isfunction):
|
|
40
|
+
if function.__module__ == helpers.__name__:
|
|
41
|
+
yield function
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@pytest.mark.parametrize("obj", list(annotated_objects()), ids=lambda obj: obj.__qualname__)
|
|
45
|
+
def test_annotations_evaluate_at_runtime(obj):
|
|
46
|
+
# annotations must stay evaluable on the oldest supported Python (no
|
|
47
|
+
# `X | Y` unions before 3.10) for tools which call get_type_hints
|
|
48
|
+
typing.get_type_hints(obj)
|
|
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
|