Commit 741ad33b authored by jobasto's avatar jobasto Committed by Christian Bergmiller

Parsing of custom structures

Previously custom structures that contain enums wouldn't be parsed correctly when calling load_type_definitions(). This is now fixed by also creating enum classes that represent the enums that are exposed in the server's address space and changing get_default_value() so that it is able to create default values for enums.
parent 226f90da
......@@ -18,8 +18,9 @@ from lxml import objectify
from opcua.ua.ua_binary import Primitives
from opcua import ua
from enum import IntEnum, EnumMeta
def get_default_value(uatype):
def get_default_value(uatype, enums):
if uatype == "String":
return "None"
elif uatype == "Guid":
......@@ -32,10 +33,44 @@ def get_default_value(uatype):
return "datetime.utcnow()"
elif uatype in ("Int16", "Int32", "Int64", "UInt16", "UInt32", "UInt64", "Double", "Float", "Byte", "SByte"):
return 0
elif uatype in enums:
return "ua." + uatype + "(" + enums[uatype] + ")"
elif issubclass(eval("ua."+uatype), IntEnum):
return "ua." + uatype + "(" + list(eval("ua."+uatype))[0] + ")"
else:
return "ua." + uatype + "()"
class EnumType(object):
def __init__(self, name ):
self.name = name
self.fields= []
self.typeid = None
def get_code(self):
code = """
class {0}(IntEnum):
'''
{0} EnumInt autogenerated from xml
'''
""".format(self.name)
for EnumeratedValue in self.fields:
name = EnumeratedValue.Name
value = EnumeratedValue.Value
code += " {} = {}\n".format(name, value)
return code
class EnumeratedValue(object):
def __init__(self, name, value):
self.Name=name
self.Value=value
class Struct(object):
def __init__(self, name):
self.name = name
......@@ -65,7 +100,7 @@ class {self.name}(object):
def __init__(self):
""".format(self.name)
if not self.fields:
code += " pass"
code += " pass"
for field in self.fields:
code += f" self.{field.name} = {field.value}\n"
return code
......@@ -93,6 +128,17 @@ class StructGenerator(object):
self._make_model(root)
def _make_model(self, root):
enums = {}
for child in root.iter("{*}EnumeratedType"):
intenum = EnumType(child.get("Name"))
for xmlfield in child.iter("{*}EnumeratedValue"):
name = xmlfield.get("Name")
value = xmlfield.get("Value")
enumvalue = EnumeratedValue(name, value)
intenum.fields.append(enumvalue)
enums[child.get("Name")] = value
self.model.append(intenum)
for child in root.iter("{*}StructuredType"):
struct = Struct(child.get("Name"))
array = False
......@@ -106,7 +152,7 @@ class StructGenerator(object):
if ":" in field.uatype:
field.uatype = field.uatype.split(":")[1]
field.uatype = _clean_name(field.uatype)
field.value = get_default_value(field.uatype)
field.value = get_default_value(field.uatype, enums)
if array:
field.array = True
field.value = []
......@@ -145,9 +191,11 @@ class StructGenerator(object):
env['datetime'] = datetime
if "uuid" not in env:
env['uuid'] = uuid
if "enum" not in env:
env['IntEnum'] = IntEnum
# generate classes one by one and add them to dict
for struct in self.model:
code = struct.get_code()
for element in self.model:
code = element.get_code()
exec(code, env)
return env
......@@ -234,6 +282,12 @@ def load_type_definitions(server, nodes=None):
ua.register_extension_object(name, nodeid, structs_dict[name])
# save the typeid if user want to create static file for type definitnion
generator.set_typeid(name, nodeid.to_string())
for key in structs_dict.keys():
if type(structs_dict[key]) is EnumMeta and key is not "IntEnum":
import opcua.ua
setattr(opcua.ua, key, structs_dict[key])
return generators, structs_dict
......
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