Skip to content

Commit e9d1180

Browse files
committed
Remove enum type from OData V2
Despite implementing enum for V2 the first mention of enum in specification is only in later versions of OData. Thus, it should not be possible to parse enum using V2 parser.
1 parent ed5196d commit e9d1180

File tree

7 files changed

+111
-143
lines changed

7 files changed

+111
-143
lines changed

pyodata/v2/__init__.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,8 @@
1111

1212
from pyodata.v2.elements import NavigationTypeProperty, EndRole, Association, AssociationSetEndRole, AssociationSet, \
1313
ReferentialConstraint, Schema
14-
from pyodata.model.elements import StructTypeProperty, StructType, ComplexType, EntityType, \
15-
EnumType, EntitySet, ExternalAnnotation, Annotation, ValueHelper, ValueHelperParameter, \
16-
FunctionImport, Typ
14+
from pyodata.model.elements import StructTypeProperty, StructType, ComplexType, EntityType, EntitySet, \
15+
ExternalAnnotation, Annotation, ValueHelper, ValueHelperParameter, FunctionImport, Typ
1716

1817

1918
import pyodata.v2.build_functions as build_functions_v2
@@ -36,7 +35,6 @@ def build_functions():
3635
NavigationTypeProperty: build_functions_v2.build_navigation_type_property,
3736
ComplexType: build_functions.build_complex_type,
3837
EntityType: build_functions.build_entity_type,
39-
EnumType: build_functions.build_enum_type,
4038
EntitySet: build_functions.build_entity_set,
4139
EndRole: build_functions_v2.build_end_role,
4240
ReferentialConstraint: build_functions_v2.build_referential_constraint,

pyodata/v2/build_functions.py

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99

1010
from pyodata.config import Config
1111
from pyodata.exceptions import PyODataParserError, PyODataModelError
12-
from pyodata.model.elements import EntityType, ComplexType, EnumType, NullType, build_element, \
13-
EntitySet, FunctionImport, ExternalAnnotation, Annotation, Typ, Identifier, Types
12+
from pyodata.model.elements import EntityType, ComplexType, NullType, build_element, EntitySet, FunctionImport, \
13+
ExternalAnnotation, Annotation, Typ, Identifier, Types
1414
from pyodata.policies import ParserError
1515
from pyodata.v2.elements import AssociationSetEndRole, Association, AssociationSet, NavigationTypeProperty, EndRole, \
1616
Schema, NullAssociation, ReferentialConstraint, PrincipalRole, DependentRole
@@ -37,15 +37,6 @@ def build_schema(config: Config, schema_nodes):
3737
decl = Schema.Declaration(namespace)
3838
schema._decls[namespace] = decl
3939

40-
for enum_type in schema_node.xpath('edm:EnumType', namespaces=config.namespaces):
41-
try:
42-
etype = build_element(EnumType, config, type_node=enum_type, namespace=namespace)
43-
except (PyODataParserError, AttributeError) as ex:
44-
config.err_policy(ParserError.ENUM_TYPE).resolve(ex)
45-
etype = NullType(enum_type.get('Name'))
46-
47-
decl.add_enum_type(etype)
48-
4940
for complex_type in schema_node.xpath('edm:ComplexType', namespaces=config.namespaces):
5041
try:
5142
ctype = build_element(ComplexType, config, type_node=complex_type)

tests/metadata.xml

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -114,23 +114,6 @@
114114
<Property Name="Number" Type="Edm.String" Nullable="false"/>
115115
<Property Name="Owner" Type="Edm.String" Nullable="false"/>
116116
</EntityType>
117-
118-
<EntityType Name="EnumTest">
119-
<Property Name="CountryOfOrigin" Type="Country"/>
120-
</EntityType>
121-
122-
<EnumType Name="Country" UnderlyingType="Edm.Int32">
123-
<Member Name="USA"/>
124-
<Member Name="China"/>
125-
<Member Name="Slovakia"/>
126-
</EnumType>
127-
128-
<EnumType Name="Language" UnderlyingType="Edm.Int32" IsFlags="True">
129-
<Member Name="English"/>
130-
<Member Name="Czech"/>
131-
<Member Name="Japanese"/>
132-
</EnumType>
133-
134117
<ComplexType Name="ComplexNumber">
135118
<Property Name="Real" Type="Edm.Double" Nullable="false"/>
136119
<Property Name="Imaginary" Type="Edm.Double" Nullable="false"/>
@@ -201,7 +184,6 @@
201184
sap:topable="true"/>
202185
<EntitySet Name="CarIDPics" EntityType="EXAMPLE_SRV.CarIDPic" sap:countable="false" sap:pageable="false"
203186
sap:topable="false"/>
204-
<EntitySet Name="EnumTests" EntityType="EXAMPLE_SRV.EnumTest" />
205187
<FunctionImport Name="retrieve" ReturnType="Edm.Boolean" EntitySet="MasterEntities" m:HttpMethod="GET"
206188
sap:action-for="EXAMPLE_SRV.MasterEntity">
207189
<Parameter Name="Param" Type="Edm.String" Mode="In" MaxLenght="5"/>

tests/metadata_v4.xml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,19 @@
148148
</Key>
149149
<Property Name="ID" Type="Edm.String" Nullable="false" />
150150
</EntityType>
151+
<EntityType Name="EnumTest">
152+
<Property Name="CountryOfOrigin" Type="Country"/>
153+
</EntityType>
154+
<EnumType Name="Country" UnderlyingType="Edm.Int32">
155+
<Member Name="USA"/>
156+
<Member Name="China"/>
157+
<Member Name="Slovakia"/>
158+
</EnumType>
159+
<EnumType Name="Language" UnderlyingType="Edm.Int32" IsFlags="True">
160+
<Member Name="English"/>
161+
<Member Name="Czech"/>
162+
<Member Name="Japanese"/>
163+
</EnumType>
151164
<Function Name="GetFavoriteAirline" IsBound="true" EntitySetPath="person/Trips/PlanItems/Microsoft.OData.SampleService.Models.TripPin.Flight/Airline" IsComposable="true">
152165
<Parameter Name="person" Type="Microsoft.OData.SampleService.Models.TripPin.Person" Nullable="false" />
153166
<ReturnType Type="Microsoft.OData.SampleService.Models.TripPin.Airline" Nullable="false" />
@@ -173,6 +186,7 @@
173186
<Parameter Name="tripId" Type="Edm.Int32" Nullable="false" />
174187
</Action>
175188
<EntityContainer Name="DefaultContainer">
189+
<EntitySet Name="EnumTests" EntityType="Microsoft.OData.SampleService.Models.TripPin.EnumTest" />
176190
<EntitySet Name="Photos" EntityType="Microsoft.OData.SampleService.Models.TripPin.Photo">
177191
<Annotation Term="Org.OData.Core.V1.ResourcePath" String="Photos" />
178192
<Annotation Term="Org.OData.Capabilities.V1.SearchRestrictions">

tests/test_model_v2.py

Lines changed: 0 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ def test_edmx(schema):
3535
'CarIDPic',
3636
'Customer',
3737
'Order',
38-
'EnumTest'
3938
}
4039

4140
assert set((entity_set.name for entity_set in schema.entity_sets)) == {
@@ -51,12 +50,6 @@ def test_edmx(schema):
5150
'CarIDPics',
5251
'Customers',
5352
'Orders',
54-
'EnumTests'
55-
}
56-
57-
assert set((enum_type.name for enum_type in schema.enum_types)) == {
58-
'Country',
59-
'Language'
6053
}
6154

6255
master_entity = schema.entity_type('MasterEntity')
@@ -879,8 +872,6 @@ def test_null_type(xml_builder_factory):
879872
<Property Name="Key" Type="Edm.UnknownType" />
880873
</EntityType>
881874
882-
<EnumType Name="MasterEnum" UnderlyingType="Edm.String" />
883-
884875
<ComplexType Name="MasterComplex">
885876
<Property Name="Width" Type="Edm.Double" />
886877
<Property Name="Width" Type="Edm.Double" />
@@ -903,8 +894,6 @@ def test_null_type(xml_builder_factory):
903894
type_info = TypeInfo(namespace=None, name='MasterProperty', is_collection=False)
904895
assert isinstance(schema.get_type(type_info).proprty('Key').typ, NullType)
905896

906-
type_info = TypeInfo(namespace=None, name='MasterEnum', is_collection=False)
907-
assert isinstance(schema.get_type(type_info), NullType)
908897

909898
type_info = TypeInfo(namespace=None, name='MasterComplex', is_collection=False)
910899
assert isinstance(schema.get_type(type_info), NullType)
@@ -1175,77 +1164,6 @@ def test_whitelisted_edm_namespace_2007_05(mocked, xml_builder_factory):
11751164
mocked.assert_called_once()
11761165

11771166

1178-
def test_enum_parsing(schema):
1179-
"""Test correct parsing of enum"""
1180-
1181-
country = schema.enum_type('Country').USA
1182-
assert str(country) == "Country'USA'"
1183-
1184-
country2 = schema.enum_type('Country')['USA']
1185-
assert str(country2) == "Country'USA'"
1186-
1187-
try:
1188-
schema.enum_type('Country').Cyprus
1189-
except PyODataException as ex:
1190-
assert str(ex) == f'EnumType EnumType(Country) has no member Cyprus'
1191-
1192-
c = schema.enum_type('Country')[1]
1193-
assert str(c) == "Country'China'"
1194-
1195-
try:
1196-
schema.enum_type('Country')[15]
1197-
except PyODataException as ex:
1198-
assert str(ex) == f'EnumType EnumType(Country) has no member with value {15}'
1199-
1200-
type_info = TypeInfo(namespace=None, name='Country', is_collection=False)
1201-
1202-
try:
1203-
schema.get_type(type_info)
1204-
except PyODataModelError as ex:
1205-
assert str(ex) == f'Neither primitive types nor types parsed from service metadata contain requested type {type_info[0]}'
1206-
1207-
language = schema.enum_type('Language')
1208-
assert language.is_flags is True
1209-
1210-
try:
1211-
schema.enum_type('ThisEnumDoesNotExist')
1212-
except KeyError as ex:
1213-
assert str(ex) == f'\'EnumType ThisEnumDoesNotExist does not exist in any Schema Namespace\''
1214-
1215-
try:
1216-
schema.enum_type('Country', 'WrongNamespace').USA
1217-
except KeyError as ex:
1218-
assert str(ex) == '\'EnumType Country does not exist in Schema Namespace WrongNamespace\''
1219-
1220-
1221-
def test_unsupported_enum_underlying_type(xml_builder_factory):
1222-
"""Test if parser will parse only allowed underlying types"""
1223-
xml_builder = xml_builder_factory()
1224-
xml_builder.add_schema('Test', '<EnumType Name="UnsupportedEnumType" UnderlyingType="Edm.Bool" />')
1225-
xml = xml_builder.serialize()
1226-
1227-
try:
1228-
MetadataBuilder(xml).build()
1229-
except PyODataParserError as ex:
1230-
assert str(ex).startswith(f'Type Edm.Bool is not valid as underlying type for EnumType - must be one of')
1231-
1232-
1233-
def test_enum_value_out_of_range(xml_builder_factory):
1234-
"""Test if parser will check for values ot of range defined by underlying type"""
1235-
xml_builder = xml_builder_factory()
1236-
xml_builder.add_schema('Test', """
1237-
<EnumType Name="Num" UnderlyingType="Edm.Byte">
1238-
<Member Name="TooBig" Value="-130" />
1239-
</EnumType>
1240-
""")
1241-
xml = xml_builder.serialize()
1242-
1243-
try:
1244-
MetadataBuilder(xml).build()
1245-
except BaseException as ex:
1246-
assert str(ex) == f'Value -130 is out of range for type Edm.Byte'
1247-
1248-
12491167
@patch('logging.Logger.warning')
12501168
def test_missing_property_referenced_in_annotation(mock_warning, xml_builder_factory):
12511169
"""Test that correct behavior when non existing property is referenced in annotation"""

tests/test_model_v4.py

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
import geojson
44
import pytest
55

6+
from pyodata.policies import PolicyIgnore
67
from pyodata.model.builder import MetadataBuilder
7-
from pyodata.exceptions import PyODataModelError
8+
from pyodata.exceptions import PyODataModelError, PyODataException, PyODataParserError
89
from pyodata.model.type_traits import TypTraits
9-
from pyodata.model.elements import Types
10+
from pyodata.model.elements import Types, TypeInfo, NullType
1011

1112
from pyodata.config import Config
1213
from pyodata.v4 import ODataV4
@@ -172,3 +173,93 @@ def test_referential_constraint(schema_v4):
172173
assert repr(nav_property.referential_constraints[0]) == \
173174
'ReferentialConstraint(StructTypeProperty(CategoryID), StructTypeProperty(ID))'
174175

176+
177+
def test_enum_parsing(schema_v4):
178+
"""Test correct parsing of enum"""
179+
180+
country = schema_v4.enum_type('Country').USA
181+
assert str(country) == "Country'USA'"
182+
183+
country2 = schema_v4.enum_type('Country')['USA']
184+
assert str(country2) == "Country'USA'"
185+
186+
try:
187+
schema_v4.enum_type('Country').Cyprus
188+
except PyODataException as ex:
189+
assert str(ex) == f'EnumType EnumType(Country) has no member Cyprus'
190+
191+
c = schema_v4.enum_type('Country')[1]
192+
assert str(c) == "Country'China'"
193+
194+
try:
195+
schema_v4.enum_type('Country')[15]
196+
except PyODataException as ex:
197+
assert str(ex) == f'EnumType EnumType(Country) has no member with value {15}'
198+
199+
type_info = TypeInfo(namespace=None, name='Country', is_collection=False)
200+
201+
try:
202+
schema_v4.get_type(type_info)
203+
except PyODataModelError as ex:
204+
assert str(ex) == f'Neither primitive types nor types parsed from service metadata contain requested type {type_info[0]}'
205+
206+
language = schema_v4.enum_type('Language')
207+
assert language.is_flags is True
208+
209+
try:
210+
schema_v4.enum_type('ThisEnumDoesNotExist')
211+
except KeyError as ex:
212+
assert str(ex) == f'\'EnumType ThisEnumDoesNotExist does not exist in any Schema Namespace\''
213+
214+
try:
215+
schema_v4.enum_type('Country', 'WrongNamespace').USA
216+
except KeyError as ex:
217+
assert str(ex) == '\'EnumType Country does not exist in Schema Namespace WrongNamespace\''
218+
219+
220+
def test_unsupported_enum_underlying_type(xml_builder_factory):
221+
"""Test if parser will parse only allowed underlying types"""
222+
xml_builder = xml_builder_factory()
223+
xml_builder.add_schema('Test', '<EnumType Name="UnsupportedEnumType" UnderlyingType="Edm.Bool" />')
224+
xml = xml_builder.serialize()
225+
226+
try:
227+
MetadataBuilder(xml, Config(ODataV4)).build()
228+
except PyODataParserError as ex:
229+
assert str(ex).startswith(f'Type Edm.Bool is not valid as underlying type for EnumType - must be one of')
230+
231+
232+
def test_enum_value_out_of_range(xml_builder_factory):
233+
"""Test if parser will check for values ot of range defined by underlying type"""
234+
xml_builder = xml_builder_factory()
235+
xml_builder.add_schema('Test', """
236+
<EnumType Name="Num" UnderlyingType="Edm.Byte">
237+
<Member Name="TooBig" Value="-130" />
238+
</EnumType>
239+
""")
240+
xml = xml_builder.serialize()
241+
242+
try:
243+
MetadataBuilder(xml, Config(ODataV4)).build()
244+
except BaseException as ex:
245+
assert str(ex) == f'Value -130 is out of range for type Edm.Byte'
246+
247+
248+
def test_enum_null_type(xml_builder_factory):
249+
""" Test NullType being correctly assigned to invalid types"""
250+
xml_builder = xml_builder_factory()
251+
xml_builder.add_schema('TEST.NAMESPACE', """
252+
<EnumType Name="MasterEnum" UnderlyingType="Edm.String" />
253+
""")
254+
255+
metadata = MetadataBuilder(
256+
xml_builder.serialize(),
257+
config=Config(
258+
ODataV4,
259+
default_error_policy=PolicyIgnore()
260+
))
261+
262+
schema = metadata.build()
263+
264+
type_info = TypeInfo(namespace=None, name='MasterEnum', is_collection=False)
265+
assert isinstance(schema.get_type(type_info), NullType)

tests/test_service_v2.py

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -86,32 +86,6 @@ def test_create_entity_code_400(service):
8686
assert str(e_info.value).startswith('HTTP POST for Entity Set')
8787

8888

89-
@responses.activate
90-
def test_create_entity_containing_enum(service):
91-
"""Basic test on creating entity with enum"""
92-
93-
# pylint: disable=redefined-outer-name
94-
95-
responses.add(
96-
responses.POST,
97-
"{0}/EnumTests".format(service.url),
98-
headers={'Content-type': 'application/json'},
99-
json={'d': {
100-
'CountryOfOrigin': 'USA',
101-
}},
102-
status=201)
103-
104-
result = service.entity_sets.EnumTests.create_entity().set(**{'CountryOfOrigin': 'USA'}).execute()
105-
106-
USA = service.schema.enum_type('Country').USA
107-
assert result.CountryOfOrigin == USA
108-
109-
traits = service.schema.enum_type('Country').traits
110-
literal = traits.to_literal(USA)
111-
112-
assert literal == "EXAMPLE_SRV.Country\'USA\'"
113-
assert traits.from_literal(literal).name == 'USA'
114-
11589
@responses.activate
11690
def test_create_entity_nested(service):
11791
"""Basic test on creating entity"""

0 commit comments

Comments
 (0)