GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Push — master ( 6a8cca...016d6e )
by P.R.
03:02
created

Node.validate()   B

Complexity

Conditions 3

Size

Total Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 3
c 2
b 0
f 0
dl 0
loc 24
ccs 0
cts 12
cp 0
crap 12
rs 8.9713
1
"""
2
Enarksh
3
4
Copyright 2013-2016 Set Based IT Consultancy
5
6
Licence MIT
7
"""
8
import abc
9
10
from enarksh.DataLayer import DataLayer
11
12
from enarksh.XmlReader.Consumption.CountingConsumption import CountingConsumption
13
from enarksh.XmlReader.Consumption.ReadWriteLockConsumption import ReadWriteLockConsumption
14
from enarksh.XmlReader.Port.InputPort import InputPort
15
from enarksh.XmlReader.Port.OutputPort import OutputPort
16
17
18
class Node(metaclass=abc.ABCMeta):
19
    # ------------------------------------------------------------------------------------------------------------------
20
    """
21
    Abstract class for parsing XML definition of nodes.
22
    """
23
    def __init__(self, parent_node=None):
24
        self._node_name = ''
25
        """
26
        The name of this node.
27
28
        :type: str
29
        """
30
31
        self._user_name = ''
32
        """
33
        The user under which this node or its child nodes must run.
34
35
        :type: str
36
        """
37
38
        self._input_ports = {}
39
        """
40
        The input ports of this node.
41
42
        :type: dict
43
        """
44
45
        self._output_ports = {}
46
        """
47
        The output ports of this node.
48
49
        :type: dict
50
        """
51
52
        self._consumptions = {}
53
        """
54
        The consumptions of this node.
55
56
        :type: dict
57
        """
58
59
        self._nod_id = 0
60
        """
61
        The ID of this node when it is stored in the database.
62
63
        :type: int
64
        """
65
66
        self._parent_node = parent_node
67
        """
68
        The parent node of this node.
69
70
        :type: Node
71
        """
72
73
        self._recursion_level = -1
74
        """
75
        The recursion level of this node. I.e. the total number of (recursive) parent nodes.
76
77
        :type: int
78
        """
79
80
        self._dependency_level = -1
81
        """
82
        The dependency level of this node. I.e. the number of predecessors of this node (with the parent node).
83
84
        :type: int
85
        """
86
87
        self._user_name = ''
88
        """
89
        The user under which this node or its child nodes must run.
90
91
        :type: str
92
        """
93
94
    # ------------------------------------------------------------------------------------------------------------------
95
    @property
96
    def name(self):
97
        """
98
        Returns the name of this node.
99
100
        :rtype: str
101
        """
102
        return self._node_name
103
104
    # ------------------------------------------------------------------------------------------------------------------
105
    @property
106
    def nod_id(self):
107
        """
108
        Returns the ID of this node.
109
110
        :rtype: int
111
        """
112
        return self._nod_id
113
114
    # ------------------------------------------------------------------------------------------------------------------
115
    @property
116
    def parent_node(self):
117
        """
118
        Returns the parent node of this node.
119
120
        :rtype: Node
121
        """
122
        return self._parent_node
123
124
    # ------------------------------------------------------------------------------------------------------------------
125
    def read_xml(self, xml):
126
        """
127
        :param xml.etree.ElementTree.Element xml:
128
        """
129
        for element in list(xml):
130
            self.read_xml_element(element)
131
132
    # ------------------------------------------------------------------------------------------------------------------
133
    def read_xml_element(self, xml):
134
        """
135
        :param xml.etree.ElementTree.Element xml:
136
        """
137
        tag = xml.tag
138
        if tag == 'NodeName':
139
            self._node_name = xml.text
140
141
        elif tag == 'UserName':
142
            self._user_name = xml.text
143
144
        elif tag == 'InputPorts':
145
            self._read_xml_input_ports(xml)
146
147
        elif tag == 'Consumptions':
148
            self._read_xml_consumptions(xml)
149
150
        elif tag == 'OutputPorts':
151
            self._read_xml_output_ports(xml)
152
153
        else:
154
            raise Exception("Unexpected tag '{0!s}'.".format(tag))
155
156
    # ------------------------------------------------------------------------------------------------------------------
157
    def _read_xml_consumptions(self, xml):
158
        """
159
        :param xml.etree.ElementTree.Element xml:
160
        """
161
        for element in list(xml):
162
            tag = element.tag
163
            if tag == 'CountingConsumption':
164
                consumption = CountingConsumption(self)
165
166
            elif tag == 'ReadWriteLockConsumption':
167
                consumption = ReadWriteLockConsumption(self)
168
169
            else:
170
                raise Exception("Unexpected tag '{0!s}'.".format(tag))
171
172
            consumption.read_xml(element)
173
            name = consumption.get_name()
174
            # Check for consumptions with duplicate names.
175
            if name in self._consumptions:
176
                raise Exception("Duplicate consumption '{0!s}'.".format(name))
177
178
            self._consumptions[name] = consumption
179
180
    # ------------------------------------------------------------------------------------------------------------------
181
    def _read_xml_input_ports(self, xml):
182
        """
183
        :param xml.etree.ElementTree.Element xml:
184
        """
185
        for element in list(xml):
186
            tag = element.tag
187
            if tag == 'Port':
188
                port = InputPort(self)
189
                port.read_xml(element)
190
191
                name = port.name
192
                # Check for ports with duplicate names.
193
                if name in self._input_ports:
194
                    raise Exception("Duplicate input port '{0!s}'.".format(name))
195
196
                self._input_ports[name] = port
197
198
            else:
199
                raise Exception("Unexpected tag '{0!s}'.".format(tag))
200
201
    # ------------------------------------------------------------------------------------------------------------------
202
    def _read_xml_output_ports(self, xml):
203
        """
204
        :param xml.etree.ElementTree.Element xml:
205
        """
206
        for element in list(xml):
207
            tag = element.tag
208
            if tag == 'Port':
209
                port = OutputPort(self)
210
                port.read_xml(element)
211
212
                name = port.name
213
                # Check for ports with duplicate names.
214
                if name in self._output_ports:
215
                    raise Exception("Duplicate output port '{0!s}'.".format(name))
216
217
                self._output_ports[name] = port
218
219
            else:
220
                raise Exception("Unexpected tag '{0!s}'.".format(tag))
221
222
    # ------------------------------------------------------------------------------------------------------------------
223
    @abc.abstractmethod
224
    def get_resource_by_name(self, resource_name):
225
        """
226
        Returns a resource of the node.
227
228
        :param str resource_name: The name of the resource.
229
        """
230
        raise NotImplementedError()
231
232
    # ------------------------------------------------------------------------------------------------------------------
233
    @staticmethod
234
    def is_activate_node():
235
        """
236
        Returns true if this node is a ActivateNode. Otherwise return false.
237
238
        :rtype: bool
239
        """
240
        return False
241
242
    # ------------------------------------------------------------------------------------------------------------------
243
    @staticmethod
244
    def is_arrest_node():
245
        """
246
        Returns true if this node is a ActivateNode. Otherwise return false.
247
248
        :rtype: bool
249
        """
250
        return False
251
252
    # ------------------------------------------------------------------------------------------------------------------
253
    def get_dependency_level(self):
254
        """
255
        Returns the dependency level (i.e. the number of predecessors of this node within the parent node) of this node.
256
257
        :rtype: int
258
        """
259
        if self._dependency_level == -1:
260
            self._dependency_level = 0
261
            for port in self._input_ports.values():
262
                level = port.get_dependency_level()
263
                if level >= self._dependency_level:
264
                    self._dependency_level = level + 1
265
266
        return self._dependency_level
267
268
    # ------------------------------------------------------------------------------------------------------------------
269
    def get_uri(self, obj_type='node'):
270
        """
271
        Returns the URI of this node.
272
273
        :param str obj_type: The entity type.
274
275
        :rtype: str
276
        """
277
        if self._parent_node:
278
            uri = self._parent_node.get_uri(obj_type)
279
        else:
280
            uri = '//' + obj_type
281
282
        return uri + '/' + self._node_name
283
284
    # ------------------------------------------------------------------------------------------------------------------
285
    def get_user_name(self):
286
        """
287
        Returns the user name under which this node must run.
288
289
        :rtype: str
290
        """
291
        if self._user_name:
292
            return self._user_name
293
294
        if self._parent_node:
295
            self._user_name = self._parent_node.get_user_name()
296
297
        return self._user_name
298
299
    # ------------------------------------------------------------------------------------------------------------------
300
    def validate(self, fake_parent=None):
301
        """
302
        Validates this node against rules which are not imposed by XSD.
303
304
        :param fake_parent:
305
306
        :rtype: str
307
        """
308
        self._parent_node = fake_parent
309
310
        errors = []
311
        """:type errors: list[dict[str,str]]"""
0 ignored issues
show
Unused Code introduced by
This string statement has no effect and could be removed.
Loading history...
312
        self._validate_helper(errors)
313
314
        if errors:
315
            message = ''
316
            for error in errors:
317
                message += 'URI:   ' + error['uri'] + '\n'
318
                message += 'Rule:  ' + error['rule'] + '\n'
319
                message += 'Error: ' + error['error'] + '\n'
320
321
            return message
322
323
        return ''
324
325
    # ------------------------------------------------------------------------------------------------------------------
326
    def _validate_helper(self, errors):
327
        """
328
        Helper function for validation this node.
329
330
        :param list[dict[str,str]] errors: A list of error messages.
331
        """
332
        # Validate all input ports.
333
        for port in self._input_ports.values():
334
            port.validate(errors)
335
336
        # Validate all consumptions.
337
        for consumption in self._consumptions.values():
338
            consumption.validate(errors)
339
340
        # @todo Validate no circular references exists.
341
342
        # Validate all output ports.
343
        for port in self._output_ports.values():
344
            port.validate(errors)
345
346
    # ------------------------------------------------------------------------------------------------------------------
347
    def store(self, srv_id, p_nod_master):
348
        """
349
        Stores the definition of this node into the database.
350
351
        :param int srv_id: The ID of the schedule revision to which this node belongs.
352
        :param int p_nod_master:
353
        """
354
        # Get uri_id for this node.
355
        uri_id = DataLayer.enk_misc_insert_uri(self.get_uri())
356
357
        # Store the definition of the node self.
358
        self._store_self(srv_id, uri_id, p_nod_master)
359
360
        # Store the consumptions of this node.
361
        for consumption in self._consumptions.values():
362
            consumption.store(self._nod_id)
363
364
        # Store the input ports of this node.
365
        for port in self._input_ports.values():
366
            port.store(self._nod_id)
367
368
        # Store the output ports of this node.
369
        for port in self._output_ports.values():
370
            port.store(self._nod_id)
371
372
    # ------------------------------------------------------------------------------------------------------------------
373
    def get_port_by_name(self, node_name, port_name):
374
        """
375
        Return an output port of a child node of this node or an input port this node.
376
377
        :param str node_name:
378
        :param str port_name:
379
380
        :rtype: str
381
        """
382
        if node_name == '.':
383
            return self._input_ports[port_name]
384
385
        node = self.get_node_by_name(node_name)
386
387
        return node._output_ports[port_name]
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _output_ports was declared protected and should not be accessed from this context.

Prefixing a member variable _ is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class:

class MyParent:
    def __init__(self):
        self._x = 1;
        self.y = 2;

class MyChild(MyParent):
    def some_method(self):
        return self._x    # Ok, since accessed from a child class

class AnotherClass:
    def some_method(self, instance_of_my_child):
        return instance_of_my_child._x   # Would be flagged as AnotherClass is not
                                         # a child class of MyParent
Loading history...
388
389
    # ------------------------------------------------------------------------------------------------------------------
390
    @abc.abstractmethod
391
    def get_node_by_name(self, node_name):
392
        """
393
        Returns a child node of this node by name.
394
395
        :param str node_name: The name of the searched child node.
396
397
        :rtype: enarksh.XmlReader.Node.Node.Node
398
        """
399
        raise NotImplementedError()
400
401
    # ------------------------------------------------------------------------------------------------------------------
402
    def store_dependencies(self):
403
        """
404
        Stores the dependencies of this node into the database.
405
        """
406
        # Store the dependencies of the input ports of this node.
407
        for port in self._input_ports.values():
408
            port.store_dependencies()
409
410
        # Store the dependencies of the output ports of this node.
411
        for port in self._output_ports.values():
412
            port.store_dependencies()
413
414
    # ------------------------------------------------------------------------------------------------------------------
415
    @abc.abstractmethod
416
    def set_levels(self, recursion_level=0):
417
        """
418
        Sets the recursion level (i.e. the number of parent nodes) of the child nodes of this node.
419
420
        :param int recursion_level: The recursion level of this node.
421
        """
422
        raise NotImplementedError()
423
424
    # ------------------------------------------------------------------------------------------------------------------
425
    @abc.abstractmethod
426
    def _store_self(self, srv_id, uri_id, p_nod_master):
427
        """
428
        Stores the definition of this node into the database.
429
430
        :param int srv_id: The ID of the schedule to which this node belongs.
431
        :param int uri_id: The ID of the URI of this node.
432
        :param int p_nod_master:
433
        """
434
        raise NotImplementedError()
435
436
# ----------------------------------------------------------------------------------------------------------------------
437