Commit 09486057 authored by bitkeeper's avatar bitkeeper Committed by oroulet

[xmlimporter] Support to make auto load type definitions optional

To the `import_xml` an optional argument `auto_load_definitions` is added. Default is True.

Case:
With commit de8269e4 `import_xml` automatic load(on the fly code generation) the type defintions.

When using your own extension object and enum implementation (with `ua.register_extension_object`  `ua.register_enum`) this is unwanted behaviour.

Previous work flow was:
* import xml
* register own extension object and enum implementations
* for the remain stuff call `load_data_type_definitions()`

To make this possible again an option is required to prevent the auto load definitions when calling the `import_xml` method.
parent 83539202
...@@ -816,11 +816,11 @@ class Client: ...@@ -816,11 +816,11 @@ class Client:
async def delete_nodes(self, nodes: Iterable[Node], recursive=False) -> Tuple[List[Node], List[ua.StatusCode]]: async def delete_nodes(self, nodes: Iterable[Node], recursive=False) -> Tuple[List[Node], List[ua.StatusCode]]:
return await delete_nodes(self.uaclient, nodes, recursive) return await delete_nodes(self.uaclient, nodes, recursive)
async def import_xml(self, path=None, xmlstring=None, strict_mode=True) -> List[ua.NodeId]: async def import_xml(self, path=None, xmlstring=None, strict_mode=True, auto_load_definitions: bool = True) -> List[ua.NodeId]:
""" """
Import nodes defined in xml Import nodes defined in xml
""" """
importer = XmlImporter(self, strict_mode=strict_mode) importer = XmlImporter(self, strict_mode=strict_mode, auto_load_definitions=auto_load_definitions)
return await importer.import_xml(path, xmlstring) return await importer.import_xml(path, xmlstring)
async def export_xml(self, nodes, path, export_values: bool = False) -> None: async def export_xml(self, nodes, path, export_values: bool = False) -> None:
......
...@@ -24,10 +24,11 @@ def _parse_version(version_string: str) -> List[int]: ...@@ -24,10 +24,11 @@ def _parse_version(version_string: str) -> List[int]:
class XmlImporter: class XmlImporter:
def __init__(self, server: Union[asyncua.Server, asyncua.Client], strict_mode: bool = True): def __init__(self, server: Union[asyncua.Server, asyncua.Client], strict_mode: bool = True, auto_load_definitions: bool = True):
''' '''
strict_mode: stop on an error, if False only an error message is logged, strict_mode: stop on an error, if False only an error message is logged,
but the import continues but the import continues
auto_load_definitions: auto generate code stubs on the fly for enum and structs
''' '''
self.parser = None self.parser = None
self.session = server self.session = server
...@@ -36,6 +37,7 @@ class XmlImporter: ...@@ -36,6 +37,7 @@ class XmlImporter:
self._unmigrated_aliases: Dict[str, str] = {} # Dict[name, nodeId string] self._unmigrated_aliases: Dict[str, str] = {} # Dict[name, nodeId string]
self.refs = None self.refs = None
self.strict_mode = strict_mode self.strict_mode = strict_mode
self.auto_load_definitions = auto_load_definitions
async def _map_namespaces(self): async def _map_namespaces(self):
""" """
...@@ -413,9 +415,12 @@ class XmlImporter: ...@@ -413,9 +415,12 @@ class XmlImporter:
async def _make_ext_obj(self, obj): async def _make_ext_obj(self, obj):
try: try:
extclass = self._get_ext_class(obj.objname) extclass = self._get_ext_class(obj.objname)
except Exception: except Exception as exp:
await self.session.load_data_type_definitions() # load new data type definitions since a customn class should be created if self.auto_load_definitions:
extclass = self._get_ext_class(obj.objname) await self.session.load_data_type_definitions() # load new data type definitions since a customn class should be created
extclass = self._get_ext_class(obj.objname)
else:
raise exp
args = {} args = {}
for name, val in obj.body: for name, val in obj.body:
if not isinstance(val, list): if not isinstance(val, list):
...@@ -627,13 +632,14 @@ class XmlImporter: ...@@ -627,13 +632,14 @@ class XmlImporter:
res = await self._get_server().add_nodes([node]) res = await self._get_server().add_nodes([node])
res[0].StatusCode.check() res[0].StatusCode.check()
await self._add_refs(obj) await self._add_refs(obj)
if is_struct: if self.auto_load_definitions:
await load_custom_struct_xml_import(node.RequestedNewNodeId, attrs) if is_struct:
if is_enum: await load_custom_struct_xml_import(node.RequestedNewNodeId, attrs)
await load_enum_xml_import(node.RequestedNewNodeId, attrs, is_option_set) if is_enum:
if is_alias: await load_enum_xml_import(node.RequestedNewNodeId, attrs, is_option_set)
if node.ParentNodeId != ua.NodeId(ua.ObjectIds.Structure): if is_alias:
await load_basetype_alias_xml_import(self.session, node.BrowseName.Name, node.RequestedNewNodeId, node.ParentNodeId) if node.ParentNodeId != ua.NodeId(ua.ObjectIds.Structure):
await load_basetype_alias_xml_import(self.session, node.BrowseName.Name, node.RequestedNewNodeId, node.ParentNodeId)
return res[0].AddedNodeId return res[0].AddedNodeId
async def _add_refs(self, obj): async def _add_refs(self, obj):
......
...@@ -718,11 +718,11 @@ class Server: ...@@ -718,11 +718,11 @@ class Server:
await custom_t.add_method(idx, method[0], method[1], method[2], method[3]) await custom_t.add_method(idx, method[0], method[1], method[2], method[3])
return custom_t return custom_t
async def import_xml(self, path=None, xmlstring=None, strict_mode=True): async def import_xml(self, path=None, xmlstring=None, strict_mode=True, auto_load_definitions: bool = True):
""" """
Import nodes defined in xml Import nodes defined in xml
""" """
importer = XmlImporter(self, strict_mode) importer = XmlImporter(self, strict_mode, auto_load_definitions)
return await importer.import_xml(path, xmlstring) return await importer.import_xml(path, xmlstring)
async def export_xml(self, nodes, path, export_values: bool = False): async def export_xml(self, nodes, path, export_values: bool = False):
......
...@@ -1327,8 +1327,12 @@ async def test_guid_node_id(): ...@@ -1327,8 +1327,12 @@ async def test_guid_node_id():
async def test_import_xml_data_type_definition(opc): async def test_import_xml_data_type_definition(opc):
if hasattr(ua, "MySubstruct"):
delattr(ua, "MySubstruct")
if hasattr(ua, "MyStruct"):
delattr(ua, "MyStruct")
nodes = await opc.opc.import_xml("tests/substructs.xml") nodes = await opc.opc.import_xml("tests/substructs.xml")
await opc.opc.load_data_type_definitions()
assert hasattr(ua, "MySubstruct") assert hasattr(ua, "MySubstruct")
assert hasattr(ua, "MyStruct") assert hasattr(ua, "MyStruct")
...@@ -1362,6 +1366,19 @@ async def test_import_xml_data_type_definition(opc): ...@@ -1362,6 +1366,19 @@ async def test_import_xml_data_type_definition(opc):
[n.append(opc.opc.get_node(node)) for node in nodes] [n.append(opc.opc.get_node(node)) for node in nodes]
await opc.opc.delete_nodes(n) await opc.opc.delete_nodes(n)
async def test_import_xml_data_no_auto_load_type_definition(opc):
# if al present in ua remove it (left overs of other tests)
if hasattr(ua, "MySubstruct"):
delattr(ua, "MySubstruct")
if hasattr(ua, "MyStruct"):
delattr(ua, "MyStruct")
if hasattr(ua, "MyEnum"):
delattr(ua, "MyEnum")
await opc.opc.import_xml("tests/substructs.xml", auto_load_definitions = False)
assert hasattr(ua, "MySubstruct") is False
assert hasattr(ua, "MyStruct") is False
assert hasattr(ua, "MyEnum") is False
async def test_struct_data_type(opc): async def test_struct_data_type(opc):
assert isinstance(ua.AddNodesItem.data_type, ua.NodeId) assert isinstance(ua.AddNodesItem.data_type, ua.NodeId)
...@@ -1372,8 +1389,10 @@ async def test_struct_data_type(opc): ...@@ -1372,8 +1389,10 @@ async def test_struct_data_type(opc):
async def test_import_xml_enum_data_type_definition(opc): async def test_import_xml_enum_data_type_definition(opc):
if hasattr(ua, "MyEnum"):
delattr(ua, "MyEnum")
nodes = await opc.opc.import_xml("tests/testenum104.xml") nodes = await opc.opc.import_xml("tests/testenum104.xml")
await opc.opc.load_data_type_definitions()
assert hasattr(ua, "MyEnum") assert hasattr(ua, "MyEnum")
e = ua.MyEnum.val2 e = ua.MyEnum.val2
var = await opc.opc.nodes.objects.add_variable( var = await opc.opc.nodes.objects.add_variable(
......
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