From eabd784f05f2bbb8c177947c503d18d874982638 Mon Sep 17 00:00:00 2001 From: Andreas Heine <56362817+AndreasHeine@users.noreply.github.com> Date: Thu, 24 Mar 2022 17:43:52 +0100 Subject: [PATCH] Prevent abstract Types from beeing instantiated (#842) * init * add: is_abstract check and typehints * change import for Node * change import for Node * remove nodeclass-typehints due to import error * add test for instantiate abstract type * edit: change ValueError to UaError * edit: test --- asyncua/common/instantiate_util.py | 13 ++++++++++++- tests/test_common.py | 6 ++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/asyncua/common/instantiate_util.py b/asyncua/common/instantiate_util.py index b9dd1ecc6..5e912a3d3 100644 --- a/asyncua/common/instantiate_util.py +++ b/asyncua/common/instantiate_util.py @@ -4,6 +4,8 @@ import logging +from typing import Union + from asyncua import ua from .ua_utils import get_node_supertypes, is_child_present from .copy_node_util import _rdesc_from_node, _read_and_copy_attrs @@ -12,13 +14,22 @@ logger = logging.getLogger(__name__) -async def instantiate(parent, node_type, nodeid=None, bname=None, dname=None, idx=0, instantiate_optional=True): +async def is_abstract(node_type) -> bool: + result = await node_type.read_attribute(ua.AttributeIds.IsAbstract) + return result.Value.Value + + +async def instantiate(parent, node_type, nodeid: ua.NodeId=None, bname: Union[str, ua.QualifiedName]=None, dname: ua.LocalizedText=None, idx: int=0, instantiate_optional: bool=True): """ instantiate a node type under a parent node. nodeid and browse name of new node can be specified, or just namespace index If they exists children of the node type, such as components, variables and properties are also instantiated """ + abstract = await is_abstract(node_type) + if abstract: + raise ua.UaError(f"InstantiationError NodeId: {node_type.nodeid} is abstract and cant be instantiated!") + rdesc = await _rdesc_from_node(parent, node_type) rdesc.TypeDefinition = node_type.nodeid diff --git a/tests/test_common.py b/tests/test_common.py index 74367c061..ac4bd2cee 100644 --- a/tests/test_common.py +++ b/tests/test_common.py @@ -1010,6 +1010,12 @@ async def test_instantiate_string_nodeid(opc): await opc.opc.delete_nodes([dev_t]) +async def test_instantiate_abstract(opc): + finit_statemachine_type = opc.opc.get_node("ns=0;i=2771") # IsAbstract=True + with pytest.raises(ua.UaError): + node = await instantiate(opc.opc.nodes.objects, finit_statemachine_type, bname="2:TestFiniteStateMachine") + + async def test_variable_with_datatype(opc): v1 = await opc.opc.nodes.objects.add_variable( 3, 'VariableEnumType1', ua.ApplicationType.ClientAndServer, datatype=ua.NodeId(ua.ObjectIds.ApplicationType)