Commit 0a8e74bd authored by ORD's avatar ORD Committed by GitHub

default_values (#340)

* do not create Variant with value None when they are supported by protocol

* add get_default_value to uatypes. This will be usefull at several places like opcuamodeler

* set correct default value in high level type creation method
parent 7cfd72ab
......@@ -357,10 +357,11 @@ def _create_method(parent, nodeid, qname, callback, inputs, outputs):
def _vtype_to_argument(vtype):
if isinstance(vtype, ua.Argument):
return vtype
arg = ua.Argument()
v = ua.Variant(None, vtype)
arg.DataType = _guess_datatype(v)
if isinstance(vtype, ua.VariantType):
arg.DataType = ua.NodeId(vtype.value)
else:
arg.DataType = ua.NodeId(vtype)
return arg
......
......@@ -381,16 +381,16 @@ class Server(object):
base_t = Node(self.iserver.isession, ua.NodeId(basetype))
custom_t = base_t.add_object_type(idx, name)
for property in properties:
for prop in properties:
datatype = None
if len(property) > 2:
datatype = property[2]
custom_t.add_property(idx, property[0], None, varianttype=property[1], datatype=datatype)
if len(prop) > 2:
datatype = prop[2]
custom_t.add_property(idx, prop[0], ua.get_default_value(prop[1]), varianttype=prop[1], datatype=datatype)
for variable in variables:
datatype = None
if len(variable) > 2:
datatype = variable[2]
custom_t.add_variable(idx, variable[0], None, varianttype=variable[1], datatype=datatype)
custom_t.add_variable(idx, variable[0], ua.get_default_value(variable[1]), varianttype=variable[1], datatype=datatype)
for method in methods:
custom_t.add_method(idx, method[0], method[1], method[2], method[3])
......
......@@ -9,8 +9,6 @@ import os
import uuid
import re
import itertools
if sys.version_info.major > 2:
unicode = str
from opcua.ua import ua_binary as uabin
from opcua.ua import status_codes
......@@ -20,6 +18,8 @@ from opcua.ua.uaerrors import UaStatusCodeError
from opcua.ua.uaerrors import UaStringParsingError
if sys.version_info.major > 2:
unicode = str
def get_win_epoch():
return uabin.win_epoch_to_datetime(0)
......@@ -27,8 +27,9 @@ def get_win_epoch():
class _FrozenClass(object):
"""
make it impossible to add members to a class.
This is a hack since I found out that most bugs are due to misspelling a variable in protocol
Make it impossible to add members to a class.
Not pythonic at all but we found out it prevents many many
bugs in use of protocol structures
"""
_freeze = False
......@@ -38,6 +39,7 @@ class _FrozenClass(object):
key, self.__class__.__name__, self.__dict__.keys()))
object.__setattr__(self, key, value)
if "PYOPCUA_NO_TYPO_CHECK" in os.environ:
# typo check is cpu consuming, but it will make debug easy.
# if typo check is not need (in production), please set env PYOPCUA_NO_TYPO_CHECK.
......@@ -750,6 +752,11 @@ class Variant(FrozenClass):
self.VariantType = value.VariantType
if self.VariantType is None:
self.VariantType = self._guess_type(self.Value)
if self.Value is None and self.VariantType not in (
VariantType.Null,
VariantType.String,
VariantType.DateTime):
raise UaError("Variant of type {} cannot have value None".format(self.VariantType))
if self.Dimensions is None and type(self.Value) in (list, tuple):
dims = get_shape(self.Value)
if len(dims) > 1:
......@@ -1032,3 +1039,47 @@ def datatype_to_varianttype(int_type):
return VariantType(int_type)
else:
return VariantTypeCustom(int_type)
def get_default_value(vtype):
"""
Given a variant type return default value for this type
"""
if vtype == VariantType.Null:
return None
elif vtype == VariantType.Boolean:
return False
elif vtype in (VariantType.SByte, VariantType.Byte, VariantType.ByteString):
return b""
elif 4 <= vtype.value <= 9:
return 0
elif vtype in (VariantType.Float, VariantType.Double):
return 0.0
elif vtype == VariantType.String:
return None # a string can be null
elif vtype == VariantType.DateTime:
return datetime.now()
elif vtype == VariantType.Guid:
return uuid.uuid4()
elif vtype == VariantType.XmlElement:
return None #Not sure this is correct
elif vtype == VariantType.NodeId:
return NodeId()
elif vtype == VariantType.ExpandedNodeId:
return NodeId()
elif vtype == VariantType.StatusCode:
return StatusCode()
elif vtype == VariantType.QualifiedName:
return QualifiedName()
elif vtype == VariantType.LocalizedText:
return LocalizedText()
elif vtype == VariantType.ExtensionObject:
return ExtensionObject()
elif vtype == VariantType.DataValue:
return DataValue()
elif vtype == VariantType.Variant:
return Variant()
else:
raise RuntimeError("function take a uatype as argument, got:", vtype)
......@@ -320,7 +320,7 @@ class TestServer(unittest.TestCase, CommonTests, SubscriptionTests, XmlTests):
ev = opcua.common.events.get_event_obj_from_type_node(etype)
check_custom_event(self, ev, etype)
self.assertEqual(ev.PropertyNum, None)
self.assertEqual(ev.PropertyNum, 0)
self.assertEqual(ev.PropertyString, None)
def test_eventgenerator_customEvent(self):
......@@ -330,7 +330,7 @@ class TestServer(unittest.TestCase, CommonTests, SubscriptionTests, XmlTests):
check_eventgenerator_CustomEvent(self, evgen, etype)
check_eventgenerator_SourceServer(self, evgen)
self.assertEqual(evgen.event.PropertyNum, None)
self.assertEqual(evgen.event.PropertyNum, 0)
self.assertEqual(evgen.event.PropertyString, None)
def test_eventgenerator_double_customEvent(self):
......@@ -343,12 +343,12 @@ class TestServer(unittest.TestCase, CommonTests, SubscriptionTests, XmlTests):
check_eventgenerator_SourceServer(self, evgen)
# Properties from MyEvent1
self.assertEqual(evgen.event.PropertyNum, None)
self.assertEqual(evgen.event.PropertyNum, 0)
self.assertEqual(evgen.event.PropertyString, None)
# Properties from MyEvent2
self.assertEqual(evgen.event.PropertyBool, None)
self.assertEqual(evgen.event.PropertyInt, None)
self.assertEqual(evgen.event.PropertyBool, False)
self.assertEqual(evgen.event.PropertyInt, 0)
def test_eventgenerator_customEvent_MyObject(self):
objects = self.opc.get_objects_node()
......@@ -359,7 +359,7 @@ class TestServer(unittest.TestCase, CommonTests, SubscriptionTests, XmlTests):
check_eventgenerator_CustomEvent(self, evgen, etype)
check_event_generator_object(self, evgen, o)
self.assertEqual(evgen.event.PropertyNum, None)
self.assertEqual(evgen.event.PropertyNum, 0)
self.assertEqual(evgen.event.PropertyString, None)
def test_context_manager(self):
......
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