diff --git a/CHANGELOG.md b/CHANGELOG.md index 14bd059..4178e2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Changed + +- chore: zero-argument `super()` everywhere and PEP 604 unions in `isinstance` checks, now that Python 3.10 is the minimum (#302) - Sena Köse + ### Fixed - model: escape single quotes in `Edm.String` literals, so filters on values containing an apostrophe produce a valid OData query - Francois Pilet diff --git a/pyodata/exceptions.py b/pyodata/exceptions.py index 9d7c387..4f84094 100644 --- a/pyodata/exceptions.py +++ b/pyodata/exceptions.py @@ -32,7 +32,7 @@ def __new__(cls, message, response): return super(HttpError, cls).__new__(cls, message, response) def __init__(self, message, response): - super(HttpError, self).__init__(message) + super().__init__(message) self.response = response diff --git a/pyodata/v2/model.py b/pyodata/v2/model.py index 0470ed3..9d6b912 100644 --- a/pyodata/v2/model.py +++ b/pyodata/v2/model.py @@ -150,7 +150,7 @@ def retain_null(self): class Identifier: def __init__(self, name): - super(Identifier, self).__init__() + super().__init__() self._name = name @@ -347,7 +347,7 @@ class EdmPrefixedTypTraits(TypTraits): """Is good for all types where values have form: prefix'value'""" def __init__(self, prefix): - super(EdmPrefixedTypTraits, self).__init__() + super().__init__() self._prefix = prefix def to_literal(self, value): @@ -423,7 +423,7 @@ class EdmDateTimeTypTraits(EdmPrefixedTypTraits): """ def __init__(self): - super(EdmDateTimeTypTraits, self).__init__('datetime') + super().__init__('datetime') def to_literal(self, value): """Convert python datetime representation to literal format @@ -440,7 +440,7 @@ def to_literal(self, value): raise PyODataModelError('Edm.DateTime accepts only UTC') # Sets timezone to none to avoid including timezone information in the literal form. - return super(EdmDateTimeTypTraits, self).to_literal(value.replace(tzinfo=None).isoformat()) + return super().to_literal(value.replace(tzinfo=None).isoformat()) def to_json(self, value): if isinstance(value, str): @@ -484,7 +484,7 @@ def from_literal(self, value): if value is None: return None - value = super(EdmDateTimeTypTraits, self).from_literal(value) + value = super().from_literal(value) return parse_datetime_literal(value).replace(tzinfo=datetime.timezone.utc) @@ -509,7 +509,7 @@ class EdmDateTimeOffsetTypTraits(EdmPrefixedTypTraits): """ def __init__(self): - super(EdmDateTimeOffsetTypTraits, self).__init__('datetimeoffset') + super().__init__('datetimeoffset') def to_literal(self, value): """Convert python datetime representation to literal format""" @@ -518,7 +518,7 @@ def to_literal(self, value): raise PyODataModelError( f'Cannot convert value of type {type(value)} to literal. Datetime format including offset is required.') - return super(EdmDateTimeOffsetTypTraits, self).to_literal(value.isoformat()) + return super().to_literal(value.isoformat()) def to_json(self, value): # datetime.timestamp() does not work due to its limited precision @@ -552,7 +552,7 @@ def from_literal(self, value): if value is None: return None - value = super(EdmDateTimeOffsetTypTraits, self).from_literal(value) + value = super().from_literal(value) try: normalized = value.upper().replace('Z', '+00:00') @@ -639,7 +639,7 @@ def __init__(self, precision, suffix, conversion): self.conversion = conversion def __repr__(self): - parent = super(EdmFPNumTypTraits, self).__repr__() + parent = super().__repr__() return f'{parent}({self.precision},{self.suffix})' @@ -677,7 +677,7 @@ class EdmStructTypTraits(TypTraits): """Edm structural types (EntityType, ComplexType) traits""" def __init__(self, edm_type=None): - super(EdmStructTypTraits, self).__init__() + super().__init__() self._edm_type = edm_type # pylint: disable=no-self-use @@ -716,7 +716,7 @@ class Typ(Identifier): Kinds = Enum('Kinds', 'Primitive Complex') def __init__(self, name, null_value, traits=TypTraits(), kind=None): - super(Typ, self).__init__(name) + super().__init__(name) self._null_value = null_value self._kind = kind if kind is not None else Typ.Kinds.Primitive # no way how to us enum value for parameter default value @@ -743,7 +743,7 @@ class Collection(Typ): """Represents collection items""" def __init__(self, name, item_type): - super(Collection, self).__init__(name, [], kind=item_type.kind) + super().__init__(name, [], kind=item_type.kind) self._item_type = item_type def __repr__(self): @@ -780,7 +780,7 @@ class VariableDeclaration(Identifier): MAXIMUM_LENGTH = -1 def __init__(self, name, type_info, nullable, max_length, precision, scale, fixed_length=None): - super(VariableDeclaration, self).__init__(name) + super().__init__(name) self._type_info = type_info self._typ = None @@ -962,7 +962,7 @@ def __getitem__(self, key): raise KeyError(f'There is no Schema Namespace {key}') def __init__(self, config: Config): - super(Schema, self).__init__() + super().__init__() self._decls = Schema.Declarations() self._config = config @@ -1469,7 +1469,7 @@ def from_etree(schema_nodes, config: Config): class StructType(Typ): def __init__(self, name, label, is_value_list): - super(StructType, self).__init__(name, None, EdmStructTypTraits(self), Typ.Kinds.Complex) + super().__init__(name, None, EdmStructTypTraits(self), Typ.Kinds.Complex) self._label = label self._is_value_list = is_value_list @@ -1565,7 +1565,7 @@ def parent(self): class EnumType(Identifier): def __init__(self, name, is_flags, underlying_type, namespace): - super(EnumType, self).__init__(name) + super().__init__(name) self._member = list() self._underlying_type = underlying_type self._traits = TypTraits() @@ -1656,7 +1656,7 @@ def namespace(self): class EntityType(StructType): def __init__(self, name, label, is_value_list): - super(EntityType, self).__init__(name, label, is_value_list) + super().__init__(name, label, is_value_list) self._key = list() self._nav_properties = dict() @@ -1695,7 +1695,7 @@ def from_etree(cls, type_node, config: Config): class EntitySet(Identifier): def __init__(self, name, entity_type_info, addressable, creatable, updatable, deletable, searchable, countable, pageable, topable, req_filter, label): - super(EntitySet, self).__init__(name) + super().__init__(name) self._entity_type_info = entity_type_info self._entity_type = None @@ -1803,7 +1803,7 @@ class StructTypeProperty(VariableDeclaration): def __init__(self, name, type_info, nullable, max_length, precision, scale, uncode, label, creatable, updatable, sortable, filterable, filter_restr, req_in_filter, text, visible, display_format, value_list, fixed_length=None): - super(StructTypeProperty, self).__init__(name, type_info, nullable, max_length, precision, scale, fixed_length) + super().__init__(name, type_info, nullable, max_length, precision, scale, fixed_length) self._value_helper = None self._struct_type = None @@ -1964,7 +1964,7 @@ class NavigationTypeProperty(VariableDeclaration): """ def __init__(self, name, from_role_name, to_role_name, association_info): - super(NavigationTypeProperty, self).__init__(name, None, False, None, None, None, None) + super().__init__(name, None, False, None, None, None, None) self.from_role_name = from_role_name self.to_role_name = to_role_name @@ -2304,7 +2304,7 @@ class Annotation: Kinds = Enum('Kinds', 'ValueHelper') def __init__(self, kind, target, qualifier=None): - super(Annotation, self).__init__() + super().__init__() self._kind = kind self._element_namespace, self._element = target.split('.') @@ -2360,7 +2360,7 @@ def __init__(self, target, collection_path, label, search_supported): # pylint: disable=unused-argument - super(ValueHelper, self).__init__(Annotation.Kinds.ValueHelper, target) + super().__init__(Annotation.Kinds.ValueHelper, target) self._entity_type_name, self._proprty_name = self.element.split('/') self._proprty = None @@ -2486,7 +2486,7 @@ class ValueHelperParameter: Direction = Enum('Direction', 'In InOut Out DisplayOnly FilterOnly Constant Constants') def __init__(self, direction, local_property_name, list_property_name): - super(ValueHelperParameter, self).__init__() + super().__init__() self._direction = direction self._value_helper = None @@ -2566,7 +2566,7 @@ def from_etree(value_help_parameter_node): class FunctionImport(Identifier): def __init__(self, name, return_type_info, entity_set, parameters, http_method='GET'): - super(FunctionImport, self).__init__(name) + super().__init__(name) self._entity_set_name = entity_set self._return_type_info = return_type_info @@ -2637,7 +2637,7 @@ class FunctionImportParameter(VariableDeclaration): Modes = Enum('Modes', 'In Out InOut') def __init__(self, name, type_info, nullable, max_length, precision, scale, mode): - super(FunctionImportParameter, self).__init__(name, type_info, nullable, max_length, precision, scale, None) + super().__init__(name, type_info, nullable, max_length, precision, scale, None) self._mode = mode diff --git a/pyodata/v2/service.py b/pyodata/v2/service.py index 97145a1..10b5d7a 100644 --- a/pyodata/v2/service.py +++ b/pyodata/v2/service.py @@ -383,8 +383,8 @@ class EntityGetRequest(ODataHttpRequest): """Used for GET operations of a single entity""" def __init__(self, handler, entity_key, entity_set_proxy, encode_path=True): - super(EntityGetRequest, self).__init__(entity_set_proxy.service.url, entity_set_proxy.service.connection, - handler, response_hook=entity_set_proxy.service.response_hook) + super().__init__(entity_set_proxy.service.url, entity_set_proxy.service.connection, + handler, response_hook=entity_set_proxy.service.response_hook) self._logger = logging.getLogger(LOGGER_NAME) self._entity_key = entity_key self._entity_set_proxy = entity_set_proxy @@ -423,7 +423,7 @@ def get_default_headers(self): return {'Accept': 'application/json'} def get_query_params(self): - qparams = super(EntityGetRequest, self).get_query_params() + qparams = super().get_query_params() if self._select is not None: qparams['$select'] = self._select @@ -462,12 +462,12 @@ class NavEntityGetRequest(EntityGetRequest): """Used for GET operations of a single entity accessed via a Navigation property""" def __init__(self, handler, master_key, entity_set_proxy, nav_property): - super(NavEntityGetRequest, self).__init__(handler, master_key, entity_set_proxy) + super().__init__(handler, master_key, entity_set_proxy) self._nav_property = nav_property def get_path(self): - return f"{super(NavEntityGetRequest, self).get_path()}/{self._nav_property}" + return f"{super().get_path()}/{self._nav_property}" class EntityCreateRequest(ODataHttpRequest): @@ -477,7 +477,7 @@ class EntityCreateRequest(ODataHttpRequest): and get the newly created entity.""" def __init__(self, url, connection, handler, entity_set, last_segment=None, response_hook=None): - super(EntityCreateRequest, self).__init__(url, connection, handler, response_hook=response_hook) + super().__init__(url, connection, handler, response_hook=response_hook) self._logger = logging.getLogger(LOGGER_NAME) self._entity_set = entity_set self._entity_type = entity_set.entity_type @@ -564,7 +564,7 @@ class EntityDeleteRequest(ODataHttpRequest): """Used for deleting entity (DELETE operations on a single entity)""" def __init__(self, url, connection, handler, entity_set, entity_key, encode_path=True, response_hook=None): - super(EntityDeleteRequest, self).__init__(url, connection, handler, response_hook=response_hook) + super().__init__(url, connection, handler, response_hook=response_hook) self._logger = logging.getLogger(LOGGER_NAME) self._entity_set = entity_set self._entity_key = entity_key @@ -598,7 +598,7 @@ class EntityModifyRequest(ODataHttpRequest): # pylint: disable=too-many-arguments def __init__(self, url, connection, handler, entity_set, entity_key, method="PATCH", encode_path=True, response_hook=None): - super(EntityModifyRequest, self).__init__(url, connection, handler, response_hook=response_hook) + super().__init__(url, connection, handler, response_hook=response_hook) self._logger = logging.getLogger(LOGGER_NAME) self._entity_set = entity_set self._entity_type = entity_set.entity_type @@ -663,7 +663,7 @@ class QueryRequest(ODataHttpRequest): # pylint: disable=too-many-instance-attributes def __init__(self, url, connection, handler, last_segment, response_hook=None): - super(QueryRequest, self).__init__(url, connection, handler, response_hook=response_hook) + super().__init__(url, connection, handler, response_hook=response_hook) self._logger = logging.getLogger(LOGGER_NAME) self._count = None @@ -750,7 +750,7 @@ def get_query_params(self): if self._next_url: return {} - qparams = super(QueryRequest, self).get_query_params() + qparams = super().get_query_params() if self._top is not None: qparams['$top'] = self._top @@ -780,7 +780,7 @@ class FunctionRequest(QueryRequest): """Function import request (Service call)""" def __init__(self, url, connection, handler, function_import, response_hook=None): - super(FunctionRequest, self).__init__( + super().__init__( url, connection, handler, function_import.name, response_hook=response_hook) @@ -1074,7 +1074,7 @@ class NavEntityProxy(EntityProxy): def __init__(self, parent_entity, prop_name, entity_type, entity): # pylint: disable=protected-access - super(NavEntityProxy, self).__init__(parent_entity._service, parent_entity._entity_set, entity_type, entity) + super().__init__(parent_entity._service, parent_entity._entity_set, entity_type, entity) self._parent_entity = parent_entity self._prop_name = prop_name @@ -1317,7 +1317,7 @@ def _build_expression(self, field_name, operator, value): return f'substringof({value}, {field_name}) eq true' if operator == 'range': - if not isinstance(value, (tuple, list)): + if not isinstance(value, tuple | list): raise TypeError(f'Range must be tuple or list not {type(value)}') if len(value) != 2: @@ -1347,7 +1347,7 @@ class GetEntitySetRequest(QueryRequest): """GET on EntitySet""" def __init__(self, url, connection, handler, last_segment, entity_type, encode_path=True, response_hook=None): - super(GetEntitySetRequest, self).__init__(url, connection, handler, last_segment, response_hook=response_hook) + super().__init__(url, connection, handler, last_segment, response_hook=response_hook) self._entity_type = entity_type self._encode_path = encode_path @@ -1392,7 +1392,7 @@ class ListWithTotalCount(list): """ def __init__(self, total_count, next_url): - super(ListWithTotalCount, self).__init__() + super().__init__() self._total_count = total_count self._next_url = next_url @@ -1723,7 +1723,7 @@ def function_import_handler(fimport, response): response_data = response.json()['d'] # 1. if return type is an entity type or collection, resolve the entity set once - if isinstance(fimport.return_type, (model.EntityType, model.Collection)): + if isinstance(fimport.return_type, model.EntityType | model.Collection): entity_set = self._service.schema.entity_set(fimport.entity_set_name) if isinstance(fimport.return_type, model.EntityType): @@ -1915,7 +1915,7 @@ class MultipartRequest(ODataHttpRequest): """HTTP Batch request""" def __init__(self, url, connection, handler, request_id=None): - super(MultipartRequest, self).__init__(url, connection, partial(MultipartRequest.http_response_handler, self)) + super().__init__(url, connection, partial(MultipartRequest.http_response_handler, self)) self.requests = [] self._handler_decoded = handler diff --git a/pyodata/vendor/SAP.py b/pyodata/vendor/SAP.py index ef78b91..7dae5ed 100644 --- a/pyodata/vendor/SAP.py +++ b/pyodata/vendor/SAP.py @@ -99,6 +99,6 @@ def __init__(self, message, response): 'The HTTP error is not a SAP BusinessGateway JSON error') logging.debug('JSON parsing error: %s', str(ex)) - super(BusinessGatewayError, self).__init__(message, response) + super().__init__(message, response) self.errordetails = errordetails