py-serializable 2.0.0__tar.gz → 2.1.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.
- {py_serializable-2.0.0 → py_serializable-2.1.0}/CHANGELOG.md +24 -105
- {py_serializable-2.0.0 → py_serializable-2.1.0}/PKG-INFO +1 -1
- {py_serializable-2.0.0 → py_serializable-2.1.0}/docs/conf.py +1 -1
- {py_serializable-2.0.0 → py_serializable-2.1.0}/py_serializable/__init__.py +46 -13
- {py_serializable-2.0.0 → py_serializable-2.1.0}/py_serializable/formatters.py +0 -2
- {py_serializable-2.0.0 → py_serializable-2.1.0}/py_serializable/helpers.py +0 -2
- {py_serializable-2.0.0 → py_serializable-2.1.0}/py_serializable/json.py +0 -2
- {py_serializable-2.0.0 → py_serializable-2.1.0}/py_serializable/xml.py +0 -2
- {py_serializable-2.0.0 → py_serializable-2.1.0}/pyproject.toml +3 -2
- {py_serializable-2.0.0 → py_serializable-2.1.0}/tests/__init__.py +0 -2
- {py_serializable-2.0.0 → py_serializable-2.1.0}/tests/base.py +1 -3
- py_serializable-2.1.0/tests/fixtures/the-phoenix-project-defaultNS-isset.SNAPSHOT.xml +1 -0
- py_serializable-2.1.0/tests/fixtures/the-phoenix-project-defaultNS-unset.SNAPSHOT.xml +1 -0
- py_serializable-2.1.0/tests/fixtures/the-phoenix-project_unknown_ignored_attributes.xml +54 -0
- py_serializable-2.1.0/tests/fixtures/the-phoenix-project_unknown_ignored_elements.xml +59 -0
- py_serializable-2.1.0/tests/fixtures/the-phoenix-project_unknown_ignored_properties.json +66 -0
- py_serializable-2.1.0/tests/fixtures/the-phoenix-project_unknown_unignored_attributes.xml +52 -0
- py_serializable-2.1.0/tests/fixtures/the-phoenix-project_unknown_unignored_elements.xml +56 -0
- py_serializable-2.1.0/tests/fixtures/the-phoenix-project_unknown_unignored_properties.json +65 -0
- {py_serializable-2.0.0 → py_serializable-2.1.0}/tests/model.py +10 -5
- {py_serializable-2.0.0 → py_serializable-2.1.0}/tests/test_formatters.py +0 -2
- {py_serializable-2.0.0 → py_serializable-2.1.0}/tests/test_helpers.py +24 -2
- {py_serializable-2.0.0 → py_serializable-2.1.0}/tests/test_json.py +45 -18
- {py_serializable-2.0.0 → py_serializable-2.1.0}/tests/test_oml.py +0 -2
- {py_serializable-2.0.0 → py_serializable-2.1.0}/tests/test_oml_serializable_property.py +0 -2
- {py_serializable-2.0.0 → py_serializable-2.1.0}/tests/test_xml.py +48 -11
- py_serializable-2.0.0/tests/fixtures/the-phoenix-project-defaultNS-isset.SNAPSHOT.xml +0 -1
- py_serializable-2.0.0/tests/fixtures/the-phoenix-project-defaultNS-unset.SNAPSHOT.xml +0 -1
- {py_serializable-2.0.0 → py_serializable-2.1.0}/LICENSE +0 -0
- {py_serializable-2.0.0 → py_serializable-2.1.0}/README.md +0 -0
- {py_serializable-2.0.0 → py_serializable-2.1.0}/docs/Makefile +0 -0
- {py_serializable-2.0.0 → py_serializable-2.1.0}/docs/changelog.rst +0 -0
- {py_serializable-2.0.0 → py_serializable-2.1.0}/docs/customising-structure.rst +0 -0
- {py_serializable-2.0.0 → py_serializable-2.1.0}/docs/examples.rst +0 -0
- {py_serializable-2.0.0 → py_serializable-2.1.0}/docs/formatters.rst +0 -0
- {py_serializable-2.0.0 → py_serializable-2.1.0}/docs/getting-started.rst +0 -0
- {py_serializable-2.0.0 → py_serializable-2.1.0}/docs/index.rst +0 -0
- {py_serializable-2.0.0 → py_serializable-2.1.0}/docs/make.bat +0 -0
- {py_serializable-2.0.0 → py_serializable-2.1.0}/docs/migration.rst +0 -0
- {py_serializable-2.0.0 → py_serializable-2.1.0}/docs/requirements.txt +0 -0
- {py_serializable-2.0.0 → py_serializable-2.1.0}/docs/support.rst +0 -0
- {py_serializable-2.0.0 → py_serializable-2.1.0}/py_serializable/py.typed +0 -0
- {py_serializable-2.0.0 → py_serializable-2.1.0}/tests/fixtures/the-phoenix-project-bookedition-none.json +0 -0
- {py_serializable-2.0.0 → py_serializable-2.1.0}/tests/fixtures/the-phoenix-project-bookedition-none.xml +0 -0
- {py_serializable-2.0.0 → py_serializable-2.1.0}/tests/fixtures/the-phoenix-project-camel-case-1-v1.xml +0 -0
- {py_serializable-2.0.0 → py_serializable-2.1.0}/tests/fixtures/the-phoenix-project-camel-case-1-v2.xml +0 -0
- {py_serializable-2.0.0 → py_serializable-2.1.0}/tests/fixtures/the-phoenix-project-camel-case-1-v3.xml +0 -0
- {py_serializable-2.0.0 → py_serializable-2.1.0}/tests/fixtures/the-phoenix-project-camel-case-1-v4.xml +0 -0
- {py_serializable-2.0.0 → py_serializable-2.1.0}/tests/fixtures/the-phoenix-project-camel-case-1.xml +0 -0
- {py_serializable-2.0.0 → py_serializable-2.1.0}/tests/fixtures/the-phoenix-project-camel-case-references.json +0 -0
- {py_serializable-2.0.0 → py_serializable-2.1.0}/tests/fixtures/the-phoenix-project-camel-case-v2.json +0 -0
- {py_serializable-2.0.0 → py_serializable-2.1.0}/tests/fixtures/the-phoenix-project-camel-case-v3.json +0 -0
- {py_serializable-2.0.0 → py_serializable-2.1.0}/tests/fixtures/the-phoenix-project-camel-case-v4.json +0 -0
- {py_serializable-2.0.0 → py_serializable-2.1.0}/tests/fixtures/the-phoenix-project-camel-case-with-ignored.json +0 -0
- {py_serializable-2.0.0 → py_serializable-2.1.0}/tests/fixtures/the-phoenix-project-camel-case-with-ignored.xml +0 -0
- {py_serializable-2.0.0 → py_serializable-2.1.0}/tests/fixtures/the-phoenix-project-camel-case.json +0 -0
- {py_serializable-2.0.0 → py_serializable-2.1.0}/tests/fixtures/the-phoenix-project-defaultNS-isset-v4.xml +0 -0
- {py_serializable-2.0.0 → py_serializable-2.1.0}/tests/fixtures/the-phoenix-project-defaultNS-mixed-v4.xml +0 -0
- {py_serializable-2.0.0 → py_serializable-2.1.0}/tests/fixtures/the-phoenix-project-defaultNS-unset-v4.xml +0 -0
- {py_serializable-2.0.0 → py_serializable-2.1.0}/tests/fixtures/the-phoenix-project-kebab-case-1-v2.xml +0 -0
- {py_serializable-2.0.0 → py_serializable-2.1.0}/tests/fixtures/the-phoenix-project-kebab-case-1.xml +0 -0
- {py_serializable-2.0.0 → py_serializable-2.1.0}/tests/fixtures/the-phoenix-project-kebab-case.json +0 -0
- {py_serializable-2.0.0 → py_serializable-2.1.0}/tests/fixtures/the-phoenix-project-snake-case-1.xml +0 -0
- {py_serializable-2.0.0 → py_serializable-2.1.0}/tests/fixtures/the-phoenix-project-snake-case.json +0 -0
- {py_serializable-2.0.0 → py_serializable-2.1.0}/tests/fixtures/the-phoenix-project_unnormalized-input_v4.xml +0 -0
|
@@ -1,131 +1,50 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
## Unreleased
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
* Delete duplicate CODEOWNERS (#156)
|
|
9
|
-
|
|
10
|
-
we have a codeowners file in root already ([`b64cdde`](https://github.com/madpah/serializable/commit/b64cdde6d4561355f7b92416dfcb36a8ff770be5))
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
## v2.0.0-alpha.1 (2025-01-16)
|
|
5
|
+
## v2.0.0 (2025-02-09)
|
|
15
6
|
|
|
16
7
|
### Breaking
|
|
17
8
|
|
|
18
|
-
* refactor!: rename
|
|
19
|
-
|
|
20
|
-
Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com> ([`39bfc1a`](https://github.com/madpah/serializable/commit/39bfc1a3f20efdb75be3b14e9bfa845dc1f62142))
|
|
9
|
+
* refactor!: rename python package `serializable` -> `py_serializable` (#155)
|
|
21
10
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
* chore: Create CODEOWNERS ([`960331a`](https://github.com/madpah/serializable/commit/960331ad5181b64afa140d1fd0d2d59b687d782b))
|
|
25
|
-
|
|
26
|
-
* chore(deps-dev): update mypy requirement from 1.13.0 to 1.14.1 (#154)
|
|
27
|
-
|
|
28
|
-
Updates the requirements on [mypy](https://github.com/python/mypy) to permit the latest version.
|
|
29
|
-
- [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md)
|
|
30
|
-
- [Commits](https://github.com/python/mypy/compare/v1.13.0...v1.14.1)
|
|
11
|
+
The python package was renamed from `serializable` to `py_serializable`.
|
|
12
|
+
Therefore, you need to adjust your imports.
|
|
31
13
|
|
|
32
|
-
|
|
33
|
-
updated-dependencies:
|
|
34
|
-
- dependency-name: mypy
|
|
35
|
-
dependency-type: direct:development
|
|
36
|
-
...
|
|
14
|
+
The following shows a quick way to adjust imports in the most efficient way.
|
|
37
15
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
- [Release notes](https://github.com/PyCQA/flake8-bugbear/releases)
|
|
45
|
-
- [Commits](https://github.com/PyCQA/flake8-bugbear/compare/24.10.31...24.12.12)
|
|
46
|
-
|
|
47
|
-
---
|
|
48
|
-
updated-dependencies:
|
|
49
|
-
- dependency-name: flake8-bugbear
|
|
50
|
-
dependency-type: direct:development
|
|
51
|
-
...
|
|
52
|
-
|
|
53
|
-
Signed-off-by: dependabot[bot] <support@github.com>
|
|
54
|
-
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> ([`cb8a91b`](https://github.com/madpah/serializable/commit/cb8a91b6c5a42f5a46379adc272ec8fa4cc2cc37))
|
|
55
|
-
|
|
56
|
-
* chore(deps-dev): update flake8-bugbear requirement (#146)
|
|
57
|
-
|
|
58
|
-
Updates the requirements on [flake8-bugbear](https://github.com/PyCQA/flake8-bugbear) to permit the latest version.
|
|
59
|
-
- [Release notes](https://github.com/PyCQA/flake8-bugbear/releases)
|
|
60
|
-
- [Commits](https://github.com/PyCQA/flake8-bugbear/compare/24.8.19...24.10.31)
|
|
16
|
+
### OLD imports
|
|
17
|
+
```py
|
|
18
|
+
import serializable
|
|
19
|
+
from serializable import ViewType, XmlArraySerializationType, XmlStringSerializationType
|
|
20
|
+
from serializable.helpers import BaseHelper, Iso8601Date
|
|
21
|
+
```
|
|
61
22
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
23
|
+
### ADJUSTED imports
|
|
24
|
+
```py
|
|
25
|
+
import py_serializable as serializable
|
|
26
|
+
from py_serializable import ViewType, XmlArraySerializationType, XmlStringSerializationType
|
|
27
|
+
from py_serializable.helpers import BaseHelper, Iso8601Date
|
|
28
|
+
```
|
|
67
29
|
|
|
68
|
-
|
|
69
|
-
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> ([`f6574e7`](https://github.com/madpah/serializable/commit/f6574e757695a4afc6922138a5e3cc8bdade2142))
|
|
70
|
-
|
|
71
|
-
* chore(deps-dev): update mypy requirement from 1.12.0 to 1.13.0 (#145)
|
|
72
|
-
|
|
73
|
-
Updates the requirements on [mypy](https://github.com/python/mypy) to permit the latest version.
|
|
74
|
-
- [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md)
|
|
75
|
-
- [Commits](https://github.com/python/mypy/compare/v1.12.0...v1.13.0)
|
|
30
|
+
see migration path: <https://py-serializable.readthedocs.io/en/refactor-rename-installable-py_serializable/migration.html>
|
|
76
31
|
|
|
77
|
-
|
|
78
|
-
updated-dependencies:
|
|
79
|
-
- dependency-name: mypy
|
|
80
|
-
dependency-type: direct:development
|
|
81
|
-
...
|
|
32
|
+
----
|
|
82
33
|
|
|
83
|
-
|
|
84
|
-
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> ([`c5117ba`](https://github.com/madpah/serializable/commit/c5117ba0ef716b8cc7a3f1d639df585bba36f5e3))
|
|
85
|
-
|
|
86
|
-
* chore(deps-dev): update mypy requirement from 1.11.2 to 1.12.0 (#143)
|
|
87
|
-
|
|
88
|
-
Updates the requirements on [mypy](https://github.com/python/mypy) to permit the latest version.
|
|
89
|
-
- [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md)
|
|
90
|
-
- [Commits](https://github.com/python/mypy/compare/v1.11.2...v1.12.0)
|
|
34
|
+
fixes #151
|
|
91
35
|
|
|
92
|
-
|
|
93
|
-
updated-dependencies:
|
|
94
|
-
- dependency-name: mypy
|
|
95
|
-
dependency-type: direct:development
|
|
96
|
-
...
|
|
36
|
+
---------
|
|
97
37
|
|
|
98
|
-
Signed-off-by:
|
|
99
|
-
|
|
38
|
+
Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
|
|
39
|
+
Signed-off-by: semantic-release <semantic-release>
|
|
40
|
+
Co-authored-by: semantic-release <semantic-release> ([`67afaef`](https://github.com/madpah/serializable/commit/67afaef4a5e670c533409f1ccbc3d2dbb263d2de))
|
|
100
41
|
|
|
101
42
|
### Unknown
|
|
102
43
|
|
|
103
|
-
* Merge branch 'main' into refactor/rename-installable-py_serializable ([`5b62208`](https://github.com/madpah/serializable/commit/5b622084eb016765096679451ce15801c45d707d))
|
|
104
|
-
|
|
105
44
|
* Delete duplicate CODEOWNERS (#156)
|
|
106
45
|
|
|
107
46
|
we have a codeowners file in root already ([`b64cdde`](https://github.com/madpah/serializable/commit/b64cdde6d4561355f7b92416dfcb36a8ff770be5))
|
|
108
47
|
|
|
109
|
-
* docs
|
|
110
|
-
|
|
111
|
-
Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com> ([`e3708ec`](https://github.com/madpah/serializable/commit/e3708ec0fbd23a3705a5fe49c8a31293bbf7446f))
|
|
112
|
-
|
|
113
|
-
* docs
|
|
114
|
-
|
|
115
|
-
Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com> ([`225b614`](https://github.com/madpah/serializable/commit/225b614346f89a04cce759fc617a42d647f8a4a9))
|
|
116
|
-
|
|
117
|
-
* docs
|
|
118
|
-
|
|
119
|
-
Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com> ([`a581861`](https://github.com/madpah/serializable/commit/a58186100361e48135b630a42bc5b5929af3dd15))
|
|
120
|
-
|
|
121
|
-
* docs
|
|
122
|
-
|
|
123
|
-
Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com> ([`2df3e21`](https://github.com/madpah/serializable/commit/2df3e21012fc9499bf47236fb85925394b3bfc2d))
|
|
124
|
-
|
|
125
|
-
* style
|
|
126
|
-
|
|
127
|
-
Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com> ([`42cf87b`](https://github.com/madpah/serializable/commit/42cf87bb30c4cf2d19eba4a86c20fa198ff48208))
|
|
128
|
-
|
|
129
48
|
|
|
130
49
|
## v1.1.2 (2024-10-01)
|
|
131
50
|
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
# encoding: utf-8
|
|
2
|
-
|
|
3
1
|
# This file is part of py-serializable
|
|
4
2
|
#
|
|
5
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -60,7 +58,7 @@ import typing # noqa: F401 # isort: skip
|
|
|
60
58
|
|
|
61
59
|
# !! version is managed by semantic_release
|
|
62
60
|
# do not use typing here, or else `semantic_release` might have issues finding the variable
|
|
63
|
-
__version__ = '2.
|
|
61
|
+
__version__ = '2.1.0'
|
|
64
62
|
|
|
65
63
|
_logger = getLogger(__name__)
|
|
66
64
|
_logger.addHandler(NullHandler())
|
|
@@ -322,10 +320,10 @@ class _JsonSerializable(Protocol):
|
|
|
322
320
|
|
|
323
321
|
_data = copy(data)
|
|
324
322
|
for k, v in data.items():
|
|
323
|
+
del _data[k]
|
|
325
324
|
decoded_k = CurrentFormatter.formatter.decode(property_name=k)
|
|
326
325
|
if decoded_k in klass.ignore_during_deserialization:
|
|
327
326
|
_logger.debug('Ignoring %s when deserializing %s.%s', k, cls.__module__, cls.__qualname__)
|
|
328
|
-
del _data[k]
|
|
329
327
|
continue
|
|
330
328
|
|
|
331
329
|
new_key = None
|
|
@@ -338,13 +336,14 @@ class _JsonSerializable(Protocol):
|
|
|
338
336
|
new_key = decoded_k
|
|
339
337
|
|
|
340
338
|
if new_key is None:
|
|
339
|
+
if klass.ignore_unknown_during_deserialization:
|
|
340
|
+
_logger.debug('Ignoring %s when deserializing %s.%s', k, cls.__module__, cls.__qualname__)
|
|
341
|
+
continue
|
|
341
342
|
_logger.error('Unexpected key %s/%s in data being serialized to %s.%s',
|
|
342
343
|
k, decoded_k, cls.__module__, cls.__qualname__)
|
|
343
344
|
raise ValueError(
|
|
344
345
|
f'Unexpected key {k}/{decoded_k} in data being serialized to {cls.__module__}.{cls.__qualname__}'
|
|
345
346
|
)
|
|
346
|
-
|
|
347
|
-
del (_data[k])
|
|
348
347
|
_data[new_key] = v
|
|
349
348
|
|
|
350
349
|
for k, v in _data.items():
|
|
@@ -595,6 +594,9 @@ class _XmlSerializable(Protocol):
|
|
|
595
594
|
|
|
596
595
|
prop_info = klass_properties.get(decoded_k)
|
|
597
596
|
if not prop_info:
|
|
597
|
+
if klass.ignore_unknown_during_deserialization:
|
|
598
|
+
_logger.debug('Ignoring %s when deserializing %s.%s', decoded_k, cls.__module__, cls.__qualname__)
|
|
599
|
+
continue
|
|
598
600
|
raise ValueError(f'Non-primitive types not supported from XML Attributes - see {decoded_k} for '
|
|
599
601
|
f'{cls.__module__}.{cls.__qualname__} which has Prop Metadata: {prop_info}')
|
|
600
602
|
|
|
@@ -648,6 +650,11 @@ class _XmlSerializable(Protocol):
|
|
|
648
650
|
|
|
649
651
|
prop_info = klass_properties.get(decoded_k)
|
|
650
652
|
if not prop_info:
|
|
653
|
+
if klass.ignore_unknown_during_deserialization:
|
|
654
|
+
_logger.debug('Ignoring %s when deserializing %s.%s', decoded_k, cls.__module__, cls.__qualname__)
|
|
655
|
+
continue
|
|
656
|
+
_logger.error('Unexpected key %s/%s in data being serialized to %s.%s',
|
|
657
|
+
k, decoded_k, cls.__module__, cls.__qualname__)
|
|
651
658
|
raise ValueError(f'{decoded_k} is not a known Property for {cls.__module__}.{cls.__qualname__}')
|
|
652
659
|
|
|
653
660
|
try:
|
|
@@ -760,7 +767,12 @@ class ObjectMetadataLibrary:
|
|
|
760
767
|
|
|
761
768
|
def __init__(self, *, klass: type, custom_name: Optional[str] = None,
|
|
762
769
|
serialization_types: Optional[Iterable[SerializationType]] = None,
|
|
763
|
-
ignore_during_deserialization: Optional[Iterable[str]] = None
|
|
770
|
+
ignore_during_deserialization: Optional[Iterable[str]] = None,
|
|
771
|
+
ignore_unknown_during_deserialization: bool = False) -> None:
|
|
772
|
+
# param ignore_unknown_during_deserialization defaults to False, since we deserialize from JSON/XML
|
|
773
|
+
# and both have mechanisms for arbitrary content that might be intended to pass to the constructors:
|
|
774
|
+
# - JSON has `additionalProperties:true`
|
|
775
|
+
# - XML has `##any` and `##other`
|
|
764
776
|
self._name = str(klass.__name__)
|
|
765
777
|
self._klass = klass
|
|
766
778
|
self._custom_name = custom_name
|
|
@@ -768,6 +780,7 @@ class ObjectMetadataLibrary:
|
|
|
768
780
|
serialization_types = _DEFAULT_SERIALIZATION_TYPES
|
|
769
781
|
self._serialization_types = serialization_types
|
|
770
782
|
self._ignore_during_deserialization = set(ignore_during_deserialization or ())
|
|
783
|
+
self._ignore_unknown_during_deserialization = ignore_unknown_during_deserialization
|
|
771
784
|
|
|
772
785
|
@property
|
|
773
786
|
def name(self) -> str:
|
|
@@ -789,6 +802,10 @@ class ObjectMetadataLibrary:
|
|
|
789
802
|
def ignore_during_deserialization(self) -> Set[str]:
|
|
790
803
|
return self._ignore_during_deserialization
|
|
791
804
|
|
|
805
|
+
@property
|
|
806
|
+
def ignore_unknown_during_deserialization(self) -> bool:
|
|
807
|
+
return self._ignore_unknown_during_deserialization
|
|
808
|
+
|
|
792
809
|
def __repr__(self) -> str:
|
|
793
810
|
return f'<s.oml.SerializableClass name={self.name}>'
|
|
794
811
|
|
|
@@ -1096,14 +1113,20 @@ class ObjectMetadataLibrary:
|
|
|
1096
1113
|
@classmethod
|
|
1097
1114
|
def register_klass(cls, klass: Type[_T], custom_name: Optional[str],
|
|
1098
1115
|
serialization_types: Iterable[SerializationType],
|
|
1099
|
-
ignore_during_deserialization: Optional[Iterable[str]] = None
|
|
1116
|
+
ignore_during_deserialization: Optional[Iterable[str]] = None,
|
|
1117
|
+
ignore_unknown_during_deserialization: bool = False
|
|
1100
1118
|
) -> Intersection[Type[_T], Type[_JsonSerializable], Type[_XmlSerializable]]:
|
|
1119
|
+
# param ignore_unknown_during_deserialization defaults to False, since we deserialize from JSON/XML
|
|
1120
|
+
# and both have mechanisms for arbitrary content that might be intended to pass to the constructors:
|
|
1121
|
+
# - JSON has `additionalProperties:true`
|
|
1122
|
+
# - XML has `##any` and `##other`
|
|
1101
1123
|
if cls.is_klass_serializable(klass=klass):
|
|
1102
1124
|
return klass
|
|
1103
1125
|
|
|
1104
1126
|
cls.klass_mappings[f'{klass.__module__}.{klass.__qualname__}'] = ObjectMetadataLibrary.SerializableClass(
|
|
1105
1127
|
klass=klass, serialization_types=serialization_types,
|
|
1106
|
-
ignore_during_deserialization=ignore_during_deserialization
|
|
1128
|
+
ignore_during_deserialization=ignore_during_deserialization,
|
|
1129
|
+
ignore_unknown_during_deserialization=ignore_unknown_during_deserialization
|
|
1107
1130
|
)
|
|
1108
1131
|
|
|
1109
1132
|
qualified_class_name = f'{klass.__module__}.{klass.__qualname__}'
|
|
@@ -1243,7 +1266,8 @@ def serializable_class(
|
|
|
1243
1266
|
cls: Literal[None] = None, *,
|
|
1244
1267
|
name: Optional[str] = ...,
|
|
1245
1268
|
serialization_types: Optional[Iterable[SerializationType]] = ...,
|
|
1246
|
-
ignore_during_deserialization: Optional[Iterable[str]] =
|
|
1269
|
+
ignore_during_deserialization: Optional[Iterable[str]] = ...,
|
|
1270
|
+
ignore_unknown_during_deserialization: bool = ...
|
|
1247
1271
|
) -> Callable[[Type[_T]], Intersection[Type[_T], Type[_JsonSerializable], Type[_XmlSerializable]]]:
|
|
1248
1272
|
...
|
|
1249
1273
|
|
|
@@ -1253,7 +1277,8 @@ def serializable_class( # type:ignore[misc] # mypy on py37
|
|
|
1253
1277
|
cls: Type[_T], *,
|
|
1254
1278
|
name: Optional[str] = ...,
|
|
1255
1279
|
serialization_types: Optional[Iterable[SerializationType]] = ...,
|
|
1256
|
-
ignore_during_deserialization: Optional[Iterable[str]] =
|
|
1280
|
+
ignore_during_deserialization: Optional[Iterable[str]] = ...,
|
|
1281
|
+
ignore_unknown_during_deserialization: bool = ...
|
|
1257
1282
|
) -> Intersection[Type[_T], Type[_JsonSerializable], Type[_XmlSerializable]]:
|
|
1258
1283
|
...
|
|
1259
1284
|
|
|
@@ -1262,7 +1287,8 @@ def serializable_class(
|
|
|
1262
1287
|
cls: Optional[Type[_T]] = None, *,
|
|
1263
1288
|
name: Optional[str] = None,
|
|
1264
1289
|
serialization_types: Optional[Iterable[SerializationType]] = None,
|
|
1265
|
-
ignore_during_deserialization: Optional[Iterable[str]] = None
|
|
1290
|
+
ignore_during_deserialization: Optional[Iterable[str]] = None,
|
|
1291
|
+
ignore_unknown_during_deserialization: bool = False
|
|
1266
1292
|
) -> Union[
|
|
1267
1293
|
Callable[[Type[_T]], Intersection[Type[_T], Type[_JsonSerializable], Type[_XmlSerializable]]],
|
|
1268
1294
|
Intersection[Type[_T], Type[_JsonSerializable], Type[_XmlSerializable]]
|
|
@@ -1274,15 +1300,22 @@ def serializable_class(
|
|
|
1274
1300
|
:param name: Alternative name to use for this Class
|
|
1275
1301
|
:param serialization_types: Serialization Types that are to be supported for this class.
|
|
1276
1302
|
:param ignore_during_deserialization: List of properties/elements to ignore during deserialization
|
|
1303
|
+
:param ignore_unknown_during_deserialization: Whether to ignore all properties/elements/attributes that are unknown
|
|
1304
|
+
to the class during deserialization
|
|
1277
1305
|
:return:
|
|
1278
1306
|
"""
|
|
1307
|
+
# param ignore_unknown_during_deserialization defaults to False, since we deserialize from JSON/XML
|
|
1308
|
+
# and both have mechanisms for arbitrary content that might be intended to pass to the constructors:
|
|
1309
|
+
# - JSON has `additionalProperties:true`
|
|
1310
|
+
# - XML has `##any` and `##other`
|
|
1279
1311
|
if serialization_types is None:
|
|
1280
1312
|
serialization_types = _DEFAULT_SERIALIZATION_TYPES
|
|
1281
1313
|
|
|
1282
1314
|
def decorate(kls: Type[_T]) -> Intersection[Type[_T], Type[_JsonSerializable], Type[_XmlSerializable]]:
|
|
1283
1315
|
ObjectMetadataLibrary.register_klass(
|
|
1284
1316
|
klass=kls, custom_name=name, serialization_types=serialization_types or [],
|
|
1285
|
-
ignore_during_deserialization=ignore_during_deserialization
|
|
1317
|
+
ignore_during_deserialization=ignore_during_deserialization,
|
|
1318
|
+
ignore_unknown_during_deserialization=ignore_unknown_during_deserialization
|
|
1286
1319
|
)
|
|
1287
1320
|
return kls
|
|
1288
1321
|
|
|
@@ -5,7 +5,7 @@ build-backend = "poetry.core.masonry.api"
|
|
|
5
5
|
|
|
6
6
|
[tool.poetry]
|
|
7
7
|
name = "py-serializable"
|
|
8
|
-
version = "2.
|
|
8
|
+
version = "2.1.0"
|
|
9
9
|
description = "Library for serializing and deserializing Python Objects to and from JSON and XML."
|
|
10
10
|
authors = ["Paul Horton <paul.horton@owasp.org>"]
|
|
11
11
|
maintainers = [
|
|
@@ -64,13 +64,14 @@ xmldiff = "2.7.0"
|
|
|
64
64
|
mypy = "1.14.1"
|
|
65
65
|
autopep8 = "2.3.1"
|
|
66
66
|
isort = "5.13.2"
|
|
67
|
-
flake8 = { version="7.1.
|
|
67
|
+
flake8 = { version="7.1.2", python=">=3.8.1" }
|
|
68
68
|
flake8-annotations = { version="3.1.1", python=">=3.8.1" }
|
|
69
69
|
flake8-bugbear = { version="24.12.12", python=">=3.8.1" }
|
|
70
70
|
flake8-isort = "6.1.1"
|
|
71
71
|
flake8-quotes = "3.4.0"
|
|
72
72
|
flake8-use-fstring = "1.4"
|
|
73
73
|
flake8-logging = "1.6.0"
|
|
74
|
+
pyupgrade = { version="3.20.0", python=">=3.9" }
|
|
74
75
|
|
|
75
76
|
|
|
76
77
|
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
# encoding: utf-8
|
|
2
|
-
|
|
3
1
|
# This file is part of py-serializable
|
|
4
2
|
#
|
|
5
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -62,7 +60,7 @@ class BaseTestCase(TestCase):
|
|
|
62
60
|
f'There are XML differences: {diff_results!r}\n- {a!s}\n+ {b!s}')
|
|
63
61
|
|
|
64
62
|
|
|
65
|
-
class DeepCompareMixin
|
|
63
|
+
class DeepCompareMixin:
|
|
66
64
|
def assertDeepEqual(self: Union[TestCase, 'DeepCompareMixin'],
|
|
67
65
|
first: Any, second: Any, msg: Optional[str] = None) -> None:
|
|
68
66
|
"""costly compare, but very verbose"""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<book xmlns="http://the.phoenix.project/testing/defaultNS" isbnNumber="978-1942788294"><id>f3758bf0-0ff7-4366-a5e5-c209d4352b2d</id><title>{X} The Phoenix Project</title><edition number="5">5th Anniversary Limited Edition</edition><publishDate>2018-04-16</publishDate><author>Karl Ranseier</author><type>fiction</type><publisher><name>IT Revolution Press LLC</name></publisher><chapters><chapter><number>1</number><title>Tuesday, September 2</title></chapter><chapter><number>2</number><title>Tuesday, September 2</title></chapter><chapter><number>3</number><title>Tuesday, September 2</title></chapter><chapter><number>4</number><title>Wednesday, September 3</title></chapter></chapters><rating>9.8</rating></book>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<ns0:book xmlns:ns0="http://the.phoenix.project/testing/defaultNS" ns0:isbnNumber="978-1942788294"><ns0:id>f3758bf0-0ff7-4366-a5e5-c209d4352b2d</ns0:id><ns0:title>{X} The Phoenix Project</ns0:title><ns0:edition ns0:number="5">5th Anniversary Limited Edition</ns0:edition><ns0:publishDate>2018-04-16</ns0:publishDate><ns0:author>Karl Ranseier</ns0:author><ns0:type>fiction</ns0:type><ns0:publisher><ns0:name>IT Revolution Press LLC</ns0:name></ns0:publisher><ns0:chapters><ns0:chapter><ns0:number>1</ns0:number><ns0:title>Tuesday, September 2</ns0:title></ns0:chapter><ns0:chapter><ns0:number>2</ns0:number><ns0:title>Tuesday, September 2</ns0:title></ns0:chapter><ns0:chapter><ns0:number>3</ns0:number><ns0:title>Tuesday, September 2</ns0:title></ns0:chapter><ns0:chapter><ns0:number>4</ns0:number><ns0:title>Wednesday, September 3</ns0:title></ns0:chapter></ns0:chapters><ns0:rating>9.8</ns0:rating></ns0:book>
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
<?xml version='1.0' encoding='utf-8'?>
|
|
2
|
+
<book xmlns="http://the.phoenix.project/testing/defaultNS"
|
|
3
|
+
xmlns:foo="https://example.com/foo"
|
|
4
|
+
something_to_be_ignored="foo"
|
|
5
|
+
isbnNumber="978-1942788294"
|
|
6
|
+
ignore_me="bar"
|
|
7
|
+
>
|
|
8
|
+
<!-- some attributes are registered to be ignored -->
|
|
9
|
+
<id>f3758bf0-0ff7-4366-a5e5-c209d4352b2d</id>
|
|
10
|
+
<title>{X} The Phoenix Project</title>
|
|
11
|
+
<edition number="5">5th Anniversary Limited Edition</edition>
|
|
12
|
+
<publishDate>2018-04-16</publishDate>
|
|
13
|
+
<author>Kevin Behr</author>
|
|
14
|
+
<author>George Spafford</author>
|
|
15
|
+
<author>Gene Kim</author>
|
|
16
|
+
<type>fiction</type>
|
|
17
|
+
<publisher foo:my-other-attribute="my-value"
|
|
18
|
+
unknown-other-attribute="some-value"
|
|
19
|
+
>
|
|
20
|
+
<address>10 Downing Street</address>
|
|
21
|
+
<name>IT Revolution Press LLC</name>
|
|
22
|
+
</publisher>
|
|
23
|
+
<references>
|
|
24
|
+
<reference ref="my-ref-2">
|
|
25
|
+
<reference ref="sub-ref-3"/>
|
|
26
|
+
<reference ref="sub-ref-1"/>
|
|
27
|
+
</reference>
|
|
28
|
+
<reference ref="my-ref-1"/>
|
|
29
|
+
<reference ref="my-ref-3">
|
|
30
|
+
<reference ref="sub-ref-2"/>
|
|
31
|
+
</reference>
|
|
32
|
+
</references>
|
|
33
|
+
<chapters>
|
|
34
|
+
<chapter>
|
|
35
|
+
<number>1</number>
|
|
36
|
+
<title>Tuesday, September 2</title>
|
|
37
|
+
</chapter>
|
|
38
|
+
<chapter>
|
|
39
|
+
<number>2</number>
|
|
40
|
+
<title>Tuesday, September 2</title>
|
|
41
|
+
</chapter>
|
|
42
|
+
<chapter>
|
|
43
|
+
<number>3</number>
|
|
44
|
+
<title>Tuesday, September 2</title>
|
|
45
|
+
</chapter>
|
|
46
|
+
<chapter>
|
|
47
|
+
<number>4</number>
|
|
48
|
+
<title>Wednesday, September 3</title>
|
|
49
|
+
</chapter>
|
|
50
|
+
</chapters>
|
|
51
|
+
<rating>9.8</rating>
|
|
52
|
+
<stockId>stock-id-1</stockId>
|
|
53
|
+
<stockId>stock-id-2</stockId>
|
|
54
|
+
</book>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<?xml version='1.0' encoding='utf-8'?>
|
|
2
|
+
<book xmlns="http://the.phoenix.project/testing/defaultNS"
|
|
3
|
+
xmlns:foo="https://example.com/foo"
|
|
4
|
+
isbnNumber="978-1942788294"
|
|
5
|
+
>
|
|
6
|
+
<!-- some elements are registered to be ignored -->
|
|
7
|
+
<something_to_be_ignored>foo</something_to_be_ignored>>
|
|
8
|
+
<id>f3758bf0-0ff7-4366-a5e5-c209d4352b2d</id>
|
|
9
|
+
<title>{X} The Phoenix Project</title>
|
|
10
|
+
<edition number="5">5th Anniversary Limited Edition</edition>
|
|
11
|
+
<publishDate>2018-04-16</publishDate>
|
|
12
|
+
<author>Gene Kim</author>
|
|
13
|
+
<author>George Spafford</author>
|
|
14
|
+
<author>Kevin Behr</author>
|
|
15
|
+
<type>fiction</type>
|
|
16
|
+
<ignore_me>bar</ignore_me>
|
|
17
|
+
<publisher>
|
|
18
|
+
<address>10 Downing Street</address>
|
|
19
|
+
<foo:my-unknown-element>some-value</foo:my-unknown-element>
|
|
20
|
+
<other-unknwon-elemment-bar xmlns="https://example.com/bar"
|
|
21
|
+
bar-thing="the-value"
|
|
22
|
+
>
|
|
23
|
+
<bar-elem>some-other-value</bar-elem>
|
|
24
|
+
</other-unknwon-elemment-bar>
|
|
25
|
+
<name>IT Revolution Press LLC</name>
|
|
26
|
+
</publisher>
|
|
27
|
+
<references>
|
|
28
|
+
<reference ref="my-ref-2">
|
|
29
|
+
<reference ref="sub-ref-3"/>
|
|
30
|
+
<reference ref="sub-ref-1"/>
|
|
31
|
+
</reference>
|
|
32
|
+
<reference ref="my-ref-3">
|
|
33
|
+
<reference ref="sub-ref-2"/>
|
|
34
|
+
</reference>
|
|
35
|
+
<reference ref="my-ref-1"/>
|
|
36
|
+
</references>
|
|
37
|
+
<chapters>
|
|
38
|
+
<chapter>
|
|
39
|
+
<number>1</number>
|
|
40
|
+
<title>Tuesday, September 2</title>
|
|
41
|
+
</chapter>
|
|
42
|
+
<chapter>
|
|
43
|
+
<number>2</number>
|
|
44
|
+
<title>Tuesday, September 2</title>
|
|
45
|
+
</chapter>
|
|
46
|
+
<chapter>
|
|
47
|
+
<number>3</number>
|
|
48
|
+
<title>Tuesday, September 2</title>
|
|
49
|
+
</chapter>
|
|
50
|
+
<chapter>
|
|
51
|
+
<number>4</number>
|
|
52
|
+
<title>Wednesday, September 3</title>
|
|
53
|
+
</chapter>
|
|
54
|
+
</chapters>
|
|
55
|
+
<rating>9.8</rating>
|
|
56
|
+
<stockId>stock-id-2</stockId>
|
|
57
|
+
<stockId>stock-id-1</stockId>
|
|
58
|
+
<ignored>bazz</ignored>
|
|
59
|
+
</book>
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "some properties are registered as ignored",
|
|
3
|
+
"something_to_be_ignored": "foo",
|
|
4
|
+
"authors": [
|
|
5
|
+
"Kevin Behr",
|
|
6
|
+
"Gene Kim",
|
|
7
|
+
"George Spafford"
|
|
8
|
+
],
|
|
9
|
+
"chapters": [
|
|
10
|
+
{
|
|
11
|
+
"number": 1,
|
|
12
|
+
"title": "Tuesday, September 2"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"number": 2,
|
|
16
|
+
"title": "Tuesday, September 2"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"number": 3,
|
|
20
|
+
"title": "Tuesday, September 2"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"number": 4,
|
|
24
|
+
"title": "Wednesday, September 3"
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
"ignored": "bar",
|
|
28
|
+
"edition": {
|
|
29
|
+
"name": "5th Anniversary Limited Edition",
|
|
30
|
+
"number": 5
|
|
31
|
+
},
|
|
32
|
+
"id": "f3758bf0-0ff7-4366-a5e5-c209d4352b2d",
|
|
33
|
+
"isbnNumber": "978-1942788294",
|
|
34
|
+
"publishDate": "2018-04-16",
|
|
35
|
+
"publisher": {
|
|
36
|
+
"address": "10 Downing Street",
|
|
37
|
+
"name": "IT Revolution Press LLC",
|
|
38
|
+
"other-unknown-property": "my-value"
|
|
39
|
+
},
|
|
40
|
+
"rating": 9.8,
|
|
41
|
+
"references": [
|
|
42
|
+
{
|
|
43
|
+
"reference": "my-ref-3",
|
|
44
|
+
"refersTo": [
|
|
45
|
+
"sub-ref-2"
|
|
46
|
+
]
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"reference": "my-ref-1"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"reference": "my-ref-2",
|
|
53
|
+
"refersTo": [
|
|
54
|
+
"sub-ref-1",
|
|
55
|
+
"sub-ref-3"
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
],
|
|
59
|
+
"stockIds": [
|
|
60
|
+
"stock-id-1",
|
|
61
|
+
"stock-id-2"
|
|
62
|
+
],
|
|
63
|
+
"title": "{J} The Phoenix Project",
|
|
64
|
+
"type": "fiction",
|
|
65
|
+
"ignore_me": "bazz"
|
|
66
|
+
}
|