Completed
Push — master ( 9d00d6...9c60ba )
by Olivier
04:47
created

is_child_present()   A

Complexity

Conditions 3

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
c 1
b 0
f 0
dl 0
loc 13
rs 9.4285
1
"""
2
Usefull method and classes not belonging anywhere and depending on opcua library
3
"""
4
5
from dateutil import parser
6
from datetime import datetime
7
from enum import Enum, IntEnum
8
9
from opcua import ua
10
from opcua.common.uaerrors import UaError
11
12
13
def val_to_string(val):
14
    """
15
    convert a python object or python-opcua object to a string
16
    which should be easy to understand for human
17
    easy to modify, and not too hard to parse back ....not easy
18
    meant for UI or command lines
19
20
    """
21
    if isinstance(val, (list, tuple)):
22
        res = []
23
        for v in val:
24
            res.append(val_to_string(v))
25
        return "[" + ", ".join(res) + "]"
26
27
    if hasattr(val, "to_string"):
28
        val = val.to_string()
29
    elif isinstance(val, ua.StatusCode):
30
        val = val.name
31
    elif isinstance(val, (Enum, IntEnum)):
32
        val = val.name
33
    elif isinstance(val, ua.DataValue):
34
        val = variant_to_string(val.Value)
35
    elif isinstance(val, str):
36
        pass
37
    elif isinstance(val, bytes):
38
        val = str(val)
39
    elif isinstance(val, datetime):
40
        val = val.isoformat()
41
    elif isinstance(val, (int, float)):
42
        val = str(val)
43
    else:
44
        # FIXME: Some types are probably missing!
45
        val = str(val)
46
    return val
47
48
49
def variant_to_string(var):
50
    """
51
    convert a variant to a string which should be easy to understand for human
52
    easy to modify, and not too hard to parse back ....not easy
53
    meant for UI or command lines
54
    """
55
    return val_to_string(var.Value)
56
57
58
def string_to_val(string, vtype):
59
    """
60
    Convert back a string to a python or python-opcua object 
61
    """
62
    string = string.strip()
63
    if string.startswith("["):
64
        string = string[1:-1]
65
        var = []
66
        for s in string.split(","):
67
            s = s.strip()
68
            val = string_to_val(s, vtype)
69
            var.append(val)
70
        return var
71
72
    if vtype == ua.VariantType.Null:
73
        val = None
74
    elif vtype == ua.VariantType.Boolean:
75
        val = bool(string)
76
    elif 4 <= vtype.value < 9:
77
        val = int(string)
78
    elif vtype in (ua.VariantType.Float, ua.VariantType.Double):
79
        val = float(string)
80
    elif vtype in (ua.VariantType.String, ua.VariantType.XmlElement):
81
        val = string
82
    elif vtype in (ua.VariantType.SByte, ua.VariantType.Guid, ua.VariantType.ByteString):
83
        val = bytes(string)
84
    elif vtype in (ua.VariantType.NodeId, ua.VariantType.ExpandedNodeId):
85
        val = ua.NodeId.from_string(string)
86
    elif vtype == ua.VariantType.QualifiedName:
87
        val = ua.QualifiedName.from_string(string)
88
    elif vtype == ua.VariantType.DateTime:
89
        val = parser.parse(string)
90
    elif vtype == ua.VariantType.LocalizedText:
91
        val = ua.LocalizedText(string)
92
    elif vtype == ua.VariantType.StatusCode:
93
        val = ua.StatusCode(string)
94
    else:
95
        # FIXME: Some types are probably missing!
96
        raise NotImplementedError
97
    return val
98
99
100
def string_to_variant(string, vtype):
101
    """
102
    convert back a string to an ua.Variant
103
    """
104
    return ua.Variant(string_to_val(string, vtype), vtype)
105
106
107
def get_node_subtypes(node, nodes=None):
108
    if nodes is None:
109
        nodes = [node]
110
    for child in node.get_children(refs=ua.ObjectIds.HasSubtype):
111
        nodes.append(child)
112
        get_node_subtypes(child, nodes)
113
    return nodes
114
115
116
def get_node_supertypes(node, includeitself = False, skipbase = True):
117
    """
118
    return get all subtype parents of node recursive
119
    :param server: used in case node is nodeid         
120
    :param node: can be a ua.Node or ua.NodeId
121
    :param includeitself: include also node to the list
122
    :param skipbase don't include the toplevel one
123
    :returns list of ua.Node, top parent first 
124
    """
125
    parents =[]      
126
    if includeitself:
127
        parents.append(node)
128
    parents.extend(_get_node_supertypes(node))
129
    if skipbase and len(parents) > 1:
130
        parents = parents [:-1]
131
        
132
    return parents
133
134
135
def _get_node_supertypes(node):
136
    """
137
    recursive implementation of get_node_derived_from_types
138
    """
139
    basetypes = []
140
    parents = node.get_referenced_nodes(refs=ua.ObjectIds.HasSubtype, direction=ua.BrowseDirection.Inverse, includesubtypes=True)
141
    if len(parents) != 0:  
142
        #TODO: Is it possible to have multiple subtypes ? If so extended support for it
143
       basetypes.append(parents[0])  
144
       basetypes.extend( _get_node_supertypes(parents[0]) )
145
       
146
    return basetypes
147
148
def is_child_present(node, browsename):
149
    """
150
    return if a browsename is present a child from the provide node
151
    :param node: node wherein to find the browsename
152
    :param browsename: browsename to search
153
    :returns returne True if the browsename is present else False 
154
    """
155
    child_descs = node.get_children_descriptions()
156
    for child_desc in child_descs:
157
        if child_desc.BrowseName == browsename:
158
            return True
159
160
    return False