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:
async def delete_nodes(self, nodes: Iterable[Node], recursive=False) -> Tuple[List[Node], List[ua.StatusCode]]:
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
"""
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)
async def export_xml(self, nodes, path, export_values: bool = False) -> None:
......
......@@ -24,10 +24,11 @@ def _parse_version(version_string: str) -> List[int]:
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,
but the import continues
auto_load_definitions: auto generate code stubs on the fly for enum and structs
'''
self.parser = None
self.session = server
......@@ -36,6 +37,7 @@ class XmlImporter:
self._unmigrated_aliases: Dict[str, str] = {} # Dict[name, nodeId string]
self.refs = None
self.strict_mode = strict_mode
self.auto_load_definitions = auto_load_definitions
async def _map_namespaces(self):
"""
......@@ -413,9 +415,12 @@ class XmlImporter:
async def _make_ext_obj(self, obj):
try:
extclass = self._get_ext_class(obj.objname)
except Exception:
except Exception as exp:
if self.auto_load_definitions:
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 = {}
for name, val in obj.body:
if not isinstance(val, list):
......@@ -627,6 +632,7 @@ class XmlImporter:
res = await self._get_server().add_nodes([node])
res[0].StatusCode.check()
await self._add_refs(obj)
if self.auto_load_definitions:
if is_struct:
await load_custom_struct_xml_import(node.RequestedNewNodeId, attrs)
if is_enum:
......
......@@ -718,11 +718,11 @@ class Server:
await custom_t.add_method(idx, method[0], method[1], method[2], method[3])
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
"""
importer = XmlImporter(self, strict_mode)
importer = XmlImporter(self, strict_mode, auto_load_definitions)
return await importer.import_xml(path, xmlstring)
async def export_xml(self, nodes, path, export_values: bool = False):
......
......@@ -1327,8 +1327,12 @@ async def test_guid_node_id():
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")
await opc.opc.load_data_type_definitions()
assert hasattr(ua, "MySubstruct")
assert hasattr(ua, "MyStruct")
......@@ -1362,6 +1366,19 @@ async def test_import_xml_data_type_definition(opc):
[n.append(opc.opc.get_node(node)) for node in nodes]
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):
assert isinstance(ua.AddNodesItem.data_type, ua.NodeId)
......@@ -1372,8 +1389,10 @@ async def test_struct_data_type(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")
await opc.opc.load_data_type_definitions()
assert hasattr(ua, "MyEnum")
e = ua.MyEnum.val2
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