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
|
|||
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 |
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.
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.