Skip to content

Commit 74393b8

Browse files
committed
fix: typehints
Signed-off-by: Jan Kowalleck <[email protected]>
1 parent 76c566c commit 74393b8

File tree

1 file changed

+91
-15
lines changed

1 file changed

+91
-15
lines changed

serializable/__init__.py

+91-15
Original file line numberDiff line numberDiff line change
@@ -16,28 +16,43 @@
1616
#
1717
# SPDX-License-Identifier: Apache-2.0
1818
# Copyright (c) Paul Horton. All Rights Reserved.
19+
1920
import enum
2021
import inspect
2122
import json
2223
import logging
2324
import os
2425
import re
25-
import typing # noqa: F401
2626
import warnings
2727
from copy import copy
2828
from decimal import Decimal
2929
from io import StringIO, TextIOWrapper
3030
from json import JSONEncoder
3131
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+
)
3348
from xml.etree.ElementTree import Element, SubElement
3449

3550
from defusedxml import ElementTree as SafeElementTree # type: ignore
3651

3752
if version_info >= (3, 8):
3853
from typing import Protocol
3954
else:
40-
from typing_extensions import Protocol # type: ignore
55+
from typing_extensions import Protocol # type: ignore[assignment]
4156

4257
from .formatters import BaseNameFormatter, CurrentFormatter
4358
from .helpers import BaseHelper
@@ -61,6 +76,37 @@ class _Klass(Protocol):
6176
ViewType = _Klass
6277

6378

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+
64110
@enum.unique
65111
class SerializationType(str, enum.Enum):
66112
"""
@@ -230,7 +276,7 @@ def _as_json(self: _T, view_: Optional[Type[Any]] = None) -> str:
230276
return json.dumps(self, cls=_SerializableJsonEncoder, view_=view_)
231277

232278

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]:
234280
"""
235281
Internal function that is injected into Classes that are annotated for serialization and deserialization by
236282
``serializable``.
@@ -318,7 +364,20 @@ def _from_json(cls: Type[_T], data: Dict[str, Any]) -> object:
318364
return cls(**_data)
319365

320366

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,
322381
xmlns: Optional[str] = None) -> Union[Element, str]:
323382
logging.debug(f'Dumping {self} to XML with view {view_}...')
324383

@@ -443,7 +502,7 @@ def _as_xml(self: _T, view_: Optional[Type[_T]] = None, as_string: bool = True,
443502

444503

445504
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]:
447506
logging.debug(f'Rendering XML from {type(data)} to {cls}...')
448507
klass = ObjectMetadataLibrary.klass_mappings.get(f'{cls.__module__}.{cls.__qualname__}', None)
449508
if klass is None:
@@ -638,7 +697,7 @@ def __init__(self, *, klass: Any, custom_name: Optional[str] = None,
638697
if serialization_types is None:
639698
serialization_types = _DEFAULT_SERIALIZATION_TYPES
640699
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 [])
642701

643702
@property
644703
def name(self) -> str:
@@ -957,9 +1016,10 @@ def register_enum(cls, klass: _T) -> _T:
9571016
return klass
9581017

9591018
@classmethod
960-
def register_klass(cls, klass: _T, custom_name: Optional[str],
1019+
def register_klass(cls, klass: Type[_T], custom_name: Optional[str],
9611020
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]]:
9631023
if cls.is_klass_serializable(klass=klass):
9641024
return klass
9651025

@@ -1001,12 +1061,12 @@ def register_klass(cls, klass: _T, custom_name: Optional[str],
10011061
})
10021062

10031063
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]
10061066

10071067
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]
10101070

10111071
# Handle any deferred Properties depending on this class
10121072
if klass.__qualname__ in ObjectMetadataLibrary._deferred_property_type_parsing:
@@ -1091,6 +1151,22 @@ def decorate(kls: Type[_T]) -> Type[_T]:
10911151
return decorate(cls)
10921152

10931153

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+
10941170
def serializable_class(cls: Optional[Any] = None, *, name: Optional[str] = None,
10951171
serialization_types: Optional[Iterable[SerializationType]] = None,
10961172
ignore_during_deserialization: Optional[Iterable[str]] = None
@@ -1107,9 +1183,9 @@ def serializable_class(cls: Optional[Any] = None, *, name: Optional[str] = None,
11071183
if serialization_types is None:
11081184
serialization_types = _DEFAULT_SERIALIZATION_TYPES
11091185

1110-
def decorate(kls: Type[_T]) -> Type[_T]:
1186+
def decorate(kls: Type[_T]) -> Type[Union[_T, JsonSerializable, XmlSerializable]]:
11111187
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 [],
11131189
ignore_during_deserialization=ignore_during_deserialization
11141190
)
11151191
return kls

0 commit comments

Comments
 (0)