Skip to content

Commit 51e70ee

Browse files
author
GuangChen2333
committed
feat: check_validation
1 parent 8b8d188 commit 51e70ee

3 files changed

Lines changed: 138 additions & 19 deletions

File tree

README.md

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,32 @@ And you will get:
7373
You can define your own data types by simply inheriting the `BaseType` class:
7474

7575
```python
76+
from typing import Tuple, Type
7677
from structovo import BaseType, Endianness
7778

7879

7980
class MyDataType(BaseType):
80-
def encode(self, endianness: Endianness) -> bytes:
81+
def check_validation(self) -> Tuple[bool, Type]:
82+
# Implement the validation of whether the self.value is valid.
8183
return ...
84+
85+
def encode(self, endianness: Endianness) -> bytes:
86+
# Implement the operation of converting self.value to bytes.
87+
return ...
88+
```
89+
90+
Like this:
91+
92+
```python
93+
from typing import Tuple, Type
94+
from structovo import BaseType, Endianness
95+
96+
97+
class BYTE(BaseType):
98+
def check_validation(self) -> Tuple[bool, Type]:
99+
result = isinstance(self.value, bytes)
100+
return result, bytes
101+
102+
def encode(self, endianness: Endianness) -> bytes:
103+
return self._pack('c', endianness)
82104
```

src/structovo/_packet.py

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from typing import TypeVar, Optional
2-
from ._types import BaseType, FixedString
2+
from ._types import BaseType
33
from ._enums import Endianness
44

55
T = TypeVar('T', bound='Pack')
@@ -14,22 +14,21 @@ def build(cls, endianness: Optional[Endianness] = Endianness.NATIVE) -> bytes:
1414
result_list = []
1515

1616
for key, type_class in anns.items():
17-
if not issubclass(type_class, BaseType) and not type_class is bytes:
18-
raise ValueError(f"{type_class} is not an instance of bytes or structovo.BaseType")
17+
try:
18+
if not issubclass(type_class, BaseType) and not type_class is bytes:
19+
raise ValueError(f"{type_class} is not an instance of bytes or structovo.BaseType")
1920

20-
if type_class is bytes:
21-
result_list.append(data.get(key))
22-
continue
21+
if type_class is bytes:
22+
result_list.append(data.get(key))
23+
continue
2324

24-
elif type_class is FixedString:
25-
try:
26-
value: FixedString = FixedString(data[key][0], data[key][1])
27-
except IndexError:
28-
raise ValueError('Using x: FixedString = (value: bytes, length: int)')
25+
else:
26+
value: BaseType = type_class(data.get(key))
2927

30-
else:
31-
value: BaseType = type_class(data.get(key))
28+
value.raise_if_invalid()
29+
result_list.append(value.encode(endianness))
30+
except Exception as e:
31+
raise ValueError(f"Key {key} raised that {e}, and now it is a {type(data.get(key))}.")
3232

33-
result_list.append(value.encode(endianness))
3433

3534
return b''.join(result_list)

src/structovo/_types.py

Lines changed: 102 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Any
1+
from typing import Any, Tuple, Optional, Type
22
from abc import ABC, abstractmethod
33
from struct import pack
44

@@ -14,6 +14,11 @@ def __new__(cls, value: Any):
1414
def _pack(self, fmt: str, endianness: Endianness) -> bytes:
1515
return pack(f'{endianness.value}{fmt}', self.value)
1616

17+
def raise_if_invalid(self):
18+
result, real = self.check_validation()
19+
if not result:
20+
raise ValueError(f"Invalid value type, it must be a {real}")
21+
1722
@property
1823
def value(self):
1924
return self._value
@@ -22,97 +27,178 @@ def value(self):
2227
def encode(self, endianness: Endianness) -> bytes:
2328
pass
2429

30+
@abstractmethod
31+
def check_validation(self) -> Tuple[bool, Type]:
32+
pass
33+
2534

2635
class PADDING(BaseType):
36+
def check_validation(self) -> Tuple[bool, Type]:
37+
result = self.value is None or isinstance(self.value, int)
38+
return result, Optional[int]
39+
2740
def encode(self, endianness: Endianness) -> bytes:
2841
return b'\x00' * (self.value if self.value else 1)
2942

3043

3144
class BYTE(BaseType):
45+
def check_validation(self) -> Tuple[bool, Type]:
46+
result = isinstance(self.value, bytes)
47+
return result, bytes
48+
3249
def encode(self, endianness: Endianness) -> bytes:
3350
return self._pack('c', endianness)
3451

3552

3653
class CHAR(BaseType):
54+
def check_validation(self) -> Tuple[bool, Type]:
55+
result = isinstance(self.value, int)
56+
return result, int
57+
3758
def encode(self, endianness: Endianness) -> bytes:
3859
return self._pack('b', endianness)
3960

4061

4162
class UCHAR(BaseType):
63+
def check_validation(self) -> Tuple[bool, Type]:
64+
result = isinstance(self.value, int)
65+
return result, int
66+
4267
def encode(self, endianness: Endianness) -> bytes:
4368
return self._pack('B', endianness)
4469

4570

4671
class BOOL(BaseType):
72+
def check_validation(self) -> Tuple[bool, Type]:
73+
result = isinstance(self.value, bool)
74+
return result, bool
75+
4776
def encode(self, endianness: Endianness) -> bytes:
4877
return self._pack('?', endianness)
4978

5079

5180
class SHORT(BaseType):
81+
def check_validation(self) -> Tuple[bool, Type]:
82+
result = isinstance(self.value, int)
83+
return result, int
84+
5285
def encode(self, endianness: Endianness) -> bytes:
5386
return self._pack('h', endianness)
5487

5588

5689
class USHORT(BaseType):
90+
def check_validation(self) -> Tuple[bool, Type]:
91+
result = isinstance(self.value, int)
92+
return result, int
93+
5794
def encode(self, endianness: Endianness) -> bytes:
5895
return self._pack('H', endianness)
5996

6097

6198
class INT(BaseType):
99+
def check_validation(self) -> Tuple[bool, Type]:
100+
result = isinstance(self.value, int)
101+
return result, int
102+
62103
def encode(self, endianness: Endianness) -> bytes:
63104
return self._pack('i', endianness)
64105

65106

66107
class UINT(BaseType):
108+
def check_validation(self) -> Tuple[bool, Type]:
109+
result = isinstance(self.value, int)
110+
return result, int
111+
67112
def encode(self, endianness: Endianness) -> bytes:
68113
return self._pack('I', endianness)
69114

70115

71116
class LONG(BaseType):
117+
def check_validation(self) -> Tuple[bool, Type]:
118+
result = isinstance(self.value, int)
119+
return result, int
120+
72121
def encode(self, endianness: Endianness) -> bytes:
73122
return self._pack('l', endianness)
74123

75124

76125
class ULONG(BaseType):
126+
def check_validation(self) -> Tuple[bool, Type]:
127+
result = isinstance(self.value, int)
128+
return result, int
129+
77130
def encode(self, endianness: Endianness) -> bytes:
78131
return self._pack('L', endianness)
79132

80133

81134
class LONGLONG(BaseType):
135+
def check_validation(self) -> Tuple[bool, Type]:
136+
result = isinstance(self.value, int)
137+
return result, int
138+
82139
def encode(self, endianness: Endianness) -> bytes:
83140
return self._pack('q', endianness)
84141

85142

86143
class ULONGLONG(BaseType):
144+
def check_validation(self) -> Tuple[bool, Type]:
145+
result = isinstance(self.value, int)
146+
return result, int
147+
87148
def encode(self, endianness: Endianness) -> bytes:
88149
return self._pack('Q', endianness)
89150

90151

91152
class SSIZET(BaseType):
153+
def check_validation(self) -> Tuple[bool, Type]:
154+
result = isinstance(self.value, int)
155+
return result, int
156+
92157
def encode(self, endianness: Endianness) -> bytes:
93158
return self._pack('n', endianness)
94159

95160

96161
class SIZET(BaseType):
162+
def check_validation(self) -> Tuple[bool, Type]:
163+
result = isinstance(self.value, int)
164+
return result, int
165+
97166
def encode(self, endianness: Endianness) -> bytes:
98167
return self._pack('N', endianness)
99168

100169

101170
class FLOAT(BaseType):
171+
def check_validation(self) -> Tuple[bool, Type]:
172+
result = isinstance(self.value, float)
173+
return result, float
174+
102175
def encode(self, endianness: Endianness) -> bytes:
103176
return self._pack('f', endianness)
104177

105178

106179
class DOUBLE(BaseType):
180+
def check_validation(self) -> Tuple[bool, Type]:
181+
result = isinstance(self.value, float)
182+
return result, float
183+
107184
def encode(self, endianness: Endianness) -> bytes:
108185
return self._pack('d', endianness)
109186

110187

111188
class FixedString(BaseType):
112-
def __new__(cls, value: bytes, length: int):
189+
def check_validation(self):
190+
return (
191+
not isinstance(self.value, tuple)
192+
or not isinstance(self.value[0], bytes)
193+
or not isinstance(self.value[1], int)
194+
), Tuple[bytes, int]
195+
196+
def __new__(cls, value: Tuple[bytes, int]):
113197
instance = super().__new__(cls, value)
114-
instance._value = value
115-
instance._length = length
198+
199+
instance._value = value[0]
200+
instance._length = value[1]
201+
116202
return instance
117203

118204
@property
@@ -124,6 +210,10 @@ def encode(self, endianness: Endianness) -> bytes:
124210

125211

126212
class LengthPrefixedString(BaseType):
213+
def check_validation(self) -> Tuple[bool, Type]:
214+
result = isinstance(self.value, bytes)
215+
return result, bytes
216+
127217
def encode(self, endianness: Endianness) -> bytes:
128218
length = len(self.value)
129219
if length > 255:
@@ -132,10 +222,18 @@ def encode(self, endianness: Endianness) -> bytes:
132222

133223

134224
class BINARY16(BaseType):
225+
def check_validation(self) -> Tuple[bool, Type]:
226+
result = isinstance(self.value, float)
227+
return result, float
228+
135229
def encode(self, endianness: Endianness) -> bytes:
136230
return self._pack('e', endianness)
137231

138232

139233
class UnsignedPointer(BaseType):
234+
def check_validation(self) -> Tuple[bool, Type]:
235+
result = isinstance(self.value, int)
236+
return result, int
237+
140238
def encode(self, endianness: Endianness) -> bytes:
141239
return self._pack('P', endianness)

0 commit comments

Comments
 (0)