Completed
Push — master ( 08a6b0...10a906 )
by Olivier
12:26
created

string_to_val()   F

Complexity

Conditions 18

Size

Total Lines 50

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 36
CRAP Score 18.9454

Importance

Changes 0
Metric Value
cc 18
dl 0
loc 50
ccs 36
cts 42
cp 0.8571
crap 18.9454
rs 2.7375
c 0
b 0
f 0

How to fix   Complexity   

Complexity

Complex classes like string_to_val() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
"""
2
Usefull method and classes not belonging anywhere and depending on opcua library
3
"""
4
5 1
from dateutil import parser
6 1
from datetime import datetime
7 1
from enum import Enum, IntEnum
8 1
import uuid
9
10 1
from opcua import ua
11 1
from opcua.ua.uaerrors import UaError
12
13
14 1
def val_to_string(val):
15
    """
16
    convert a python object or python-opcua object to a string
17
    which should be easy to understand for human
18
    easy to modify, and not too hard to parse back ....not easy
19
    meant for UI or command lines
20
21
    """
22 1
    if isinstance(val, (list, tuple)):
23 1
        res = []
24 1
        for v in val:
25 1
            res.append(val_to_string(v))
26 1
        return "[" + ", ".join(res) + "]"
27
28 1
    if hasattr(val, "to_string"):
29 1
        val = val.to_string()
30 1
    elif isinstance(val, ua.StatusCode):
31
        val = val.name
32 1
    elif isinstance(val, (Enum, IntEnum)):
33
        val = val.name
34 1
    elif isinstance(val, ua.DataValue):
35
        val = variant_to_string(val.Value)
36 1
    elif isinstance(val, ua.XmlElement):
37 1
        val = val.Value
38 1
    elif isinstance(val, str):
39 1
        pass
40 1
    elif isinstance(val, bytes):
41
        val = val.decode("utf-8")
42 1
    elif isinstance(val, datetime):
43
        val = val.isoformat()
44 1
    elif isinstance(val, (int, float)):
45 1
        val = str(val)
46
    else:
47
        # FIXME: Some types are probably missing!
48
        val = str(val)
49 1
    return val
50
51
52 1
def variant_to_string(var):
53
    """
54
    convert a variant to a string which should be easy to understand for human
55
    easy to modify, and not too hard to parse back ....not easy
56
    meant for UI or command lines
57
    """
58
    return val_to_string(var.Value)
59
60
61 1
def string_to_val(string, vtype):
62
    """
63
    Convert back a string to a python or python-opcua object
64
    Note: no error checking is done here, supplying null strings could raise exceptions (datetime and guid)
65
    """
66 1
    string = string.strip()
67 1
    if string.startswith("["):
68 1
        string = string[1:-1]
69 1
        var = []
70 1
        for s in string.split(","):
71 1
            s = s.strip()
72 1
            val = string_to_val(s, vtype)
73 1
            var.append(val)
74 1
        return var
75
76 1
    if vtype == ua.VariantType.Null:
77
        val = None
78 1
    elif vtype == ua.VariantType.Boolean:
79 1
        if string in ("True", "true", "on", "On", "1"):
80 1
            val = True
81
        else:
82
            val = False
83 1
    elif vtype in (ua.VariantType.SByte, ua.VariantType.Int16, ua.VariantType.Int32, ua.VariantType.Int64):
84 1
        val = int(string)
85 1
    elif vtype in (ua.VariantType.Byte, ua.VariantType.UInt16, ua.VariantType.UInt32, ua.VariantType.UInt64):
86 1
        val = int(string)
87 1
    elif vtype in (ua.VariantType.Float, ua.VariantType.Double):
88 1
        val = float(string)
89 1
    elif vtype == ua.VariantType.XmlElement:
90 1
        val = ua.XmlElement(string)
91 1
    elif vtype == ua.VariantType.String:
92 1
        val = string
93 1
    elif vtype == ua.VariantType.ByteString:
94
        val = string.encode()
95 1
    elif vtype in (ua.VariantType.NodeId, ua.VariantType.ExpandedNodeId):
96 1
        val = ua.NodeId.from_string(string)
97 1
    elif vtype == ua.VariantType.QualifiedName:
98 1
        val = ua.QualifiedName.from_string(string)
99 1
    elif vtype == ua.VariantType.DateTime:
100 1
        val = parser.parse(string)
101 1
    elif vtype == ua.VariantType.LocalizedText:
102 1
        val = ua.LocalizedText(string)
103 1
    elif vtype == ua.VariantType.StatusCode:
104 1
        val = ua.StatusCode(string)
105
    elif vtype == ua.VariantType.Guid:
106
        val = uuid.UUID(string)
107
    else:
108
        # FIXME: Some types are probably missing!
109
        raise NotImplementedError
110 1
    return val
111
112
113 1
def string_to_variant(string, vtype):
114
    """
115
    convert back a string to an ua.Variant
116
    """
117
    return ua.Variant(string_to_val(string, vtype), vtype)
118
119
120 1
def get_node_children(node, nodes=None):
121
    """
122
    Get recursively all children of a node
123
    """
124
    if nodes is None:
125
        nodes = [node]
126
    for child in node.get_children():
127
        nodes.append(child)
128
        get_node_children(child, nodes)
129
    return nodes
130
131
132 1
def get_node_subtypes(node, nodes=None):
133 1
    if nodes is None:
134 1
        nodes = [node]
135 1
    for child in node.get_children(refs=ua.ObjectIds.HasSubtype):
136 1
        nodes.append(child)
137 1
        get_node_subtypes(child, nodes)
138 1
    return nodes
139
140
141 1
def get_node_supertypes(node, includeitself=False, skipbase=True):
142
    """
143
    return get all subtype parents of node recursive
144
    :param node: can be a ua.Node or ua.NodeId
145
    :param includeitself: include also node to the list
146
    :param skipbase don't include the toplevel one
147
    :returns list of ua.Node, top parent first 
148
    """
149 1
    parents = []
150 1
    if includeitself:
151 1
        parents.append(node)
152 1
    parents.extend(_get_node_supertypes(node))
153 1
    if skipbase and len(parents) > 1:
154 1
        parents = parents[:-1]
155
156 1
    return parents
157
158
159 1
def _get_node_supertypes(node):
160
    """
161
    recursive implementation of get_node_derived_from_types
162
    """
163 1
    basetypes = []
164 1
    parent = get_node_supertype(node)
165 1
    if parent:
166 1
        basetypes.append(parent)
167 1
        basetypes.extend(_get_node_supertypes(parent))
168
169 1
    return basetypes
170
171
172 1
def get_node_supertype(node):
173
    """
174
    return node supertype or None
175
    """
176 1
    supertypes = node.get_referenced_nodes(refs=ua.ObjectIds.HasSubtype,
177
                                           direction=ua.BrowseDirection.Inverse,
178
                                           includesubtypes=True)
179 1
    if supertypes:
180 1
        return supertypes[0]
181
    else:
182 1
        return None
183
184
185 1
def is_child_present(node, browsename):
186
    """
187
    return if a browsename is present a child from the provide node
188
    :param node: node wherein to find the browsename
189
    :param browsename: browsename to search
190
    :returns returne True if the browsename is present else False 
191
    """
192 1
    child_descs = node.get_children_descriptions()
193 1
    for child_desc in child_descs:
194 1
        if child_desc.BrowseName == browsename:
195
            return True
196
197 1
    return False
198
199
200 1
def data_type_to_variant_type(dtype_node):
201
    """
202
    Given a Node datatype, find out the variant type to encode
203
    data. This is not exactly straightforward...
204
    """
205 1
    base = get_base_data_type(dtype_node)
206
207 1
    if base.nodeid.Identifier != 29:
208 1
        return ua.VariantType(base.nodeid.Identifier)
209
    else:
210
        # we have an enumeration, value is a Int32
211 1
        return ua.VariantType.Int32
212
213 1
def get_base_data_type(datatype):
214
    """
215
    Looks up the base datatype of the provided datatype Node
216
    The base datatype is either:
217
    A primitive type (ns=0, i<=21) or a complex one (ns=0 i>21 and i<=30) like Enum and Struct.
218
    
219
    Args:
220
        datatype: NodeId of a datype of a variable
221
    Returns:
222
        NodeId of datatype base or None in case base datype can not be determined
223
    """
224 1
    base = datatype
225 1
    while base:
226 1
        if base.nodeid.NamespaceIndex == 0 and isinstance(base.nodeid.Identifier, int) and base.nodeid.Identifier <= 30:
227 1
            return base
228 1
        base = get_node_supertype(base)
229
    raise ua.UaError("Datatype must be a subtype of builtin types {0!s}".format(datatype))
230
231
232 1
def get_nodes_of_namespace(server, namespaces=None):
233
    """
234
    Get the nodes of one or more namespaces .      
235
    Args:
236
        server: opc ua server to use
237
        namespaces: list of string uri or int indexes of the namespace to export
238
    Returns:
239
        List of nodes that are part of the provided namespaces
240
    """
241 1
    if namespaces is None:
242
        namespaces = []
243 1
    ns_available = server.get_namespace_array()
244
245 1
    if not namespaces:
246
        namespaces = ns_available[1:]
247 1
    elif isinstance(namespaces, (str, int)):
248 1
        namespaces = [namespaces]
249
250
    # make sure all namespace are indexes (if needed convert strings to indexes)
251 1
    namespace_indexes = [n if isinstance(n, int) else ns_available.index(n) for n in namespaces]
252
253
    # filter nodeis based on the provide namespaces and convert the nodeid to a node
254 1
    nodes = [server.get_node(nodeid) for nodeid in server.iserver.aspace.keys()
255
             if nodeid.NamespaceIndex != 0 and nodeid.NamespaceIndex in namespace_indexes]
256 1
    return nodes
257
258
259 1
def get_default_value(uatype):
260
    if isinstance(uatype, ua.VariantType):
261
        return ua.get_default_values(uatype)
262
    elif hasattr(ua.VariantType, uatype):
263
        return ua.get_default_value(getattr(ua.VariantType, uatype))
264
    else:
265
        return getattr(ua, uatype)()
266
267
268