Completed
Push — master ( 09e12b...15e96c )
by Aaron
07:32
created

ElementBitField   A

Complexity

Total Complexity 11

Size/Duplication

Total Lines 96
Duplicated Lines 100 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 96
loc 96
rs 10
wmc 11

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __init__() 20 20 1
A pack() 11 11 2
A update() 10 10 3
A valid() 13 13 1
A unpack() 19 19 2
A make() 3 3 1
A validate() 8 8 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
"""StarStruct element class."""
2
3
import struct
4
import re
5
6
from starstruct.element import register, Element
7
from starstruct.modes import Mode
8
from starstruct.bitfield import BitField
9
10
11 View Code Duplication
@register
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
12
class ElementBitField(Element):
13
    """
14
    The bitfield StarStruct element class.
15
    """
16
17
    def __init__(self, field, mode=Mode.Native, alignment=1):
18
        """Initialize a StarStruct element object."""
19
20
        # All of the type checks have already been performed by the class
21
        # factory
22
        self.name = field[0]
23
        self.ref = field[2]
24
25
        self._mode = mode
26
        self._alignment = alignment
27
28
        # Validate that the format specifiers are valid struct formats, this
29
        # doesn't have to be done now because the format will be checked when
30
        # any struct functions are called, but it's better to inform the user of
31
        # any errors earlier.
32
        # The easiest way to perform this check is to create a "Struct" class
33
        # instance, this will also increase the efficiency of all struct related
34
        # functions called.
35
        self.format = mode.value + field[1]
36
        self._struct = struct.Struct(self.format)
37
38
    @staticmethod
39
    def valid(field):
40
        """
41
        Validation function to determine if a field tuple represents a valid
42
        enum element type.
43
44
        The basics have already been validated by the Element factory class,
45
        validate that the struct format is a valid numeric value.
46
        """
47
        return (len(field) == 3 and
48
                isinstance(field[1], str) and
49
                re.match(r'\d*[cbB?hHiIlLqQnNfdP]', field[1]) and
50
                isinstance(field[2], BitField))
51
52
    def validate(self, msg):
53
        """
54
        Ensure that the supplied message contains the required information for
55
        this element object to operate.
56
57
        The "enum" element requires no further validation.
58
        """
59
        pass
60
61
    def update(self, mode=None, alignment=None):
62
        """change the mode of the struct format"""
63
        if alignment:
64
            self._alignment = alignment
65
66
        if mode:
67
            self._mode = mode
68
            self.format = mode.value + self.format[1:]
69
            # recreate the struct with the new format
70
            self._struct = struct.Struct(self.format)
71
72
    def pack(self, msg):
73
        """Pack the provided values into the supplied buffer."""
74
        # Turn the enum value list into a single number and pack it into the
75
        # specified format
76
        data = self._struct.pack(self.ref.pack(msg[self.name]))
77
78
        # If the data does not meet the alignment, add some padding
79
        missing_bytes = len(data) % self._alignment
80
        if missing_bytes:
81
            data += b'\x00' * missing_bytes
82
        return data
83
84
    def unpack(self, msg, buf):
85
        """Unpack data from the supplied buffer using the initialized format."""
86
        ret = self._struct.unpack_from(buf, 0)
87
88
        # Remember to remove any alignment-based padding
89
        extra_bytes = self._alignment - 1 - (struct.calcsize(self.format) %
90
                                             self._alignment)
91
        unused = buf[struct.calcsize(self.format) + extra_bytes:]
92
93
        # Convert the returned value to the referenced BitField type
94
        try:
95
            member = self.ref.unpack(ret[0])
96
        except ValueError as e:
97
            raise ValueError(
98
                'Value: {0} was not valid for {1}\n\twith msg: {2},\n\tbuf: {3}'.format(
99
                    ret[0], self.ref, msg, buf
100
                )).with_traceback(e.__traceback__)
101
102
        return (member, unused)
103
104
    def make(self, msg):
105
        """Return the "transformed" value for this element"""
106
        return self.ref.make(msg[self.name])
107