Passed
Pull Request — master (#114)
by Aldo
04:00
created

TraceEntries.load_entries()   F

Complexity

Conditions 25

Size

Total Lines 85
Code Lines 52

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 46
CRAP Score 25.5882

Importance

Changes 0
Metric Value
cc 25
eloc 52
nop 2
dl 0
loc 85
ccs 46
cts 51
cp 0.902
crap 25.5882
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like build.tracing.trace_entries.TraceEntries.load_entries() 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
    Class Entries. Used to evaluate entries provided.
3
"""
4 1
import re
5 1
from napps.amlight.sdntrace import constants
6
7 1
DPID_ADDR = re.compile('([0-9A-Fa-f]{2}[-:]){7}[0-9A-Fa-f]{2}$')
8 1
MAC_ADDR = re.compile('([0-9A-Fa-f]{2}[-:]){5}[0-9A-Fa-f]{2}$')
9 1
IP_ADDR = re.compile("^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}"
10
                     "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$")
11
12
13 1
class TraceEntries(object):
14
    """ Class Entries. Used to evaluate entries provided. """
15
16 1
    def __init__(self):
17 1
        self._dpid = 0
18 1
        self._in_port = 0
19 1
        self._dl_src = 0
20 1
        self._dl_dst = 'ca:fe:ca:fe:ca:fe'
21 1
        self._dl_vlan = 0
22 1
        self._dl_type = 0x800
23 1
        self._dl_vlan_pcp = 0
24 1
        self._nw_src = '1.1.1.1'
25 1
        self._nw_dst = '1.1.1.2'
26 1
        self._nw_tos = 0
27 1
        self._nw_proto = 0
28 1
        self._tp_src = 0
29 1
        self._tp_dst = 0
30 1
        self.timeout = 0.5
31 1
        self.init_entries = dict()  # User request
32
33 1
    @property
34 1
    def dpid(self):
35
        """ Property dpid """
36 1
        return self._dpid
37
38 1
    @dpid.setter
39 1
    def dpid(self, dpid):
40
        """ Validates DPID formats: '1', 'a',  '0000000000000001',
41
        'abcdefabcdefabcd', 'ab:cd:ef:ab:cd:ef:ab:cd'
42
43
        Args:
44
            dpid: entries['trace']['switch']['dpid']
45
        """
46 1
        if not isinstance(dpid, str):
47 1
            raise ValueError("Error: dpid has to be string")
48
49 1
        if 0 < len(dpid) <= 16:  # pylint: disable=len-as-condition
50
            # DPIDs: '1', 'a', '0000000000000001', 'abcdefabcdefabcd'
51 1
            if dpid.isalnum():
52 1
                if not re.search('[g-z]', dpid.lower()):
53 1
                    error_len = False
54
                else:
55
                    error_len = True
56
            else:
57 1
                error_len = True
58
59 1
        elif len(dpid) == 23:
60
            # DPIDs: 'ab:cd:ef:ab:cd:ef:ab:cd'
61
            # Valid chars: 0-9, :, a-f, A-Z
62 1
            if re.search(DPID_ADDR, dpid):
63 1
                error_len = False
64
            else:
65
                error_len = True
66
        else:
67 1
            error_len = True
68
69 1
        if error_len:
70 1
            msg = "Error: dpid allows [a-f], int, and :. Lengths: 1-16 and 23"
71 1
            raise ValueError(msg)
72
73 1
        self._dpid = dpid
74
75 1
    @property
76 1
    def in_port(self):
77
        """ IN_PORT Getter """
78 1
        return self._in_port
79
80 1
    @in_port.setter
81 1
    def in_port(self, in_port):
82
        """ IN_PORT Setter """
83 1
        if not isinstance(in_port, int):
84 1
            raise ValueError("Error: in_port has to be integer")
85
        else:
86 1
            if in_port <= 0 or in_port >= 2**64:
87 1
                raise ValueError("Error: in_port has to be > 0")
88
89 1
        self._in_port = in_port
90
91 1
    @property
92 1
    def dl_src(self):
93
        """ dl_src Getter """
94 1
        return self._dl_src
95
96 1
    @dl_src.setter
97 1
    def dl_src(self, dl_src):
98
        """ dl_src Setter: entries['trace']['eth']['dl_src'].
99
        Validates MAC formats: 'ab:cd:ef:ab:cd:ef'
100
101
        Args:
102
            dl_src: entries['trace']['eth']['dl_src']
103
        """
104
105 1
        if not isinstance(dl_src, str):
106 1
            raise ValueError("Error: dl_src has to be string")
107
108 1
        elif not re.search(MAC_ADDR, dl_src):
109
            # DPIDs: 'ab:cd:ef:ab:cd:ef'
110
            # Valid chars: 0-9, :, a-f, A-Z
111 1
            msg = "Error: dl_src allows char [a-f], int, and :. Lengths: 17"
112 1
            raise ValueError(msg)
113
114 1
        self._dl_src = dl_src
115
116 1
    @property
117 1
    def dl_dst(self):
118
        """ dl_dst Getter """
119 1
        return self._dl_dst
120
121 1
    @dl_dst.setter
122 1
    def dl_dst(self, dl_dst):
123
        """ dl_dst Setter: entries['trace']['eth']['dl_dst'].
124
        Validates MAC formats: 'ab:cd:ef:ab:cd:ef'
125
126
        Args:
127
            dl_dst: entries['trace']['eth']['dl_dst']
128
        """
129
130 1
        if not isinstance(dl_dst, str):
131 1
            raise ValueError("Error: dl_dst has to be string")
132
133 1
        elif not re.search(MAC_ADDR, dl_dst):
134
            # DPIDs: 'ab:cd:ef:ab:cd:ef'
135
            # Valid chars: 0-9, :, a-f, A-Z
136 1
            msg = "Error: dl_dst allows char [a-f], int, and :. Lengths: 17"
137 1
            raise ValueError(msg)
138
139 1
        self._dl_dst = dl_dst
140
141 1
    @property
142 1
    def dl_vlan(self):
143
        """ dl_vlan Getter """
144 1
        return self._dl_vlan
145
146 1
    @dl_vlan.setter
147 1
    def dl_vlan(self, dl_vlan):
148
        """ dl_vlan Setter """
149 1
        if not isinstance(dl_vlan, int):
150 1
            raise ValueError("Error: dl_vlan has to be integer")
151
        else:
152 1
            if not 0 < dl_vlan <= 4095:
153 1
                raise ValueError("Error: dl_vlan has to be between 0 and 4095")
154
155 1
        self._dl_vlan = dl_vlan
156
157 1
    @property
158 1
    def dl_type(self):
159
        """ dl_type Getter """
160 1
        return self._dl_type
161
162 1
    @dl_type.setter
163 1
    def dl_type(self, dl_type):
164
        """ dl_type Setter """
165 1
        if not isinstance(dl_type, int):
166 1
            raise ValueError("Error: dl_type has to be integer")
167
        else:
168 1
            if not 0 < dl_type <= 65535:
169 1
                raise ValueError("Error: dl_type has to be [0-65535]")
170
171 1
        self._dl_type = dl_type
172
173 1
    @property
174 1
    def dl_vlan_pcp(self):
175
        """ dl_vlan_pcp Getter """
176 1
        return self._dl_vlan_pcp
177
178 1
    @dl_vlan_pcp.setter
179 1
    def dl_vlan_pcp(self, dl_vlan_pcp):
180
        """ dl_vlan_pcp Setter """
181 1
        if not isinstance(dl_vlan_pcp, int):
182 1
            raise ValueError("Error: dl_vlan_pcp has to be integer")
183
        else:
184 1
            if not 0 < dl_vlan_pcp <= 7:
185 1
                raise ValueError("Error: dl_vlan_pcp has to be [0-7]")
186
187 1
        self._dl_vlan_pcp = dl_vlan_pcp
188
189 1
    @property
190 1
    def nw_tos(self):
191
        """ nw_tos Getter """
192 1
        return self._nw_tos
193
194 1
    @nw_tos.setter
195 1
    def nw_tos(self, nw_tos):
196
        """ nw_tos Setter """
197 1
        if not isinstance(nw_tos, int):
198 1
            raise ValueError("Error: nw_tos has to be integer")
199
        else:
200 1
            if not 0 < nw_tos <= 7:
201 1
                raise ValueError("Error: nw_tos has to be between 0 and 7")
202
203 1
        self._nw_tos = nw_tos
204
205 1
    @property
206 1
    def nw_src(self):
207
        """ nw_src Getter """
208 1
        return self._nw_src
209
210 1
    @nw_src.setter
211 1
    def nw_src(self, nw_src):
212
        """ nw_src Setter """
213
214 1
        if not isinstance(nw_src, str):
215 1
            raise ValueError("Error: nw_src has to be string")
216
217 1
        elif not re.search(IP_ADDR, nw_src):
218
            # Filters: 0.0.0.1 to 255.255.255.255
219 1
            msg = "Error: nw_src is not a proper IPv4"
220 1
            raise ValueError(msg)
221
222 1
        self._nw_src = nw_src
223
224 1
    @property
225 1
    def nw_dst(self):
226
        """ nw_dst Getter """
227 1
        return self._nw_dst
228
229 1
    @nw_dst.setter
230 1
    def nw_dst(self, nw_dst):
231
        """ nw_dst Setter """
232
233 1
        if not isinstance(nw_dst, str):
234 1
            raise ValueError("Error: nw_dst has to be string")
235
236 1
        elif not re.search(IP_ADDR, nw_dst):
237
            # Filters: 0.0.0.1 to 255.255.255.255
238 1
            msg = "Error: nw_dst is not a proper IPv4"
239 1
            raise ValueError(msg)
240
241 1
        self._nw_dst = nw_dst
242
243 1
    @property
244 1
    def nw_proto(self):
245
        """ nw_proto Getter """
246 1
        return self._nw_proto
247
248 1
    @nw_proto.setter
249 1
    def nw_proto(self, nw_proto):
250
        """ nw_proto Setter """
251 1
        if not isinstance(nw_proto, int):
252
            raise ValueError("Error: nw_proto has to be integer")
253
        else:
254 1
            if not 0 < nw_proto <= 65535:
255
                raise ValueError("Error: nw_proto has to be [0-65535]")
256
257 1
        self._nw_proto = nw_proto
258
259 1
    @property
260 1
    def tp_src(self):
261
        """ tp_src Getter """
262 1
        return self._tp_src
263
264 1
    @tp_src.setter
265 1
    def tp_src(self, tp_src):
266
        """ tp_src Setter """
267 1
        if not isinstance(tp_src, int):
268 1
            raise ValueError("Error: tp_src has to be integer")
269
        else:
270 1
            if not 0 < tp_src <= 65535:
271 1
                raise ValueError("Error: tp_src has to be between 0 and 65535")
272
273 1
        self._tp_src = tp_src
274
275 1
    @property
276 1
    def tp_dst(self):
277
        """ tp_dst Getter """
278 1
        return self._tp_dst
279
280 1
    @tp_dst.setter
281 1
    def tp_dst(self, tp_dst):
282
        """ tp_dst Setter """
283 1
        if not isinstance(tp_dst, int):
284 1
            raise ValueError("Error: tp_dst has to be integer")
285
        else:
286 1
            if not 0 < tp_dst <= 65535:
287 1
                raise ValueError("Error: tp_dst has to be between 0 and 65535")
288
289 1
        self._tp_dst = tp_dst
290
291 1
    def load_entries(self, entries):
292
        """ Import entries provided
293
294
        Args:
295
            entries: user-provided entries
296
        """
297
        # Basic entries['trace']
298 1
        if 'trace' not in entries:
299 1
            raise ValueError("Error: Trace key entry missing")
300 1
        elif not isinstance(entries['trace'], dict):
301
            raise ValueError("Error: Trace has to be dict")
302
303 1
        trace = entries['trace']
304
305
        # Basic entries['trace']['switch']
306 1
        if 'switch' not in trace:
307 1
            raise ValueError("Error: switch key not provided")
308 1
        elif not isinstance(trace['switch'], dict):
309
            raise ValueError("Error: switch has to be dict")
310
311 1
        switch = trace['switch']
312
313 1
        if 'dpid' not in switch:
314 1
            raise ValueError("Error: dpid not provided")
315
        else:
316 1
            self.dpid = switch['dpid']
317
318 1
        if 'in_port' not in switch:
319 1
            raise ValueError("Error: in_port not provided")
320
        else:
321 1
            self.in_port = switch['in_port']
322
323
        # Basic entries['trace']['switch']
324 1
        eth = trace.get("eth", {})
325 1
        if not isinstance(eth, dict):
326 1
            raise ValueError("Error: eth has to be dict")
327
328 1
        if 'dl_vlan' in eth:
329 1
            self.dl_vlan = eth['dl_vlan']
330
331 1
        if 'dl_src' in eth:
332
            self.dl_src = eth['dl_src']
333
334 1
        if 'dl_dst' in eth:
335
            self.dl_dst = eth['dl_dst']
336
337 1
        if 'dl_vlan_pcp' in eth:
338
            self.dl_vlan_pcp = eth['dl_vlan_pcp']
339
340 1
        if 'dl_type' in eth:
341 1
            self.dl_type = eth['dl_type']
342
343
        # Basic entries['trace']['ip']
344 1
        if 'ip' in trace:
345 1
            ip_ = trace['ip']
346
347 1
            if 'nw_src' in ip_:
348 1
                self.nw_src = ip_['nw_src']
349
350 1
            if 'nw_dst' in ip_:
351 1
                self.nw_dst = ip_['nw_dst']
352
353 1
            if 'nw_tos' in ip_:
354 1
                self.nw_tos = ip_['nw_tos']
355
356 1
            if 'nw_proto' in ip_:
357 1
                self.nw_proto = ip_['nw_proto']
358 1
                if ((ip_['nw_proto'] == constants.UDP or ip_['nw_proto'] == constants.TCP)
359
                     and 'tp' not in trace):
360 1
                    raise ValueError("Error: tp not provided")
361
362
        # Basic entries['trace']['ip']
363 1
        if 'tp' in trace:
364 1
            tp_ = trace['tp']
365
366 1
            if 'tp_src' in tp_:
367 1
                self.tp_src = tp_['tp_src']
368
369 1
            if 'tp_dst' in tp_:
370 1
                self.tp_dst = tp_['tp_dst']
371
372 1
        if 'timeout' in trace:
373 1
            self.timeout = trace["timeout"]
374
375
        self.init_entries = entries
376