Skip to content

Commit 36cb45f

Browse files
committed
service: do not search for Ass. Sets in own namespace
The implementation of navigation properties expected that the corresponding Association and the corresponding AssociationSet must be both in the same namespace but that is not true. See: https://services.odata.org/V2/Northwind/Northwind.svc/$metadata Reported by FedorSelitsky <[email protected]> in the PR #14.
1 parent ab4236b commit 36cb45f

File tree

4 files changed

+79
-5
lines changed

4 files changed

+79
-5
lines changed

pyodata/v2/service.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -994,13 +994,12 @@ def nav(self, nav_property, key):
994994
# Get entity set of navigation property
995995
association_info = navigation_property.association_info
996996
association_set = self._service.schema.association_set_by_association(
997-
association_info.name,
998-
association_info.namespace)
997+
association_info.name)
999998

1000999
navigation_entity_set = None
10011000
for entity_set in association_set.end_roles:
10021001
if association_set.end_roles[entity_set] == navigation_property.to_role.role:
1003-
navigation_entity_set = self._service.schema.entity_set(entity_set, association_info.namespace)
1002+
navigation_entity_set = self._service.schema.entity_set(entity_set)
10041003

10051004
if not navigation_entity_set:
10061005
raise PyODataException('No association set for role {}'.format(navigation_property.to_role))

tests/conftest.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,23 @@ def metadata():
7272
<Property Name="CarName" Type="Edm.String" Nullable="false" sap:unicode="false" sap:label="Data" sap:creatable="false" sap:updatable="false" sap:sortable="true" sap:filterable="true"/>
7373
<Property Name="Content" Type="Edm.Binary" Nullable="false" sap:label="Picture" sap:creatable="false" sap:updatable="false" sap:sortable="false" sap:filterable="false"/>
7474
</EntityType>
75+
76+
<EntityType Name="Customer">
77+
<Key>
78+
<PropertyRef Name="Name"/>
79+
</Key>
80+
<Property Name="Name" Type="Edm.String" Nullable="false" />
81+
<NavigationProperty Name="Orders" Relationship="EXAMPLE_SRV.CustomerOrders" FromRole="CustomerRole" ToRole="OrdersRole"/>
82+
</EntityType>
83+
84+
<EntityType Name="Order">
85+
<Key>
86+
<PropertyRef Name="Number"/>
87+
</Key>
88+
<Property Name="Number" Type="Edm.String" Nullable="false" />
89+
<Property Name="Owner" Type="Edm.String" Nullable="false" />
90+
</EntityType>
91+
7592
<ComplexType Name="ComplexNumber">
7693
<Property Name="Real" Type="Edm.Double" Nullable="false"/>
7794
<Property Name="Imaginary" Type="Edm.Double" Nullable="false"/>
@@ -111,6 +128,20 @@ def metadata():
111128
</Dependent>
112129
</ReferentialConstraint>
113130
</Association>
131+
132+
<Association Name="CustomerOrders">
133+
<End Role="CustomerRole" Type="EXAMPLE_SRV.Customer" Multiplicity="1"/>
134+
<End Role="OrdersRole" Type="EXAMPLE_SRV.Order" Multiplicity="*"/>
135+
<ReferentialConstraint>
136+
<Principal Role="CustomerRole">
137+
<PropertyRef Name="Name"/>
138+
</Principal>
139+
<Dependent Role="OrdersRole">
140+
<PropertyRef Name="Owner"/>
141+
</Dependent>
142+
</ReferentialConstraint>
143+
</Association>
144+
114145
<EntityContainer Name="EXAMPLE_SRV" m:IsDefaultEntityContainer="true" sap:supported-formats="atom json xlsx">
115146
<EntitySet Name="MasterEntities" EntityType="EXAMPLE_SRV.MasterEntity" sap:label="Master entities" sap:creatable="false" sap:updatable="false" sap:deletable="false" sap:searchable="true" sap:content-version="1"/>
116147
<EntitySet Name="DataValueHelp" EntityType="EXAMPLE_SRV.DataEntity" sap:creatable="false" sap:updatable="false" sap:deletable="false" sap:searchable="true" sap:content-version="1"/>
@@ -237,6 +268,10 @@ def metadata():
237268
238269
<EntitySet Name="Addresses" EntityType="Address"/>
239270
271+
<EntitySet Name="Customers" EntityType="EXAMPLE_SRV.Customer"/>
272+
273+
<EntitySet Name="Orders" EntityType="EXAMPLE_SRV.Order"/>
274+
240275
<FunctionImport Name="get_max" ReturnType="TemperatureMeasurement" EntitySet="TemperatureMeasurements" m:HttpMethod="GET" />
241276
242277
<FunctionImport Name="get_best_measurements" ReturnType="Collection(EXAMPLE_SRV.TemperatureMeasurement)" EntitySet="EXAMPLE_SRV.TemperatureMeasurements" m:HttpMethod="GET" />
@@ -256,6 +291,11 @@ def metadata():
256291
<End Role="AddressRole" EntitySet="Addresses"/>
257292
</AssociationSet>
258293
294+
<AssociationSet Name="CustomerOrder_AssocSet" Association="EXAMPLE_SRV.CustomerOrders">
295+
<End Role="CustomerRole" EntitySet="Customers"/>
296+
<End Role="OrdersRole" EntitySet="Orders"/>
297+
</AssociationSet>
298+
259299
</EntityContainer>
260300
261301
</Schema>

tests/test_model_v2.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ def test_edmx(schema):
2424
'City',
2525
'TemperatureMeasurement',
2626
'Car',
27-
'CarIDPic'
27+
'CarIDPic',
28+
'Customer',
29+
'Order'
2830
}
2931

3032
assert set((entity_set.name for entity_set in schema.entity_sets)) == {
@@ -37,7 +39,9 @@ def test_edmx(schema):
3739
'CitiesWithFilter',
3840
'TemperatureMeasurements',
3941
'Cars',
40-
'CarIDPics'
42+
'CarIDPics',
43+
'Customers',
44+
'Orders'
4145
}
4246

4347
master_entity = schema.entity_type('MasterEntity')
@@ -161,6 +165,7 @@ def test_edmx_associations(schema):
161165

162166
assert set((association.name for association in schema.associations)) == {'toCarIDPic',
163167
'toDataEntity',
168+
'CustomerOrders',
164169
'AssociationEmployeeAddress'}
165170

166171
association = schema.association('toDataEntity')
@@ -184,6 +189,7 @@ def test_edmx_associations(schema):
184189

185190
assert set((association_set.name for association_set in schema.association_sets)) == {'toDataEntitySet',
186191
'AssociationEmployeeAddress_AssocSet',
192+
'CustomerOrder_AssocSet',
187193
'toCarIDPicSet'}
188194
association_set = schema.association_set('toDataEntitySet')
189195
assert str(association_set) == 'AssociationSet(toDataEntitySet)'

tests/test_service_v2.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,35 @@ def test_navigation_1on1_get_value_without_proxy(service):
533533
assert stream.content == b'DEADBEAF'
534534

535535

536+
@responses.activate
537+
def test_navigation_when_nes_in_another_ns(service):
538+
"""Check whether it is possible to navigate when AssociationSet is defined
539+
in a different namespace.
540+
"""
541+
542+
# pylint: disable=redefined-outer-name
543+
544+
responses.add(
545+
responses.GET,
546+
"{0}/Customers('Mammon')/Orders".format(service.url),
547+
json={'d': {'results' : [{
548+
'Number': '456',
549+
'Owner': 'Mammon',
550+
}]}},
551+
status=200)
552+
553+
request = service.entity_sets.Customers.get_entity('Mammon').nav('Orders').get_entities()
554+
555+
assert isinstance(request, pyodata.v2.service.GetEntitySetRequest)
556+
557+
orders = request.execute()
558+
559+
assert len(orders) == 1
560+
561+
assert orders[0].Number == '456'
562+
assert orders[0].Owner == 'Mammon'
563+
564+
536565
@responses.activate
537566
def test_entity_get_value_1on1_with_proxy(service):
538567
"""Check getting $value"""

0 commit comments

Comments
 (0)