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
Pull Request — master (#4)
by Oleg
02:28
created

Node.parent_node()   A

Complexity

Conditions 1

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
dl 0
loc 8
ccs 0
cts 2
cp 0
crap 2
rs 9.4285
c 0
b 0
f 0
1
"""
2
Enarksh
3
4
Copyright 2013-2016 Set Based IT Consultancy
5
6
Licence MIT
7
"""
8
import abc
9
from xml.etree.ElementTree import Element
0 ignored issues
show
Unused Code introduced by
Unused Element imported from xml.etree.ElementTree
Loading history...
10
11
from enarksh.DataLayer import DataLayer
12
13
from enarksh.XmlReader.Consumption.CountingConsumption import CountingConsumption
14
from enarksh.XmlReader.Consumption.ReadWriteLockConsumption import ReadWriteLockConsumption
15
from enarksh.XmlReader.Port.InputPort import InputPort
16
from enarksh.XmlReader.Port.OutputPort import OutputPort
17
18
19
class Node:
20
    # ------------------------------------------------------------------------------------------------------------------
21
    """
22
    Abstract class for parsing XML definition of nodes.
23
    """
24
    def __init__(self, parent_node=None):
25
        self._node_name = ''
26
        """
27
        The name of this node.
28
29
        :type: str
30
        """
31
32
        self._user_name = ''
33
        """
34
        The user under which this node or its child nodes must run.
35
36
        :type: str
37
        """
38
39
        self._input_ports = {}
40
        """
41
        The input ports of this node.
42
43
        :type: dict
44
        """
45
46
        self._output_ports = {}
47
        """
48
        The output ports of this node.
49
50
        :type: dict
51
        """
52
53
        self._consumptions = {}
54
        """
55
        The consumptions of this node.
56
57
        :type: dict
58
        """
59
60
        self._nod_id = 0
61
        """
62
        The ID of this node when it is stored in the database.
63
64
        :type: int
65
        """
66
67
        self._parent_node = parent_node
68
        """
69
        The parent node of this node.
70
71
        :type: Node
72
        """
73
74
        self._recursion_level = -1
75
        """
76
        The recursion level of this node. I.e. the total number of (recursive) parent nodes.
77
78
        :type: int
79
        """
80
81
        self._dependency_level = -1
82
        """
83
        The dependency level of this node. I.e. the number of predecessors of this node (with the parent node).
84
85
        :type: int
86
        """
87
88
        self._user_name = ''
89
        """
90
        The user under which this node or its child nodes must run.
91
92
        :type: str
93
        """
94
95
    # ------------------------------------------------------------------------------------------------------------------
96
    @property
97
    def name(self):
98
        """
99
        Returns the name of this node.
100
101
        :rtype: str
102
        """
103
        return self._node_name
104
105
    # ------------------------------------------------------------------------------------------------------------------
106
    @property
107
    def nod_id(self):
108
        """
109
        Returns the ID of this node.
110
111
        :rtype: int
112
        """
113
        return self._nod_id
114
115
    # ------------------------------------------------------------------------------------------------------------------
116
    @property
117
    def parent_node(self):
118
        """
119
        Returns the parent node of this node.
120
121
        :rtype: Node
122
        """
123
        return self._parent_node
124
125
    # ------------------------------------------------------------------------------------------------------------------
126
    def read_xml(self, xml):
127
        """
128
        :param xml.etree.ElementTree.Element xml:
129
        """
130
        for element in list(xml):
131
            self.read_xml_element(element)
132
133
    # ------------------------------------------------------------------------------------------------------------------
134
    def read_xml_element(self, xml):
135
        """
136
        :param xml.etree.ElementTree.Element xml:
137
        """
138
        tag = xml.tag
139
        if tag == 'NodeName':
140
            self._node_name = xml.text
141
142
        elif tag == 'UserName':
143
            self._user_name = xml.text
144
145
        elif tag == 'InputPorts':
146
            self._read_xml_input_ports(xml)
147
148
        elif tag == 'Consumptions':
149
            self._read_xml_consumptions(xml)
150
151
        elif tag == 'OutputPorts':
152
            self._read_xml_output_ports(xml)
153
154
        else:
155
            raise Exception("Unexpected tag '{0!s}'.".format(tag))
156
157
    # ------------------------------------------------------------------------------------------------------------------
158
    def _read_xml_consumptions(self, xml):
159
        """
160
        :param xml.etree.ElementTree.Element xml:
161
        """
162
        for element in list(xml):
163
            tag = element.tag
164
            if tag == 'CountingConsumption':
165
                consumption = CountingConsumption(self)
166
167
            elif tag == 'ReadWriteLockConsumption':
168
                consumption = ReadWriteLockConsumption(self)
169
170
            else:
171
                raise Exception("Unexpected tag '{0!s}'.".format(tag))
172
173
            consumption.read_xml(element)
174
            name = consumption.get_name()
175
            # Check for consumptions with duplicate names.
176
            if name in self._consumptions:
177
                raise Exception("Duplicate consumption '{0!s}'.".format(name))
178
179
            self._consumptions[name] = consumption
180
181
    # ------------------------------------------------------------------------------------------------------------------
182
    def _read_xml_input_ports(self, xml):
183
        """
184
        :param xml.etree.ElementTree.Element xml:
185
        """
186
        for element in list(xml):
187
            tag = element.tag
188
            if tag == 'Port':
189
                port = InputPort(self)
190
                port.read_xml(element)
191
192
                name = port.name
193
                # Check for ports with duplicate names.
194
                if name in self._input_ports:
195
                    raise Exception("Duplicate input port '{0!s}'.".format(name))
196
197
                self._input_ports[name] = port
198
199
            else:
200
                raise Exception("Unexpected tag '{0!s}'.".format(tag))
201
202
    # ------------------------------------------------------------------------------------------------------------------
203
    def _read_xml_output_ports(self, xml):
204
        """
205
        :param xml.etree.ElementTree.Element xml:
206
        """
207
        for element in list(xml):
208
            tag = element.tag
209
            if tag == 'Port':
210
                port = OutputPort(self)
211
                port.read_xml(element)
212
213
                name = port.name
214
                # Check for ports with duplicate names.
215
                if name in self._output_ports:
216
                    raise Exception("Duplicate output port '{0!s}'.".format(name))
217
218
                self._output_ports[name] = port
219
220
            else:
221
                raise Exception("Unexpected tag '{0!s}'.".format(tag))
222
223
    # ------------------------------------------------------------------------------------------------------------------
224
    @abc.abstractmethod
225
    def get_resource_by_name(self, resource_name):
226
        """
227
        Returns a resource of the node.
228
229
        :param str resource_name: The name of the resource.
230
        """
231
        pass
232
233
    # ------------------------------------------------------------------------------------------------------------------
234
    @staticmethod
235
    def is_activate_node():
236
        """
237
        Returns true if this node is a ActivateNode. Otherwise return false.
238
239
        :rtype: bool
240
        """
241
        return False
242
243
    # ------------------------------------------------------------------------------------------------------------------
244
    @staticmethod
245
    def is_arrest_node():
246
        """
247
        Returns true if this node is a ActivateNode. Otherwise return false.
248
249
        :rtype: bool
250
        """
251
        return False
252
253
    # ------------------------------------------------------------------------------------------------------------------
254
    def get_dependency_level(self):
255
        """
256
        Returns the dependency level (i.e. the number of predecessors of this node within the parent node) of this node.
257
258
        :rtype: int
259
        """
260
        if self._dependency_level == -1:
261
            self._dependency_level = 0
262
            for port in self._input_ports.values():
263
                level = port.get_dependency_level()
264
                if level >= self._dependency_level:
265
                    self._dependency_level = level + 1
266
267
        return self._dependency_level
268
269
    # ------------------------------------------------------------------------------------------------------------------
270
    def get_uri(self, obj_type='node'):
271
        """
272
        Returns the URI of this node.
273
274
        :param str obj_type: The entity type.
275
276
        :rtype: str
277
        """
278
        if self._parent_node:
279
            uri = self._parent_node.get_uri(obj_type)
280
        else:
281
            uri = '//' + obj_type
282
283
        return uri + '/' + self._node_name
284
285
    # ------------------------------------------------------------------------------------------------------------------
286
    def get_user_name(self):
287
        """
288
        Returns the user name under which this node must run.
289
290
        :rtype: str
291
        """
292
        if self._user_name:
293
            return self._user_name
294
295
        if self._parent_node:
296
            self._user_name = self._parent_node.get_user_name()
297
298
        return self._user_name
299
300
    # ------------------------------------------------------------------------------------------------------------------
301
    def validate(self, fake_parent=None):
302
        """
303
        Validates this node against rules which are not imposed by XSD.
304
305
        :param fake_partnt:
306
307
        :rtype: str
308
        """
309
        self._parent_node = fake_parent
310
311
        errors = []
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 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:
396
        """
397
        pass
398
399
    # ------------------------------------------------------------------------------------------------------------------
400
    def store_dependencies(self):
401
        """
402
        Stores the dependencies of this node into the database.
403
        """
404
        # Store the dependencies of the input ports of this node.
405
        for port in self._input_ports.values():
406
            port.store_dependencies()
407
408
        # Store the dependencies of the output ports of this node.
409
        for port in self._output_ports.values():
410
            port.store_dependencies()
411
412
    # ------------------------------------------------------------------------------------------------------------------
413
    @abc.abstractmethod
414
    def set_levels(self, recursion_level=0):
415
        """
416
        Sets the recursion level (i.e. the number of parent nodes) of the child nodes of this node.
417
418
        :param int recursion_level: The recursion level of this node.
419
        """
420
        pass
421
422
    # ------------------------------------------------------------------------------------------------------------------
423
    @abc.abstractmethod
424
    def _store_self(self, srv_id, uri_id, p_nod_master):
425
        """
426
        Stores the definition of this node into the database.
427
428
        :param int srv_id: The ID of the schedule to which this node belongs.
429
        :param int uri_id: The ID of the URI of this node.
430
        :param int p_nod_master:
431
        """
432
        pass
433
434
# ----------------------------------------------------------------------------------------------------------------------
435