Issues (43)

starstruct/elementbase.py (1 issue)

1
"""
2
The basic StarStruct element class.
3
"""
4
5 1
import re
6 1
import struct
7 1
from typing import Optional
0 ignored issues
show
The import typing could not be resolved.

This can be caused by one of the following:

1. Missing Dependencies

This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.

# .scrutinizer.yml
before_commands:
    - sudo pip install abc # Python2
    - sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use the command for the correct version.

2. Missing __init__.py files

This error could also result from missing __init__.py files in your module folders. Make sure that you place one file in each sub-folder.

Loading history...
8
9 1
from starstruct.element import register, Element
10 1
from starstruct.modes import Mode
11
12
13 1
@register
14 1
class ElementBase(Element):
15
    """
16
    Initialize a StarStruct element object.
17
18
    :param field: The fields passed into the constructor of the element
19
    :param mode: The mode for the Element
20
    :param alignment: The number of bytes to align objects with.
21
    """
22
23 1
    def __init__(self, field: tuple, mode: Optional[Mode]=Mode.Native, alignment: Optional[int]=1):
24
25
        # All of the type checks have already been performed by the class
26
        # factory
27
        self.name = field[0]
28
29
        # The ref attribute is required for all elements, but the base element
30
        # type does not have one
31
        self.ref = None
32
33
        self._mode = mode
34
        self._alignment = alignment
35
36
        # Validate that the format specifiers are valid struct formats, this
37
        # doesn't have to be done now because the format will be checked when
38
        # any struct functions are called, but it's better to inform the user of
39
        # any errors earlier.
40
        # The easiest way to perform this check is to create a "Struct" class
41
        # instance, this will also increase the efficiency of all struct related
42
        # functions called.
43
        self.format = mode.value + field[1]
44
        self._struct = struct.Struct(self.format)
45
46 1
    @staticmethod
47 1
    def valid(field: tuple) -> bool:
48
        """
49
        Validation function to determine if a field tuple represents a valid
50
        base element type.
51
52
        The basics have already been validated by the Element factory class,
53
        validate the specific struct format now.
54
55
        Basic elements don't support numeric modifiers, since that requires a
56
        list of values.
57
        """
58 1
        return len(field) == 2 \
59
            and isinstance(field[1], str) \
60
            and re.match(r'[?nNfdP]', field[1])
61
62 1
    def validate(self, msg):
63
        """
64
        Ensure that the supplied message contains the required information for
65
        this element object to operate.
66
67
        The "base" element requires no further validation.
68
        """
69
        pass
70
71 1
    def update(self, mode=None, alignment=None):
72
        """change the mode of the struct format"""
73
        if alignment:
74
            self._alignment = alignment
75
76
        if mode:
77
            self._mode = mode
78
            self.format = mode.value + self.format[1:]
79
            # recreate the struct with the new format
80
            self._struct = struct.Struct(self.format)
81
82 1
    def pack(self, msg):
83
        """Pack the provided values into the supplied buffer."""
84
        data = self._struct.pack(msg[self.name])
85
86
        # If the data does not meet the alignment, add some padding
87
        missing_bytes = len(data) % self._alignment
88
        if missing_bytes:
89
            data += b'\x00' * missing_bytes
90
        return data
91
92 1
    def unpack(self, msg, buf):
93
        """Unpack data from the supplied buffer using the initialized format."""
94
        ret = self._struct.unpack_from(buf, 0)
95
96
        # Remember to remove any alignment-based padding
97
        extra_bytes = self._alignment - 1 - (struct.calcsize(self.format) %
98
                                             self._alignment)
99
        unused = buf[struct.calcsize(self.format) + extra_bytes:]
100
        return (ret[0], unused)
101
102 1
    def make(self, msg):
103
        """Return the "transformed" value for this element"""
104
        return msg[self.name]
105