16
16
#
17
17
# SPDX-License-Identifier: Apache-2.0
18
18
# Copyright (c) Paul Horton. All Rights Reserved.
19
+
19
20
import enum
20
21
import inspect
21
22
import json
22
23
import logging
23
24
import os
24
25
import re
25
- import typing # noqa: F401
26
26
import warnings
27
27
from copy import copy
28
28
from decimal import Decimal
29
29
from io import StringIO , TextIOWrapper
30
30
from json import JSONEncoder
31
31
from sys import version_info
32
- from typing import Any , Callable , Dict , Iterable , List , Optional , Set , Tuple , Type , TypeVar , Union , cast
32
+ from typing import (
33
+ Any ,
34
+ Callable ,
35
+ Dict ,
36
+ Iterable ,
37
+ List ,
38
+ Literal ,
39
+ Optional ,
40
+ Set ,
41
+ Tuple ,
42
+ Type ,
43
+ TypeVar ,
44
+ Union ,
45
+ cast ,
46
+ overload ,
47
+ )
33
48
from xml .etree .ElementTree import Element , SubElement
34
49
35
50
from defusedxml import ElementTree as SafeElementTree # type: ignore
36
51
37
52
if version_info >= (3 , 8 ):
38
53
from typing import Protocol
39
54
else :
40
- from typing_extensions import Protocol # type: ignore
55
+ from typing_extensions import Protocol # type: ignore[assignment]
41
56
42
57
from .formatters import BaseNameFormatter , CurrentFormatter
43
58
from .helpers import BaseHelper
@@ -61,6 +76,37 @@ class _Klass(Protocol):
61
76
ViewType = _Klass
62
77
63
78
79
+ class XmlSerializable (Protocol ):
80
+
81
+ @overload
82
+ def as_xml (self : _T , view_ : Optional [Type [_T ]], as_string : Literal [True ],
83
+ element_name : Optional [str ], xmlns : Optional [str ]) -> str :
84
+ ...
85
+
86
+ @overload
87
+ def as_xml (self : _T , view_ : Optional [Type [_T ]], as_string : Literal [False ],
88
+ element_name : Optional [str ], xmlns : Optional [str ]) -> Element :
89
+ ...
90
+
91
+ def as_xml (self : _T , view_ : Optional [Type [_T ]] = None , as_string : Literal [True , False ] = True ,
92
+ element_name : Optional [str ] = None , xmlns : Optional [str ] = None ) -> Union [Element , str ]:
93
+ return _as_xml (self , view_ , as_string , element_name , xmlns )
94
+
95
+ @classmethod
96
+ def from_xml (cls : Type [_T ], data : Union [TextIOWrapper , Element ],
97
+ default_namespace : Optional [str ] = None ) -> Optional [_T ]:
98
+ return _from_xml (cls , data , default_namespace )
99
+
100
+
101
+ class JsonSerializable (Protocol ):
102
+ def as_json (self : _T , view_ : Optional [Type [Any ]] = None ) -> str :
103
+ return _as_json (self , view_ )
104
+
105
+ @classmethod
106
+ def from_json (cls : Type [_T ], data : Dict [str , Any ]) -> Optional [_T ]:
107
+ return _from_json (cls , data )
108
+
109
+
64
110
@enum .unique
65
111
class SerializationType (str , enum .Enum ):
66
112
"""
@@ -230,7 +276,7 @@ def _as_json(self: _T, view_: Optional[Type[Any]] = None) -> str:
230
276
return json .dumps (self , cls = _SerializableJsonEncoder , view_ = view_ )
231
277
232
278
233
- def _from_json (cls : Type [_T ], data : Dict [str , Any ]) -> object :
279
+ def _from_json (cls : Type [_T ], data : Dict [str , Any ]) -> Optional [ _T ] :
234
280
"""
235
281
Internal function that is injected into Classes that are annotated for serialization and deserialization by
236
282
``serializable``.
@@ -318,7 +364,20 @@ def _from_json(cls: Type[_T], data: Dict[str, Any]) -> object:
318
364
return cls (** _data )
319
365
320
366
321
- def _as_xml (self : _T , view_ : Optional [Type [_T ]] = None , as_string : bool = True , element_name : Optional [str ] = None ,
367
+ @overload
368
+ def _as_xml (self : _T , view_ : Optional [Type [_T ]], as_string : Literal [True ],
369
+ element_name : Optional [str ], xmlns : Optional [str ]) -> str :
370
+ ...
371
+
372
+
373
+ @overload
374
+ def _as_xml (self : _T , view_ : Optional [Type [_T ]], as_string : Literal [False ],
375
+ element_name : Optional [str ], xmlns : Optional [str ]) -> Element :
376
+ ...
377
+
378
+
379
+ def _as_xml (self : _T , view_ : Optional [Type [_T ]] = None ,
380
+ as_string : Literal [True , False ] = True , element_name : Optional [str ] = None ,
322
381
xmlns : Optional [str ] = None ) -> Union [Element , str ]:
323
382
logging .debug (f'Dumping { self } to XML with view { view_ } ...' )
324
383
@@ -443,7 +502,7 @@ def _as_xml(self: _T, view_: Optional[Type[_T]] = None, as_string: bool = True,
443
502
444
503
445
504
def _from_xml (cls : Type [_T ], data : Union [TextIOWrapper , Element ],
446
- default_namespace : Optional [str ] = None ) -> object :
505
+ default_namespace : Optional [str ] = None ) -> Optional [ _T ] :
447
506
logging .debug (f'Rendering XML from { type (data )} to { cls } ...' )
448
507
klass = ObjectMetadataLibrary .klass_mappings .get (f'{ cls .__module__ } .{ cls .__qualname__ } ' , None )
449
508
if klass is None :
@@ -638,7 +697,7 @@ def __init__(self, *, klass: Any, custom_name: Optional[str] = None,
638
697
if serialization_types is None :
639
698
serialization_types = _DEFAULT_SERIALIZATION_TYPES
640
699
self ._serialization_types = serialization_types
641
- self ._ignore_during_deserialization = set (ignore_during_deserialization or {} )
700
+ self ._ignore_during_deserialization = set (ignore_during_deserialization or [] )
642
701
643
702
@property
644
703
def name (self ) -> str :
@@ -957,9 +1016,10 @@ def register_enum(cls, klass: _T) -> _T:
957
1016
return klass
958
1017
959
1018
@classmethod
960
- def register_klass (cls , klass : _T , custom_name : Optional [str ],
1019
+ def register_klass (cls , klass : Type [ _T ] , custom_name : Optional [str ],
961
1020
serialization_types : Iterable [SerializationType ],
962
- ignore_during_deserialization : Optional [Iterable [str ]] = None ) -> _T :
1021
+ ignore_during_deserialization : Optional [Iterable [str ]] = None
1022
+ ) -> Type [Union [_T , JsonSerializable , XmlSerializable ]]:
963
1023
if cls .is_klass_serializable (klass = klass ):
964
1024
return klass
965
1025
@@ -1001,12 +1061,12 @@ def register_klass(cls, klass: _T, custom_name: Optional[str],
1001
1061
})
1002
1062
1003
1063
if SerializationType .JSON in serialization_types :
1004
- klass .as_json = _as_json # type: ignore
1005
- klass .from_json = classmethod (_from_json ) # type: ignore
1064
+ klass .as_json = _as_json # type:ignore[attr-defined]
1065
+ klass .from_json = classmethod (_from_json ) # type:ignore[attr-defined]
1006
1066
1007
1067
if SerializationType .XML in serialization_types :
1008
- klass .as_xml = _as_xml # type: ignore
1009
- klass .from_xml = classmethod (_from_xml ) # type: ignore
1068
+ klass .as_xml = _as_xml # type:ignore[attr-defined]
1069
+ klass .from_xml = classmethod (_from_xml ) # type:ignore[attr-defined]
1010
1070
1011
1071
# Handle any deferred Properties depending on this class
1012
1072
if klass .__qualname__ in ObjectMetadataLibrary ._deferred_property_type_parsing :
@@ -1091,6 +1151,22 @@ def decorate(kls: Type[_T]) -> Type[_T]:
1091
1151
return decorate (cls )
1092
1152
1093
1153
1154
+ @overload
1155
+ def serializable_class (cls : Literal [None ], * , name : Optional [str ] = None ,
1156
+ serialization_types : Optional [Iterable [SerializationType ]] = None ,
1157
+ ignore_during_deserialization : Optional [Iterable [str ]] = None
1158
+ ) -> Callable [[Type [_T ]], Type [Union [_T , JsonSerializable , XmlSerializable ]]]:
1159
+ ...
1160
+
1161
+
1162
+ @overload
1163
+ def serializable_class (cls : Type [_T ], * , name : Optional [str ] = None ,
1164
+ serialization_types : Optional [Iterable [SerializationType ]] = None ,
1165
+ ignore_during_deserialization : Optional [Iterable [str ]] = None
1166
+ ) -> Type [Union [_T , JsonSerializable , XmlSerializable ]]:
1167
+ ...
1168
+
1169
+
1094
1170
def serializable_class (cls : Optional [Any ] = None , * , name : Optional [str ] = None ,
1095
1171
serialization_types : Optional [Iterable [SerializationType ]] = None ,
1096
1172
ignore_during_deserialization : Optional [Iterable [str ]] = None
@@ -1107,9 +1183,9 @@ def serializable_class(cls: Optional[Any] = None, *, name: Optional[str] = None,
1107
1183
if serialization_types is None :
1108
1184
serialization_types = _DEFAULT_SERIALIZATION_TYPES
1109
1185
1110
- def decorate (kls : Type [_T ]) -> Type [_T ]:
1186
+ def decorate (kls : Type [_T ]) -> Type [Union [ _T , JsonSerializable , XmlSerializable ] ]:
1111
1187
ObjectMetadataLibrary .register_klass (
1112
- klass = kls , custom_name = name , serialization_types = serialization_types or {} ,
1188
+ klass = kls , custom_name = name , serialization_types = serialization_types or [] ,
1113
1189
ignore_during_deserialization = ignore_during_deserialization
1114
1190
)
1115
1191
return kls
0 commit comments