From 576ff7bf8faf57b9da44193be67d1a68d547645d Mon Sep 17 00:00:00 2001 From: Jan Kowalleck Date: Mon, 8 Jan 2024 12:58:51 +0100 Subject: [PATCH] refactor: simplify imports Signed-off-by: Jan Kowalleck --- serializable/__init__.py | 46 +++++++++++++++++--------------------- serializable/formatters.py | 10 ++++----- serializable/helpers.py | 4 ++-- 3 files changed, 27 insertions(+), 33 deletions(-) diff --git a/serializable/__init__.py b/serializable/__init__.py index 3cf50cb..05ac496 100644 --- a/serializable/__init__.py +++ b/serializable/__init__.py @@ -17,23 +17,23 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright (c) Paul Horton. All Rights Reserved. -import enum -import inspect -import json -import re from copy import copy from decimal import Decimal +from enum import Enum, EnumMeta, unique +from inspect import getfullargspec, getmembers, isclass from io import StringIO, TextIOBase -from json import JSONEncoder +from json import JSONEncoder, dumps as json_dumps from logging import NullHandler, getLogger +from re import compile as re_compile, search as re_search from typing import ( - TYPE_CHECKING, Any, Callable, Dict, Iterable, List, + Literal, Optional, + Protocol, Set, Tuple, Type, @@ -49,12 +49,6 @@ from .formatters import BaseNameFormatter, CurrentFormatter from .helpers import BaseHelper -if TYPE_CHECKING: # pragma: no cover - from typing import Literal, Protocol -else: - from abc import ABC - Protocol = ABC - # `Intersection` is still not implemented, so it is interim replaced by Union for any support # see section "Intersection" in https://peps.python.org/pep-0483/ # see https://github.com/python/typing/issues/213 @@ -84,11 +78,11 @@ class ViewType: _F = TypeVar('_F', bound=Callable[..., Any]) _T = TypeVar('_T') -_E = TypeVar('_E', bound=enum.Enum) +_E = TypeVar('_E', bound=Enum) -@enum.unique -class SerializationType(str, enum.Enum): +@unique +class SerializationType(str, Enum): """ Enum to define the different formats supported for serialization and deserialization. """ @@ -103,8 +97,8 @@ class SerializationType(str, enum.Enum): ) -@enum.unique -class XmlArraySerializationType(enum.Enum): +@unique +class XmlArraySerializationType(Enum): """ Enum to differentiate how array-type properties (think Iterables) are serialized. @@ -183,7 +177,7 @@ def view(self) -> Optional[Type[ViewType]]: def default(self, o: Any) -> Any: # Enum - if isinstance(o, enum.Enum): + if isinstance(o, Enum): return o.value # Iterables @@ -260,7 +254,7 @@ def as_json(self: Any, view_: Optional[Type[ViewType]] = None) -> str: ``serializable``. """ _logger.debug('Dumping %s to JSON with view: %s...', self, view_) - return json.dumps(self, cls=_SerializableJsonEncoder, view_=view_) + return json_dumps(self, cls=_SerializableJsonEncoder, view_=view_) @classmethod def from_json(cls: Type[_T], data: Dict[str, Any]) -> Optional[_T]: @@ -517,7 +511,7 @@ def from_xml(cls: Type[_T], data: Union[TextIOBase, Element], _namespaces = dict([node for _, node in SafeElementTree.iterparse(StringIO(SafeElementTree.tostring(data, 'unicode')), events=['start-ns'])]) - default_namespace = (re.compile(r'^\{(.*?)\}.').search(data.tag) or (None, _namespaces.get('')))[1] + default_namespace = (re_compile(r'^\{(.*?)\}.').search(data.tag) or (None, _namespaces.get('')))[1] if default_namespace is None: def strip_default_namespace(s: str) -> str: @@ -678,7 +672,7 @@ class ObjectMetadataLibrary: _klass_property_types: Dict[str, type] = {} _klass_property_views: Dict[str, Set[Type[ViewType]]] = {} _klass_property_xml_sequence: Dict[str, int] = {} - custom_enum_klasses: Set[Type[enum.Enum]] = set() + custom_enum_klasses: Set[Type[Enum]] = set() klass_mappings: Dict[str, 'ObjectMetadataLibrary.SerializableClass'] = {} klass_property_mappings: Dict[str, Dict[str, 'ObjectMetadataLibrary.SerializableProperty']] = {} @@ -847,7 +841,7 @@ def get_none_value(self, view_: Optional[Type[ViewType]] = None) -> Any: def is_helper_type(self) -> bool: ct = self.custom_type - return inspect.isclass(ct) and issubclass(ct, BaseHelper) + return isclass(ct) and issubclass(ct, BaseHelper) def is_primitive_type(self) -> bool: return self.concrete_type in self._PRIMITIVE_TYPES @@ -868,7 +862,7 @@ def _parse_type(self, type_: Any) -> None: self._is_optional = True type_to_parse = type_to_parse[9:-1] - match = re.search(r"^(?P[\w.]+)\[['\"]?(?P\w+)['\"]?]$", type_to_parse) + match = re_search(r"^(?P[\w.]+)\[['\"]?(?P\w+)['\"]?]$", type_to_parse) if match: results = match.groupdict() if results.get('array_type', None) in self._SORTED_CONTAINERS_TYPES: @@ -956,7 +950,7 @@ def _parse_type(self, type_: Any) -> None: self._concrete_type = self.type_ # Handle Enums - if issubclass(type(self.concrete_type), enum.EnumMeta): + if issubclass(type(self.concrete_type), EnumMeta): self._is_enum = True # Ensure marked as not deferred @@ -1033,9 +1027,9 @@ def register_klass(cls, klass: Type[_T], custom_name: Optional[str], qualified_class_name = f'{klass.__module__}.{klass.__qualname__}' cls.klass_property_mappings.update({qualified_class_name: {}}) _logger.debug('Registering Class %s with custom name %s', qualified_class_name, custom_name) - for name, o in inspect.getmembers(klass, ObjectMetadataLibrary.is_property): + for name, o in getmembers(klass, ObjectMetadataLibrary.is_property): qualified_property_name = f'{qualified_class_name}.{name}' - prop_arg_specs = inspect.getfullargspec(o.fget) + prop_arg_specs = getfullargspec(o.fget) cls.klass_property_mappings[qualified_class_name].update({ name: ObjectMetadataLibrary.SerializableProperty( diff --git a/serializable/formatters.py b/serializable/formatters.py index 2925724..affba22 100644 --- a/serializable/formatters.py +++ b/serializable/formatters.py @@ -17,8 +17,8 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright (c) Paul Horton. All Rights Reserved. -import re from abc import ABC, abstractmethod +from re import compile as re_compile from typing import Type @@ -49,8 +49,8 @@ def encode_handle_python_builtins_and_keywords(cls, name: str) -> str: class CamelCasePropertyNameFormatter(BaseNameFormatter): - _ENCODE_PATTERN = re.compile(r'_([a-z])') - _DECODE_PATTERN = re.compile(r'(? str: @@ -67,7 +67,7 @@ def decode(cls, property_name: str) -> str: class KebabCasePropertyNameFormatter(BaseNameFormatter): - _ENCODE_PATTERN = re.compile(r'(_)') + _ENCODE_PATTERN = re_compile(r'(_)') @classmethod def encode(cls, property_name: str) -> str: @@ -81,7 +81,7 @@ def decode(cls, property_name: str) -> str: class SnakeCasePropertyNameFormatter(BaseNameFormatter): - _ENCODE_PATTERN = re.compile(r'(.)([A-Z][a-z]+)') + _ENCODE_PATTERN = re_compile(r'(.)([A-Z][a-z]+)') @classmethod def encode(cls, property_name: str) -> str: diff --git a/serializable/helpers.py b/serializable/helpers.py index fe596ad..d0e2721 100644 --- a/serializable/helpers.py +++ b/serializable/helpers.py @@ -17,9 +17,9 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright (c) Paul Horton. All Rights Reserved. -import re from datetime import date, datetime from logging import getLogger +from re import sub as re_sub from typing import TYPE_CHECKING, Any, Optional, Type, TypeVar, Union if TYPE_CHECKING: # pragma: no cover @@ -191,7 +191,7 @@ def deserialize(cls, o: Any) -> datetime: o = str(o)[1:] # Ensure any milliseconds are 6 digits - o = re.sub(r'\.(\d{1,6})', lambda v: f'.{int(v.group()[1:]):06}', str(o)) + o = re_sub(r'\.(\d{1,6})', lambda v: f'.{int(v.group()[1:]):06}', str(o)) if str(o).endswith('Z'): # Replace ZULU time with 00:00 offset