Passed
Push — master ( 4b3140...3dcfbb )
by P.R.
01:38
created

Port.generate_xml()   B

Complexity

Conditions 4

Size

Total Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 23
rs 8.7972
cc 4
1
"""
2
Enarksh
3
4
Copyright 2015-2016 Set Based IT Consultancy
5
6
Licence MIT
7
"""
8
import abc
9
from xml.etree.ElementTree import SubElement
10
11
12
class Port:
13
    """
14
    Class Port
15
    Class for generating XML messages for elements of type 'InputPortType' and 'OutputPortType'.
16
    """
17
18
    NODE_SELF_NAME = '.'  # -- @todo Discuss about this constant, because I can't import Node.
19
    """
20
    Token for node self.
21
    """
22
23
    # ------------------------------------------------------------------------------------------------------------------
24
    def __init__(self, node, port_name):
25
        """
26
        Object constructor.
27
        """
28
29
        self._node = node
30
        """
31
        The node of which this port is a port.
32
33
        :type: enarksh_lib.xml_generator.node.Node.Node
34
        """
35
36
        self._port_name = port_name
37
        """
38
        The name of this port.
39
40
        :type: str
41
        """
42
43
        self._predecessors = []
44
        """
45
        The dependencies of this port.
46
47
        :type: list[enarksh_lib.xml_generator.port.Port.Port]
48
        """
49
50
        self._successors = []
51
        """
52
        The dependants of this port.
53
54
        :type: list[enarksh_lib.xml_generator.port.Port.Port]
55
        """
56
57
    # ------------------------------------------------------------------------------------------------------------------
58
    def add_dependency(self, port):
59
        """
60
        Add a port as a dependency of this port.
61
62
        :param enarksh_lib.xml_generator.port.Port.Port port: The port that depends on this port.
63
        """
64
        # -- @todo Validate owner of port and owner of this port.
65
66
        if port not in self._predecessors:
67
            self._predecessors.append(port)
68
69
    # ------------------------------------------------------------------------------------------------------------------
70
    def generate_xml(self, parent):
71
        """
72
        Generates the XML element for this port.
73
74
        :param xml.etree.ElementTree.Element parent: The parent XML element.
75
        """
76
        port = SubElement(parent, 'Port')
77
78
        port_name = SubElement(port, 'PortName')
79
        port_name.text = self._port_name
80
81
        if self._predecessors:
82
            dependencies_element = SubElement(port, 'Dependencies')
83
84
            for predecessor in self._predecessors:
85
                dependency = SubElement(dependencies_element, 'Dependency')
86
87
                node_name = SubElement(dependency, 'NodeName')
88
                node_name.text = self.NODE_SELF_NAME if predecessor._node == self._node.get_parent() \
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _node 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...
89
                    else self._node.get_name()
90
91
                port_name = SubElement(dependency, 'PortName')
92
                port_name.text = self._port_name
93
94
    # ------------------------------------------------------------------------------------------------------------------
95
    def get_all_dependencies(self):
96
        """
97
        Returns all the dependencies of this port.
98
99
        :rtype: enarksh_lib.xml_generator.port.Port.Port port:
100
        """
101
        return self._predecessors
102
103
    # ------------------------------------------------------------------------------------------------------------------
104
    def get_dependencies_ports(self, ports, level):
105
        """
106
107
        :param list[enarksh_lib.xml_generator.port.Port.Port] ports:
108
        :param int                                            level:
109
110
        :rtype: list[]
111
        """
112
        for port in self._predecessors:
113
            if port not in ports:
114
                if level:
115
                    ports.append(port)
116
                port.get_implicit_dependencies_ports(ports, level + 1)
117
118
    # ------------------------------------------------------------------------------------------------------------------
119
    @abc.abstractmethod
120
    def get_implicit_dependencies_ports(self, ports, level):
121
        """
122
        :param list[enarksh_lib.xml_generator.port.Port.Port] ports:
123
        :param int                                            level:
124
        """
125
        raise NotImplementedError()
126
127
    # ------------------------------------------------------------------------------------------------------------------
128
    def get_name(self):
129
        """
130
        Returns the name of this port.
131
132
        :rtype: str
133
        """
134
        return self._port_name
135
136
    # ------------------------------------------------------------------------------------------------------------------
137
    def get_node(self):
138
        """
139
        Returns the node of this port.
140
141
        :rtype: enarksh_lib.xml_generator.node.Node.Node
142
        """
143
        return self._node
144
145
    # ------------------------------------------------------------------------------------------------------------------
146
    def get_node_name(self):
147
        """
148
        Returns the name of the node to which this port belongs.
149
150
        :rtype: str
151
        """
152
        self._node.get_name()
153
154
    # ------------------------------------------------------------------------------------------------------------------
155
    def purge(self):
156
        """
157
        Removes dependencies from this port that are implicit dependencies (via one or more predecessors).
158
        """
159
        # Get all implicit dependencies ports.
160
        implicit_dependencies = []
161
        for port in self._predecessors:
162
            port.get_implicit_dependencies_ports(implicit_dependencies, 0)
163
164
        # Create a new dependency array without implicit dependencies.
165
        direct_dependencies = []
166
        for port in self._predecessors:
167
            if port not in implicit_dependencies:
168
169
                # Prevent duplicate dependencies.
170
                if port not in direct_dependencies:
171
                    direct_dependencies.append(port)
172
173
        self._predecessors = direct_dependencies
174
175
    # ------------------------------------------------------------------------------------------------------------------
176
    def replace_node_dependency(self, node_name, dependencies):
177
        """
178
        Replaces any dependency of this port on node 'node_name' with dependencies 'dependencies'.
179
180
        :param str    node_name:
181
        :param list[] dependencies:
182
        """
183
        obsolete = []
184
185
        # Find any predecessor that depends on node 'node_name'.
186
        for index, port in enumerate(self._predecessors):
187
            if port.get_node_name() == node_name:
188
                obsolete.append(index)
189
190
        if obsolete:
191
            # Remove all dependencies of node 'node_name'.
192
            for index in obsolete:
193
                self._predecessors.pop(index)
194
195
            # And replace those dependencies with 'dependencies'.
196
            for dep in dependencies:
197
                self._predecessors.append(dep)
198
199
# ----------------------------------------------------------------------------------------------------------------------
200