Skip to content

Commit bfa215f

Browse files
phanak-sapfilak-sap
authored andcommitted
model: split entity_types and their generated Collections
Collection of entity type is not "Entity Type". Schema class should return for entity_type property only parsed <EntityType> elements, not with generated possible return types for another elements. Otherwise it is misleading API to user, in a sense that there are things in schema.entity_type that are not present in the XML. tests: Update Complex type parsing with Schema check model: fix Flake8 errors tests: update test_model to check better generated collections model: split complex_types and their generated Collections Update Changelog.md Remove unnecessary code.
1 parent 416504a commit bfa215f

File tree

3 files changed

+63
-9
lines changed

3 files changed

+63
-9
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
55
and this project adheres to [Semantic Versioning](http://semver.org/).
66

77
## [Unreleased]
8+
- model: split properties schema.entity_types/complex_types and their generated Collections - Petr Hanak
89

910
### Fixed
1011
- Fix Edm.Binary literal representation - Daniel Balko

pyodata/v2/model.py

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -176,15 +176,14 @@ def parse(value):
176176

177177

178178
class Types:
179-
"""Repository of all available OData types
179+
"""Repository of all available OData V2 primitive types + their Collection variants
180180
181181
Since each type has instance of appropriate type, this
182182
repository acts as central storage for all instances. The
183183
rule is: don't create any type instances if not necessary,
184184
always reuse existing instances if possible
185185
"""
186186

187-
# dictionary of all registered types (primitive, complex and collection variants)
188187
Types = None
189188

190189
@staticmethod
@@ -794,6 +793,10 @@ def __init__(self, namespace):
794793
self.associations = dict()
795794
self.association_sets = dict()
796795

796+
# generated collections for ease of lookup (e.g. function import return type)
797+
self._collections_entity_types = dict()
798+
self._collections_complex_types = dict()
799+
797800
def list_entity_types(self):
798801
return list(self.entity_types.values())
799802

@@ -823,9 +826,9 @@ def add_entity_type(self, etype):
823826
# automatically create and register collection variant if not exists
824827
if isinstance(etype, NullType):
825828
return
826-
827829
collection_type_name = f'Collection({etype.name})'
828-
self.entity_types[collection_type_name] = Collection(etype.name, etype)
830+
self._collections_entity_types[collection_type_name] = Collection(etype.name, etype)
831+
# TODO performance memory: this is generating collection for every entity type encoutered, regardless of such collection is really used.
829832

830833
def add_complex_type(self, ctype):
831834
"""Add new complex type to the type repository as well as its collection variant"""
@@ -835,9 +838,9 @@ def add_complex_type(self, ctype):
835838
# automatically create and register collection variant if not exists
836839
if isinstance(ctype, NullType):
837840
return
838-
839841
collection_type_name = f'Collection({ctype.name})'
840-
self.complex_types[collection_type_name] = Collection(ctype.name, ctype)
842+
self._collections_complex_types[collection_type_name] = Collection(ctype.name, ctype)
843+
# TODO performance memory: this is generating collection for every entity type encoutered, regardless of such collection is really used.
841844

842845
def add_enum_type(self, etype):
843846
"""Add new enum type to the type repository"""
@@ -881,7 +884,7 @@ def typ(self, type_name, namespace=None):
881884
"""Returns either EntityType, ComplexType or EnumType that matches the name.
882885
"""
883886

884-
for type_space in (self.entity_type, self.complex_type, self.enum_type):
887+
for type_space in (self.entity_type, self._collections_entity_types, self.complex_type, self._collections_complex_types, self.enum_type):
885888
try:
886889
return type_space(type_name, namespace=namespace)
887890
except KeyError:
@@ -905,6 +908,21 @@ def entity_type(self, type_name, namespace=None):
905908

906909
raise KeyError(f'EntityType {type_name} does not exist in any Schema Namespace')
907910

911+
def _collections_entity_types(self, type_name, namespace=None):
912+
if namespace is not None:
913+
try:
914+
return self._decls[namespace]._collections_entity_types[type_name]
915+
except KeyError:
916+
raise KeyError(f'EntityType collection {type_name} does not exist in Schema Namespace {namespace}')
917+
918+
for decl in list(self._decls.values()):
919+
try:
920+
return decl._collections_entity_types[type_name]
921+
except KeyError:
922+
pass
923+
924+
raise KeyError(f'EntityType collection {type_name} does not exist in any Schema Namespace')
925+
908926
def complex_type(self, type_name, namespace=None):
909927
if namespace is not None:
910928
try:
@@ -920,6 +938,21 @@ def complex_type(self, type_name, namespace=None):
920938

921939
raise KeyError(f'ComplexType {type_name} does not exist in any Schema Namespace')
922940

941+
def _collections_complex_types(self, type_name, namespace=None):
942+
if namespace is not None:
943+
try:
944+
return self._decls[namespace]._collections_complex_types[type_name]
945+
except KeyError:
946+
raise KeyError(f'ComplexType collection {type_name} does not exist in Schema Namespace {namespace}')
947+
948+
for decl in list(self._decls.values()):
949+
try:
950+
return decl._collections_complex_types[type_name]
951+
except KeyError:
952+
pass
953+
954+
raise KeyError(f'ComplexType collection {type_name} does not exist in any Schema Namespace')
955+
923956
def enum_type(self, type_name, namespace=None):
924957
if namespace is not None:
925958
try:
@@ -946,18 +979,28 @@ def get_type(self, type_info):
946979
except KeyError:
947980
pass
948981

949-
# then look for type in entity types
982+
# then look for type in entity types and collections of entity types
950983
try:
951984
return self.entity_type(search_name, type_info.namespace)
952985
except KeyError:
953986
pass
954987

955-
# then look for type in complex types
988+
try:
989+
return self._collections_entity_types(search_name, type_info.namespace)
990+
except KeyError:
991+
pass
992+
993+
# then look for type in complex types and collections of complex types
956994
try:
957995
return self.complex_type(search_name, type_info.namespace)
958996
except KeyError:
959997
pass
960998

999+
try:
1000+
return self._collections_complex_types(search_name, type_info.namespace)
1001+
except KeyError:
1002+
pass
1003+
9611004
# then look for type in enum types
9621005
try:
9631006
return self.enum_type(search_name, type_info.namespace)

tests/test_model_v2.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,11 +135,18 @@ def test_edmx(schema):
135135
assert schema.typ('MasterEntity') == schema.entity_type('MasterEntity')
136136
assert schema.typ('MasterEntity', namespace='EXAMPLE_SRV') == schema.entity_type('MasterEntity',
137137
namespace='EXAMPLE_SRV')
138+
# check that the collection of this EntityType was generated
139+
assert schema.typ('Collection(MasterEntity)', namespace='EXAMPLE_SRV') == schema._collections_entity_types('Collection(MasterEntity)',
140+
namespace='EXAMPLE_SRV')
138141

139142
# ComplexType from the method typ
140143
assert schema.typ('Building') == schema.complex_type('Building')
141144
assert schema.typ('Building', namespace='EXAMPLE_SRV') == schema.complex_type('Building', namespace='EXAMPLE_SRV')
142145

146+
# check that the collection of this ComplexType was generated
147+
assert schema.typ('Collection(Building)', namespace='EXAMPLE_SRV') == schema._collections_complex_types(
148+
'Collection(Building)',namespace='EXAMPLE_SRV')
149+
143150
# Error handling in the method typ - without namespace
144151
with pytest.raises(KeyError) as typ_ex_info:
145152
assert schema.typ('FooBar')
@@ -349,6 +356,9 @@ def test_edmx_complex_types(schema):
349356
assert str(real_prop) == 'StructTypeProperty(Real)'
350357
assert str(real_prop.struct_type) == 'ComplexType(ComplexNumber)'
351358

359+
# after correct parsing, new complex type is registered in metadata schema
360+
assert str(schema.typ('ComplexNumber')) == 'ComplexType(ComplexNumber)'
361+
assert str(schema.typ('Collection(ComplexNumber)')) == 'Collection(ComplexNumber)'
352362

353363
def test_edmx_complex_type_prop_vh(schema):
354364
"""Check that value helpers work also for ComplexType properties and aliases"""

0 commit comments

Comments
 (0)