From 93051aa0e24d3bb919085b5f2df6d72935d6ec3d Mon Sep 17 00:00:00 2001 From: Sebastian Dransfeld Date: Tue, 5 Nov 2024 07:40:09 +0100 Subject: [PATCH 1/4] Need enum name in escaped value --- odata/enumtype.py | 5 +++++ odata/reflector.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/odata/enumtype.py b/odata/enumtype.py index 8c032fa..216c5cb 100644 --- a/odata/enumtype.py +++ b/odata/enumtype.py @@ -21,6 +21,11 @@ def __init__(self, name, enum_class=EnumType): super(EnumTypeProperty, self).__init__(name) self.enum_class = enum_class + def escape_value(self, value): + if self.enum_class.__module__: + return f"{self.enum_class.__module__}.{self.enum_class.__name__}'{value.name}'" + return f"{self.enum_class.__name__}'{value.name}'" + def serialize(self, value): return value.name diff --git a/odata/reflector.py b/odata/reflector.py index e2e5f23..138c8d4 100644 --- a/odata/reflector.py +++ b/odata/reflector.py @@ -94,7 +94,7 @@ "FloatProperty": "float", "BooleanProperty": "bool", "UUIDProperty": "uuid.UUID", - "EnumTypeProperty": "str" + "EnumTypeProperty": "Enum" } From 55598054077e335baca67a28c1d6c1c555e7964d Mon Sep 17 00:00:00 2001 From: Sebastian Dransfeld Date: Tue, 25 Mar 2025 09:16:59 +0100 Subject: [PATCH 2/4] Do not remove property key values --- odata/state.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/odata/state.py b/odata/state.py index 32ffe18..cfe913d 100644 --- a/odata/state.py +++ b/odata/state.py @@ -244,9 +244,6 @@ def _clean_new_entity(self, entity, server_flags: ODataServerFlags): # Deep insert from nav properties for prop_name, prop in es.navigation_properties: - if prop.foreign_key: - insert_data.pop(prop.foreign_key, None) - value = getattr(entity, prop_name, None) """:type : None | odata.entity.EntityBase | list[odata.entity.EntityBase]""" if value is not None: From 94d76da8ad1d6fd1fe438800989c1bdedc22af2a Mon Sep 17 00:00:00 2001 From: Sebastian Dransfeld Date: Tue, 25 Mar 2025 09:24:13 +0100 Subject: [PATCH 3/4] Add missing docstring --- odata/service.py | 1 + 1 file changed, 1 insertion(+) diff --git a/odata/service.py b/odata/service.py index dc2aa68..dc7e03a 100644 --- a/odata/service.py +++ b/odata/service.py @@ -91,6 +91,7 @@ class ODataService(object): :param auth: Custom Requests auth object to use for credentials :param console: Rich console instance to use for messages. If set to None a new console will be created. Console will inherit quiet flag from quiet_progress. :param quiet_progress: Don't show any progress information while reflecting metadata and while other long duration tasks are running. Default is to show progress + :param server_flags: Server specific flags for an OData server :raises ODataConnectionError: Fetching metadata failed. Server returned an HTTP error code """ From e2354665119ace87a8228797d2d887bbdd96d439 Mon Sep 17 00:00:00 2001 From: Sebastian Dransfeld Date: Tue, 25 Mar 2025 09:25:02 +0100 Subject: [PATCH 4/4] Add timeout parameter --- odata/connection.py | 4 ++-- odata/context.py | 4 ++-- odata/service.py | 11 +++++++---- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/odata/connection.py b/odata/connection.py index d5ffea9..1d81874 100644 --- a/odata/connection.py +++ b/odata/connection.py @@ -28,15 +28,15 @@ class ODataConnection(object): 'OData-Version': '4.0', 'User-Agent': 'python-odata {0}'.format(version), } - timeout = 90 - def __init__(self, session=None, auth=None, extra_headers: dict = None): + def __init__(self, session=None, auth=None, extra_headers: dict = None, timeout=90): if session is None: self.session = requests.Session() else: self.session = session self.auth = auth self.log = logging.getLogger('odata.connection') + self.timeout = timeout self.extra_headers = extra_headers diff --git a/odata/context.py b/odata/context.py index f98bb52..a34f6f4 100644 --- a/odata/context.py +++ b/odata/context.py @@ -9,9 +9,9 @@ class Context: - def __init__(self, session=None, auth=None, extra_headers: dict = None, server_flags: ODataServerFlags = None): + def __init__(self, session=None, auth=None, extra_headers: dict = None, server_flags: ODataServerFlags = None, timeout=90): self.log = logging.getLogger('odata.context') - self.connection = ODataConnection(session=session, auth=auth, extra_headers=extra_headers) + self.connection = ODataConnection(session=session, auth=auth, extra_headers=extra_headers, timeout=timeout) self.server_flags = server_flags def query(self, entitycls): diff --git a/odata/service.py b/odata/service.py index dc7e03a..60cb382 100644 --- a/odata/service.py +++ b/odata/service.py @@ -92,6 +92,7 @@ class ODataService(object): :param console: Rich console instance to use for messages. If set to None a new console will be created. Console will inherit quiet flag from quiet_progress. :param quiet_progress: Don't show any progress information while reflecting metadata and while other long duration tasks are running. Default is to show progress :param server_flags: Server specific flags for an OData server + :param timeout: Connection timeout :raises ODataConnectionError: Fetching metadata failed. Server returned an HTTP error code """ @@ -105,13 +106,14 @@ def __init__(self, auth=None, console: rich.console.Console = None, quiet_progress: bool = False, - server_flags: ODataServerFlags = ODataServerFlags()): + server_flags: ODataServerFlags = ODataServerFlags(), + timeout=90): self.url = url if url.endswith("/") else url + "/" # make sure url ends with / otherwise we have problems self.metadata_url = urllib.parse.urljoin(self.url, "$metadata") self.collections = {} self.log = logging.getLogger('odata.service') self.server_flags = server_flags - self.default_context = Context(auth=auth, session=session, extra_headers=extra_headers, server_flags=server_flags) + self.default_context = Context(auth=auth, session=session, extra_headers=extra_headers, server_flags=server_flags, timeout=timeout) self.console = console if console is not None else rich.console.Console(quiet=quiet_progress) self.quiet_progress = quiet_progress @@ -204,17 +206,18 @@ def _write_reflected_types(self, metadata_url: str, package: str): outputter = MetadataReflector(metadata_url=metadata_url, entities=self.entities, types=self.types, package=package, quiet=self.quiet_progress) outputter.write_reflected_types() - def create_context(self, auth=None, session=None, extra_headers: dict = None): + def create_context(self, auth=None, session=None, extra_headers: dict = None, timeout=90): """ Create new context to use for session-like usage :param auth: Custom Requests auth object to use for credentials :param session: Custom Requests session to use for communication with the endpoint :param extra_headers: Any extra headers to pass to use for all communications + :param timeout: Connection timeout :return: Context instance :rtype: Context """ - return Context(auth=auth, session=session, extra_headers=extra_headers, server_flags=self.server_flags) + return Context(auth=auth, session=session, extra_headers=extra_headers, server_flags=self.server_flags, timeout=timeout) def describe(self, entity) -> None: """