Commit 7b2b130f authored by Christoph Ziebuhr's avatar Christoph Ziebuhr Committed by oroulet

Fix interpretation of IncludeSubtypes

parent 2be7ce80
...@@ -219,7 +219,7 @@ async def select_event_attributes_from_type_node(node: "Node", attributeSelector ...@@ -219,7 +219,7 @@ async def select_event_attributes_from_type_node(node: "Node", attributeSelector
if curr_node.nodeid.Identifier == ua.ObjectIds.BaseEventType: if curr_node.nodeid.Identifier == ua.ObjectIds.BaseEventType:
break break
parents = await curr_node.get_referenced_nodes( parents = await curr_node.get_referenced_nodes(
refs=ua.ObjectIds.HasSubtype, direction=ua.BrowseDirection.Inverse, includesubtypes=True refs=ua.ObjectIds.HasSubtype, direction=ua.BrowseDirection.Inverse
) )
if len(parents) != 1: # Something went wrong if len(parents) != 1: # Something went wrong
return None return None
...@@ -278,9 +278,7 @@ async def get_event_obj_from_type_node(node): ...@@ -278,9 +278,7 @@ async def get_event_obj_from_type_node(node):
# Add the sub-properties of the VariableType # Add the sub-properties of the VariableType
for prop in await var.get_properties(): for prop in await var.get_properties():
await self._add_new_property(prop, var) await self._add_new_property(prop, var)
parents = await curr_node.get_referenced_nodes(refs=ua.ObjectIds.HasSubtype, parents = await curr_node.get_referenced_nodes(refs=ua.ObjectIds.HasSubtype, direction=ua.BrowseDirection.Inverse)
direction=ua.BrowseDirection.Inverse,
includesubtypes=True)
if len(parents) != 1: # Something went wrong if len(parents) != 1: # Something went wrong
raise UaError("Parent of event type could not be found") raise UaError("Parent of event type could not be found")
curr_node = parents[0] curr_node = parents[0]
...@@ -295,9 +293,7 @@ async def get_event_obj_from_type_node(node): ...@@ -295,9 +293,7 @@ async def get_event_obj_from_type_node(node):
async def _find_parent_eventtype(node): async def _find_parent_eventtype(node):
""" """
""" """
parents = await node.get_referenced_nodes(refs=ua.ObjectIds.HasSubtype, direction=ua.BrowseDirection.Inverse, parents = await node.get_referenced_nodes(refs=ua.ObjectIds.HasSubtype, direction=ua.BrowseDirection.Inverse)
includesubtypes=True)
if len(parents) != 1: # Something went wrong if len(parents) != 1: # Something went wrong
raise UaError("Parent of event type could not be found") raise UaError("Parent of event type could not be found")
if parents[0].nodeid.NamespaceIndex == 0: if parents[0].nodeid.NamespaceIndex == 0:
......
...@@ -97,7 +97,7 @@ async def _instantiate_node(server, ...@@ -97,7 +97,7 @@ async def _instantiate_node(server,
parents = await get_node_supertypes(node_type, includeitself=True) parents = await get_node_supertypes(node_type, includeitself=True)
node = make_node(server, res.AddedNodeId) node = make_node(server, res.AddedNodeId)
for parent in parents: for parent in parents:
descs = await parent.get_children_descriptions(includesubtypes=False) descs = await parent.get_children_descriptions()
for c_rdesc in descs: for c_rdesc in descs:
# skip items that already exists, prefer the 'lowest' one in object hierarchy # skip items that already exists, prefer the 'lowest' one in object hierarchy
if not await is_child_present(node, c_rdesc.BrowseName): if not await is_child_present(node, c_rdesc.BrowseName):
......
...@@ -204,7 +204,7 @@ async def get_node_supertype(node): ...@@ -204,7 +204,7 @@ async def get_node_supertype(node):
return node supertype or None return node supertype or None
""" """
supertypes = await node.get_referenced_nodes( supertypes = await node.get_referenced_nodes(
refs=ua.ObjectIds.HasSubtype, direction=ua.BrowseDirection.Inverse, includesubtypes=True refs=ua.ObjectIds.HasSubtype, direction=ua.BrowseDirection.Inverse
) )
if supertypes: if supertypes:
return supertypes[0] return supertypes[0]
......
...@@ -12,7 +12,7 @@ from functools import partial ...@@ -12,7 +12,7 @@ from functools import partial
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
if TYPE_CHECKING: if TYPE_CHECKING:
from typing import Callable, Dict, List, Union, Tuple from typing import Callable, Dict, List, Union, Tuple, Generator
from asyncua.ua.uaprotocol_auto import ( from asyncua.ua.uaprotocol_auto import (
ObjectAttributes, DataTypeAttributes, ReferenceTypeAttributes, ObjectAttributes, DataTypeAttributes, ReferenceTypeAttributes,
VariableTypeAttributes, VariableAttributes, ObjectTypeAttributes VariableTypeAttributes, VariableAttributes, ObjectTypeAttributes
...@@ -152,24 +152,19 @@ class ViewService(object): ...@@ -152,24 +152,19 @@ class ViewService(object):
# If ReferenceTypeId is not specified in the BrowseDescription, # If ReferenceTypeId is not specified in the BrowseDescription,
# all References are returned and includeSubtypes is ignored. # all References are returned and includeSubtypes is ignored.
return True return True
if not subtypes and ref2.Identifier == ua.ObjectIds.HasSubtype: if ref1 == ref2:
return False return True
if ref1.Identifier == ref2.Identifier: if subtypes and ref2 in self._get_sub_ref(ref1):
return True return True
oktypes = self._get_sub_ref(ref1) return False
if not subtypes and ua.NodeId(ua.ObjectIds.HasSubtype) in oktypes:
oktypes.remove(ua.NodeId(ua.ObjectIds.HasSubtype)) def _get_sub_ref(self, ref: ua.NodeId) -> Generator[ua.NodeId, None, None]:
return ref2 in oktypes nodedata = self._aspace.get(ref)
def _get_sub_ref(self, ref: ua.NodeId) -> List[ua.NodeId]:
res: List[ua.NodeId] = []
nodedata = self._aspace[ref]
if nodedata is not None: if nodedata is not None:
for ref_desc in nodedata.references: for ref_desc in nodedata.references:
if ref_desc.ReferenceTypeId.Identifier == ua.ObjectIds.HasSubtype and ref_desc.IsForward: if ref_desc.ReferenceTypeId == ua.NodeId(ua.ObjectIds.HasSubtype) and ref_desc.IsForward:
res.append(ref_desc.NodeId) yield ref_desc.NodeId
res += self._get_sub_ref(ref_desc.NodeId) yield from self._get_sub_ref(ref_desc.NodeId)
return res
def _suitable_direction(self, direction: ua.BrowseDirection, isforward: bool) -> bool: def _suitable_direction(self, direction: ua.BrowseDirection, isforward: bool) -> bool:
if direction == ua.BrowseDirection.Both: if direction == ua.BrowseDirection.Both:
...@@ -231,11 +226,8 @@ class ViewService(object): ...@@ -231,11 +226,8 @@ class ViewService(object):
continue continue
if ref.IsForward == el.IsInverse: if ref.IsForward == el.IsInverse:
continue continue
if not el.IncludeSubtypes and ref.ReferenceTypeId != el.ReferenceTypeId: if not self._suitable_reftype(el.ReferenceTypeId, ref.ReferenceTypeId, el.IncludeSubtypes):
continue continue
elif el.IncludeSubtypes and ref.ReferenceTypeId != el.ReferenceTypeId:
if ref.ReferenceTypeId not in self._get_sub_ref(el.ReferenceTypeId):
continue
nodeids.append(ref.NodeId) nodeids.append(ref.NodeId)
return nodeids return nodeids
......
...@@ -357,9 +357,15 @@ async def test_browse_references(opc): ...@@ -357,9 +357,15 @@ async def test_browse_references(opc):
assert objects in parents assert objects in parents
parents = await folder.get_referenced_nodes( parents = await folder.get_referenced_nodes(
refs=ua.ObjectIds.HierarchicalReferences, direction=ua.BrowseDirection.Inverse, includesubtypes=False refs=ua.ObjectIds.HierarchicalReferences, direction=ua.BrowseDirection.Inverse, includesubtypes=True
) )
assert objects in parents assert objects in parents
parents = await folder.get_referenced_nodes(
refs=ua.ObjectIds.HierarchicalReferences, direction=ua.BrowseDirection.Inverse, includesubtypes=False
)
assert objects not in parents
assert await folder.get_parent() == objects assert await folder.get_parent() == objects
...@@ -928,7 +934,7 @@ async def test_copy_node(opc): ...@@ -928,7 +934,7 @@ async def test_copy_node(opc):
ctrl_t = await dev_t.add_object(0, "controller") ctrl_t = await dev_t.add_object(0, "controller")
prop_t = await ctrl_t.add_property(0, "state", "Running") prop_t = await ctrl_t.add_property(0, "state", "Running")
# Create device sutype # Create device sutype
devd_t = await dev_t.add_object_type(0, "MyDeviceDervived") devd_t = await dev_t.add_object_type(0, "MyDeviceDerived")
_ = await devd_t.add_variable(0, "childparam", 1.0) _ = await devd_t.add_variable(0, "childparam", 1.0)
_ = await devd_t.add_property(0, "sensorx_id", "0340") _ = await devd_t.add_property(0, "sensorx_id", "0340")
nodes = await copy_node(opc.opc.nodes.objects, dev_t) nodes = await copy_node(opc.opc.nodes.objects, dev_t)
...@@ -959,7 +965,7 @@ async def test_instantiate_1(opc): ...@@ -959,7 +965,7 @@ async def test_instantiate_1(opc):
await prop_t.set_modelling_rule(True) await prop_t.set_modelling_rule(True)
# Create device sutype # Create device sutype
devd_t = await dev_t.add_object_type(0, "MyDeviceDervived") devd_t = await dev_t.add_object_type(0, "MyDeviceDerived")
v_t = await devd_t.add_variable(0, "childparam", 1.0) v_t = await devd_t.add_variable(0, "childparam", 1.0)
await v_t.set_modelling_rule(True) await v_t.set_modelling_rule(True)
p_t = await devd_t.add_property(0, "sensorx_id", "0340") p_t = await devd_t.add_property(0, "sensorx_id", "0340")
...@@ -973,10 +979,11 @@ async def test_instantiate_1(opc): ...@@ -973,10 +979,11 @@ async def test_instantiate_1(opc):
assert dev_t.nodeid == await mydevice.read_type_definition() assert dev_t.nodeid == await mydevice.read_type_definition()
_ = await mydevice.get_child(["0:controller"]) _ = await mydevice.get_child(["0:controller"])
prop = await mydevice.get_child(["0:controller", "0:state"]) prop = await mydevice.get_child(["0:controller", "0:state"])
with pytest.raises(ua.UaError): _ = await mydevice.get_child(["0:vendor"])
await mydevice.get_child(["0:controller", "0:vendor"]) with pytest.raises(ua.uaerrors.BadNoMatch):
with pytest.raises(ua.UaError): await mydevice.get_child(["0:model"])
await mydevice.get_child(["0:controller", "0:model"]) with pytest.raises(ua.uaerrors.BadNoMatch):
await mydevice.get_child(["0:MyDeviceDerived"])
assert ua.ObjectIds.PropertyType == (await prop.read_type_definition()).Identifier assert ua.ObjectIds.PropertyType == (await prop.read_type_definition()).Identifier
assert "Running" == await prop.read_value() assert "Running" == await prop.read_value()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment