Passed
Branch master (0442a2)
by P.R.
02:00
created

ArrayDataType.debug()   F

Complexity

Conditions 10

Size

Total Lines 45

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 45
rs 3.1304
cc 10

How to fix   Complexity   

Complexity

Complex classes like ArrayDataType.debug() 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
SDoc
3
4
Copyright 2016 Set Based IT Consultancy
5
6
Licence MIT
7
"""
8
# ----------------------------------------------------------------------------------------------------------------------
9
import copy
10
from sdoc.sdoc1.data_type.DataType import DataType
11
from sdoc.sdoc1.error import DataTypeError
12
13
14
class ArrayDataType(DataType):
0 ignored issues
show
Unused Code introduced by
This abstract class does not seem to be used anywhere.
Loading history...
15
    """
16
    Class for array data types.
17
    """
18
19
    # ------------------------------------------------------------------------------------------------------------------
20
    def __init__(self):
21
        self._elements = {}
22
        """
23
        The elements in this array.
24
25
        :type: dict[mixed, sdoc.sdoc1.data_type.DataType.DataType]
26
        """
27
28
    # ------------------------------------------------------------------------------------------------------------------
29
    def debug(self, indent=0):
30
        """
31
        Returns a string for debugging.
32
33
        :param int indent: The indentation level.
34
35
        :rtype: str
36
        """
37
        ret = '[\n'
38
        sep = " => "
39
        longest = 0
40
        brace_indent = indent
41
        first = True
42
43
        # Find the length of the longest key.
44
        for key in self._elements:
45
            if len("{0!s}".format(key)) >= longest:
46
                longest = len("{0!s}".format(key))
47
                if isinstance(key, str):
48
                    # The longest key is a string. Add 2 positions for quotes.
49
                    longest += 2
50
51
        for key in sorted(self._elements, key=lambda x: str(x)):
0 ignored issues
show
Unused Code introduced by
This lambda might be unnecessary.
Loading history...
52
            # Checking the key type, and setting quotes.
53
            if isinstance(key, int):
54
                str1 = " " + " " * indent + "{}".format(key).ljust(longest, " ")
55
            elif isinstance(key, str):
56
                str1 = " " + " " * indent + "'{}'".format(key).ljust(longest, " ")
57
58
            # Creating indentation level.
59
            if isinstance(self._elements[key], ArrayDataType):
60
                # Need this check if we have many nested nodes.
61
                if first:
62
                    indent += len(str1 + sep)
63
                else:
64
                    indent = len(str1 + sep)
65
                str2 = "{}".format(self._elements[key].debug(indent)).ljust(longest, " ")
66
                ret += str1 + sep + str2
67
            else:
68
                str2 = "{}".format(self._elements[key].debug()).strip()
69
                ret += str1 + sep + str2 + "\n"
70
71
            first = False
72
73
        return ret + brace_indent * " " + "]\n"
74
75
    # ------------------------------------------------------------------------------------------------------------------
76
    def dereference(self):
77
        """
78
        Returns a clone of this array.
79
80
        :rtype: ArrayDataType
81
        """
82
        tmp = ArrayDataType()
83
        tmp._elements = copy.deepcopy(self._elements)
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _elements 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...
84
85
        return tmp
86
87
    # ------------------------------------------------------------------------------------------------------------------
88
    def get_array(self, key):
89
        """
90
        Adds a new elements to this array. If the key holds an element already the element will be replaced.
91
92
        :param int_str key: The key of the new element. Must be a scalar data type.
93
94
        :rtype: sdoc.sdoc1.data_type.DataType.ArrayDataType
95
96
        @todo consider key must be int or str
97
        """
98
        if key not in self._elements:
99
            # Variable is not defined: create a new array.
100
            self._elements[key] = ArrayDataType()
101
102
        else:
103
            # Variable is defined.
104
            element = self._elements[key]
105
            if not isinstance(element, ArrayDataType):
106
                # Variable is defined but not an array: replace the element.
107
                self._elements[key] = ArrayDataType()
108
109
        return self._elements[key]
110
111
    # ------------------------------------------------------------------------------------------------------------------
112
    def add_element(self, key, value):
113
        """
114
        Adds a new elements to this array. If the key holds an element already the element will be replaced.
115
116
        :param sdoc.sdoc1.data_type.DataType.DataType key: The key of the new element. Must be a scalar data type.
117
        :param sdoc.sdoc1.data_type.DataType.DataType value: The value of the new element.
118
119
        :rtype: sdoc.sdoc1.data_type.DataType.DataType
120
121
        @todo consider key must be int or str
122
        """
123
        if not key.is_scalar():
124
            raise DataTypeError("Key '{0!s}' is not a scalar.".format(str(key)))
125
126
        self._elements[key.get_value()] = value.dereference()
127
128
        return self._elements[key.get_value()]
129
130
    # ------------------------------------------------------------------------------------------------------------------
131
    def get_reference(self, name):
132
        """
133
        Returns a reference to an element in this array.
134
135
        :param int|str name: The name of the elements
136
137
        :rtype: sdoc.sdoc1.data_type.DataType.DataType
138
        """
139
        if name not in self._elements:
140
            raise DataTypeError("Identifier '{0!s}' does not have a value.".format(name))
141
142
        return self._elements[name]
143
144
    # ------------------------------------------------------------------------------------------------------------------
145
    def get_value(self):
146
        """
147
        Not implemented.
148
        """
149
        raise NotImplementedError()
150
151
    # ------------------------------------------------------------------------------------------------------------------
152
    def get_type_id(self):
153
        """
154
        Returns the ID of this data type.
155
156
        :rtype: int
157
        """
158
        return DataType.ARRAY
159
160
    # ------------------------------------------------------------------------------------------------------------------
161
    def has_element(self, name):
162
        """
163
        Returns True if this array has a specified element.
164
165
        :param int|str name: The name of the element.
166
167
        :rtype: bool
168
        """
169
        return name in self._elements
170
171
    # ------------------------------------------------------------------------------------------------------------------
172
    def is_constant(self):
173
        """
174
        Returns False always.
175
176
        :rtype: bool
177
        """
178
        return False
179
180
    # ------------------------------------------------------------------------------------------------------------------
181
    def is_defined(self):
182
        """
183
        Returns True always.
184
185
        :rtype: bool
186
        """
187
        return True
188
189
    # ------------------------------------------------------------------------------------------------------------------
190
    def is_scalar(self):
191
        """
192
        Returns False always.
193
194
        :rtype: bool
195
        """
196
        return False
197
198
    # ------------------------------------------------------------------------------------------------------------------
199
    def is_true(self):
200
        """
201
        Returns True if this array holds 1 or more elements. Returns False otherwise.
202
203
        :rtype: bool
204
        """
205
        return len(self._elements) > 0
206
207
# ----------------------------------------------------------------------------------------------------------------------
208