From c2c6cf693266ccd013f1b3b2cba90eb3fc7d2e12 Mon Sep 17 00:00:00 2001 From: Walke Mirco Date: Fri, 10 Jul 2020 10:23:58 +0200 Subject: [PATCH 1/6] Fixed autofetch all pages when $top is set --- odata/query.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/odata/query.py b/odata/query.py index 4d276ad..5d54972 100644 --- a/odata/query.py +++ b/odata/query.py @@ -73,7 +73,7 @@ def __iter__(self): for row in value: yield self._create_model(row) - if '@odata.nextLink' in data: + if '@odata.nextLink' in data and not '$top' in options.keys(): #do not load next page on userpaging url = urljoin(self.entity.__odata_url_base__, data['@odata.nextLink']) options = {} # we get all options in the nextLink url else: From 1becf638b4a242f81f8a08c243fd69f3ce3187a5 Mon Sep 17 00:00:00 2001 From: Walke Mirco Date: Fri, 10 Jul 2020 10:34:37 +0200 Subject: [PATCH 2/6] *.code-workspace in .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 1eb011e..16567dd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ *.pyc *.pyo *.egg-info +*.code-workspace .idea dist build/ From f6362b69c6e6dd7b3a55ad9c55ab5fc026741cbb Mon Sep 17 00:00:00 2001 From: Walke Mirco Date: Fri, 10 Jul 2020 14:58:08 +0200 Subject: [PATCH 3/6] use response @odata.type to determine object class --- odata/navproperty.py | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/odata/navproperty.py b/odata/navproperty.py index 4c5527c..5316b45 100644 --- a/odata/navproperty.py +++ b/odata/navproperty.py @@ -57,10 +57,20 @@ def __repr__(self): def instances_from_data(self, raw_data): if self.is_collection: - return [self.entitycls.__new__(self.entitycls, from_data=d) for d in raw_data] + return [self.instance_from_data(d) for d in raw_data['value']] if raw_data['value'] else [] else: - return self.entitycls.__new__(self.entitycls, from_data=raw_data) - + return self.instance_from_data(raw_data) if raw_data else None + + def instance_from_data(self, raw_data): + entitycls = self._getClass_by_response_type(raw_data.get('@odata.type')) + return entitycls.__new__(entitycls, from_data=raw_data) + + def _getClass_by_response_type(self, odata_type): + if not odata_type: return self.entitycls + for subclass in self.entitycls.__subclasses__(): + if subclass.__odata_type__ == odata_type[1:]: return subclass + return self.entitycls + def _get_parent_cache(self, instance): es = instance.__odata__ ic = es.nav_cache @@ -102,20 +112,11 @@ def __get__(self, instance, owner): parent_url += '/' url = urljoin(parent_url, self.name) - - if self.is_collection: - if 'collection' not in cache: - raw_data = connection.execute_get(url) - if raw_data: - cache['collection'] = self.instances_from_data(raw_data['value']) - else: - cache['collection'] = [] - return cache['collection'] - else: - if 'single' not in cache: - raw_data = connection.execute_get(url) - if raw_data: - cache['single'] = self.instances_from_data(raw_data) - else: - cache['single'] = None - return cache['single'] + cache_type = 'collection' if self.is_collection else 'single' + + try: + return cache[cache_type] + except KeyError: + raw_data = connection.execute_get(url) + cache[cache_type] = self.instances_from_data(raw_data) + return cache[cache_type] \ No newline at end of file From 8eec95708d9d0fc55d904b6f8da8436984ea1e7f Mon Sep 17 00:00:00 2001 From: Walke Mirco Date: Fri, 10 Jul 2020 15:21:03 +0200 Subject: [PATCH 4/6] more ignores --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 16567dd..1174eae 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ dist build/ doc/_build/ venv/ +.vscode/ +debug.py From 9cec08f30951d0cc669521233b7f9c582c885b50 Mon Sep 17 00:00:00 2001 From: Walke Mirco Date: Fri, 10 Jul 2020 14:58:08 +0200 Subject: [PATCH 5/6] use response @odata.type to determine object class --- odata/navproperty.py | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/odata/navproperty.py b/odata/navproperty.py index 4c5527c..5316b45 100644 --- a/odata/navproperty.py +++ b/odata/navproperty.py @@ -57,10 +57,20 @@ def __repr__(self): def instances_from_data(self, raw_data): if self.is_collection: - return [self.entitycls.__new__(self.entitycls, from_data=d) for d in raw_data] + return [self.instance_from_data(d) for d in raw_data['value']] if raw_data['value'] else [] else: - return self.entitycls.__new__(self.entitycls, from_data=raw_data) - + return self.instance_from_data(raw_data) if raw_data else None + + def instance_from_data(self, raw_data): + entitycls = self._getClass_by_response_type(raw_data.get('@odata.type')) + return entitycls.__new__(entitycls, from_data=raw_data) + + def _getClass_by_response_type(self, odata_type): + if not odata_type: return self.entitycls + for subclass in self.entitycls.__subclasses__(): + if subclass.__odata_type__ == odata_type[1:]: return subclass + return self.entitycls + def _get_parent_cache(self, instance): es = instance.__odata__ ic = es.nav_cache @@ -102,20 +112,11 @@ def __get__(self, instance, owner): parent_url += '/' url = urljoin(parent_url, self.name) - - if self.is_collection: - if 'collection' not in cache: - raw_data = connection.execute_get(url) - if raw_data: - cache['collection'] = self.instances_from_data(raw_data['value']) - else: - cache['collection'] = [] - return cache['collection'] - else: - if 'single' not in cache: - raw_data = connection.execute_get(url) - if raw_data: - cache['single'] = self.instances_from_data(raw_data) - else: - cache['single'] = None - return cache['single'] + cache_type = 'collection' if self.is_collection else 'single' + + try: + return cache[cache_type] + except KeyError: + raw_data = connection.execute_get(url) + cache[cache_type] = self.instances_from_data(raw_data) + return cache[cache_type] \ No newline at end of file From 026d55b6182b28fcf512aa6b8cb98e52c7acb764 Mon Sep 17 00:00:00 2001 From: Norritt Addarkar <12830480+Addarkar@users.noreply.github.com> Date: Sat, 11 Jul 2020 15:55:15 +0200 Subject: [PATCH 6/6] Navproperty result is now a full featured object, same as query result object --- odata/navproperty.py | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/odata/navproperty.py b/odata/navproperty.py index 5316b45..7828e95 100644 --- a/odata/navproperty.py +++ b/odata/navproperty.py @@ -55,21 +55,24 @@ def __init__(self, name, entitycls, collection=False, foreign_key=None): def __repr__(self): return u''.format(self.entitycls) - def instances_from_data(self, raw_data): + def instances_from_data(self, raw_data, connection): if self.is_collection: - return [self.instance_from_data(d) for d in raw_data['value']] if raw_data['value'] else [] + return [self.instance_from_data(d, connection) for d in raw_data['value']] if raw_data['value'] else [] else: - return self.instance_from_data(raw_data) if raw_data else None - - def instance_from_data(self, raw_data): - entitycls = self._getClass_by_response_type(raw_data.get('@odata.type')) - return entitycls.__new__(entitycls, from_data=raw_data) + return self.instance_from_data(raw_data, connection) if raw_data else None + + def instance_from_data(self, raw_data, connection): # mwa: this needs to be seperated form navproperty + entitycls = self._getClass_by_response_type(self.entitycls, raw_data.get('@odata.type')) + e = entitycls.__new__(entitycls, from_data=raw_data) + es = e.__odata__ + es.connection = connection + return e - def _getClass_by_response_type(self, odata_type): - if not odata_type: return self.entitycls - for subclass in self.entitycls.__subclasses__(): - if subclass.__odata_type__ == odata_type[1:]: return subclass - return self.entitycls + def _getClass_by_response_type(self, matched_class, odata_type): + if not odata_type: return matched_class + for subclass in matched_class.__subclasses__(): + if subclass.__odata_type__ == odata_type[1:]: return self._getClass_by_response_type(subclass, odata_type) + return matched_class def _get_parent_cache(self, instance): es = instance.__odata__ @@ -118,5 +121,5 @@ def __get__(self, instance, owner): return cache[cache_type] except KeyError: raw_data = connection.execute_get(url) - cache[cache_type] = self.instances_from_data(raw_data) + cache[cache_type] = self.instances_from_data(raw_data, connection) return cache[cache_type] \ No newline at end of file