structo 0.0.5__tar.gz → 0.0.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {structo-0.0.5 → structo-0.0.7}/PKG-INFO +1 -1
- {structo-0.0.5 → structo-0.0.7}/structo/__init__.py +2 -2
- {structo-0.0.5 → structo-0.0.7}/structo/object.py +3 -2
- {structo-0.0.5 → structo-0.0.7}/structo/packed.py +2 -2
- {structo-0.0.5 → structo-0.0.7}/structo/serialise.py +13 -3
- {structo-0.0.5 → structo-0.0.7}/structo/serializer.py +1 -1
- {structo-0.0.5 → structo-0.0.7}/structo/types/array.py +7 -7
- {structo-0.0.5 → structo-0.0.7}/structo/types/list.py +5 -15
- structo-0.0.7/tests/test_array.py +20 -0
- structo-0.0.7/tests/test_list.py +17 -0
- structo-0.0.7/tests/test_object.py +55 -0
- structo-0.0.5/tests/test_array.py +0 -7
- {structo-0.0.5 → structo-0.0.7}/.gitignore +0 -0
- {structo-0.0.5 → structo-0.0.7}/LICENSE +0 -0
- {structo-0.0.5 → structo-0.0.7}/README.md +0 -0
- {structo-0.0.5 → structo-0.0.7}/examples/custom_serializer.py +0 -0
- {structo-0.0.5 → structo-0.0.7}/examples/iterable_serializer.py +0 -0
- {structo-0.0.5 → structo-0.0.7}/examples/wav.py +0 -0
- {structo-0.0.5 → structo-0.0.7}/pyproject.toml +0 -0
- {structo-0.0.5 → structo-0.0.7}/pytest.ini +0 -0
- {structo-0.0.5 → structo-0.0.7}/structo/types/__init__.py +0 -0
- {structo-0.0.5 → structo-0.0.7}/structo/types/blob.py +0 -0
- {structo-0.0.5 → structo-0.0.7}/structo/types/buffer.py +0 -0
- {structo-0.0.5 → structo-0.0.7}/structo/types/literal.py +0 -0
- {structo-0.0.5 → structo-0.0.7}/structo/types/object.py +0 -0
- {structo-0.0.5 → structo-0.0.7}/structo/types/packed.py +0 -0
- {structo-0.0.5 → structo-0.0.7}/structo/types/primatives.py +0 -0
- {structo-0.0.5 → structo-0.0.7}/structo/types/string.py +0 -0
- {structo-0.0.5 → structo-0.0.7}/structo/utils.py +0 -0
- {structo-0.0.5 → structo-0.0.7}/tests/test_packed.py +0 -0
- {structo-0.0.5 → structo-0.0.7}/tests/test_primatives.py +0 -0
- {structo-0.0.5 → structo-0.0.7}/tests/test_size.py +0 -0
- {structo-0.0.5 → structo-0.0.7}/tests/utils.py +0 -0
- {structo-0.0.5 → structo-0.0.7}/uv.lock +0 -0
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
Structify
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
__version__ = "0.0.
|
|
5
|
+
__version__ = "0.0.7"
|
|
6
6
|
|
|
7
|
-
from .serializer import Serializer,
|
|
7
|
+
from .serializer import Serializer, Serializable
|
|
8
8
|
from .serialise import get_serializer
|
|
9
9
|
from .object import SerializableObject
|
|
10
10
|
from .packed import PackedInts, PackedInt
|
|
@@ -3,7 +3,7 @@ import annotationlib
|
|
|
3
3
|
import typing as t
|
|
4
4
|
from dataclasses import dataclass
|
|
5
5
|
|
|
6
|
-
from .serializer import
|
|
6
|
+
from .serializer import Serializable, Serializer
|
|
7
7
|
from .serialise import get_serializer
|
|
8
8
|
|
|
9
9
|
|
|
@@ -32,10 +32,11 @@ class SerializableObjectMeta(type):
|
|
|
32
32
|
|
|
33
33
|
# This is very messed up since we
|
|
34
34
|
@t.dataclass_transform()
|
|
35
|
-
class SerializableObject(
|
|
35
|
+
class SerializableObject(Serializable, metaclass=SerializableObjectMeta):
|
|
36
36
|
@classmethod
|
|
37
37
|
def serializer(cls) -> Serializer[t.Self]:
|
|
38
38
|
from .types import ObjectSerializer
|
|
39
|
+
|
|
39
40
|
return ObjectSerializer(cls)
|
|
40
41
|
|
|
41
42
|
@classmethod
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from .serializer import
|
|
1
|
+
from .serializer import Serializable, Serializer
|
|
2
2
|
import typing as t
|
|
3
3
|
import io
|
|
4
4
|
from typing import Annotated
|
|
@@ -38,7 +38,7 @@ class PackedIntsMeta(type):
|
|
|
38
38
|
|
|
39
39
|
# This is very messed up since we
|
|
40
40
|
@t.dataclass_transform()
|
|
41
|
-
class PackedInts(
|
|
41
|
+
class PackedInts(Serializable, metaclass=PackedIntsMeta):
|
|
42
42
|
_bits: dict[str, PackedInt]
|
|
43
43
|
|
|
44
44
|
@classmethod
|
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
import typing as t
|
|
2
|
-
from .serializer import Serializer,
|
|
2
|
+
from .serializer import Serializer, Serializable
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
def
|
|
5
|
+
def to_serializer[T](format: type[T] | Serializer[T]) -> Serializer[T]:
|
|
6
|
+
if isinstance(format, Serializer):
|
|
7
|
+
return format
|
|
8
|
+
|
|
9
|
+
if isinstance(format, type) and issubclass(format, Serializable):
|
|
10
|
+
return format.serializer()
|
|
11
|
+
|
|
12
|
+
raise AssertionError(f"Invalid value_type: {format}")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def get_serializer(format: type | Serializer) -> Serializer:
|
|
6
16
|
if t.get_origin(format) is t.Annotated:
|
|
7
17
|
args = t.get_args(format)
|
|
8
18
|
serializers = [arg for arg in args if isinstance(arg, Serializer)]
|
|
@@ -12,7 +22,7 @@ def get_serializer(format: type) -> Serializer:
|
|
|
12
22
|
|
|
13
23
|
return serializer
|
|
14
24
|
|
|
15
|
-
if
|
|
25
|
+
if issubclass(format, Serializable):
|
|
16
26
|
return format.serializer()
|
|
17
27
|
|
|
18
28
|
# Nicely formatted errors:
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
+
from ..serialise import to_serializer
|
|
1
2
|
from ..serializer import Serializer
|
|
2
3
|
|
|
3
4
|
|
|
4
5
|
class Array[T](Serializer[list[T]]):
|
|
5
6
|
length: int
|
|
6
|
-
|
|
7
|
+
value_type: Serializer[T]
|
|
7
8
|
|
|
8
|
-
def __init__(self, length: int,
|
|
9
|
+
def __init__(self, length: int, value_type: Serializer[T] | type[T]) -> None:
|
|
9
10
|
assert length > 0, "Array must be longer than 0"
|
|
10
11
|
self.length = length
|
|
11
|
-
self.
|
|
12
|
+
self.value_type = to_serializer(value_type)
|
|
12
13
|
|
|
13
14
|
def write(self, buf, value):
|
|
14
15
|
assert (
|
|
@@ -16,19 +17,18 @@ class Array[T](Serializer[list[T]]):
|
|
|
16
17
|
), f"expected array with {self.length} length, receieved {len(value)}"
|
|
17
18
|
|
|
18
19
|
for item in value:
|
|
19
|
-
self.
|
|
20
|
+
self.value_type.write(buf, item)
|
|
20
21
|
|
|
21
22
|
def read(self, buf):
|
|
22
23
|
items = []
|
|
23
24
|
for _ in range(self.length):
|
|
24
|
-
items.append(self.
|
|
25
|
+
items.append(self.value_type.read(buf))
|
|
25
26
|
|
|
26
27
|
return items
|
|
27
28
|
|
|
28
29
|
def sizeof(self):
|
|
29
|
-
element_length = self.
|
|
30
|
+
element_length = self.value_type.sizeof()
|
|
30
31
|
if element_length is None:
|
|
31
32
|
return None
|
|
32
33
|
else:
|
|
33
34
|
return element_length * self.length
|
|
34
|
-
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import typing as t
|
|
2
|
+
from ..serialise import to_serializer
|
|
2
3
|
from ..serializer import Serializer
|
|
3
|
-
from ..object import
|
|
4
|
+
from ..object import Serializable
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
class List[T](Serializer[list[T]]):
|
|
@@ -9,22 +10,11 @@ class List[T](Serializer[list[T]]):
|
|
|
9
10
|
length_type: Serializer[int]
|
|
10
11
|
value_type: Serializer
|
|
11
12
|
|
|
12
|
-
@t.overload
|
|
13
13
|
def __init__(
|
|
14
|
-
self, length_type: Serializer[int], value_type: Serializer[T]
|
|
15
|
-
) -> None:
|
|
16
|
-
|
|
17
|
-
@t.overload
|
|
18
|
-
def __init__(
|
|
19
|
-
self, length_type: Serializer[int], value_type: T
|
|
20
|
-
) -> None: ...
|
|
21
|
-
|
|
22
|
-
def __init__(self, length_type: Serializer[int], value_type: Serializer | SerializableObject) -> None:
|
|
14
|
+
self, length_type: Serializer[int], value_type: Serializer[T] | type[T]
|
|
15
|
+
) -> None:
|
|
23
16
|
self.length_type = length_type
|
|
24
|
-
|
|
25
|
-
self.value_type = value_type.serializer()
|
|
26
|
-
else:
|
|
27
|
-
self.value_type = value_type
|
|
17
|
+
self.value_type = to_serializer(value_type)
|
|
28
18
|
|
|
29
19
|
def write(self, buf, value):
|
|
30
20
|
length = len(value)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import typing as t
|
|
2
|
+
import structo as st
|
|
3
|
+
from utils import test
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@test("Array: sizeof")
|
|
7
|
+
def _():
|
|
8
|
+
assert st.Array(4, st.int8).sizeof() == 4
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@test("Array: nested bits")
|
|
12
|
+
def _():
|
|
13
|
+
class Bits(st.PackedInts):
|
|
14
|
+
a: t.Annotated[int, st.PackedInt(bits=2)]
|
|
15
|
+
|
|
16
|
+
class Object(st.SerializableObject):
|
|
17
|
+
bits: t.Annotated[list[Bits], st.Array(2, Bits)]
|
|
18
|
+
|
|
19
|
+
obj = Object(bits=[Bits(1), Bits(2)])
|
|
20
|
+
assert obj == Object.from_bytes(obj.to_bytes())
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from utils import test
|
|
2
|
+
import typing as t
|
|
3
|
+
|
|
4
|
+
import structo as st
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@test("List: nested bits")
|
|
8
|
+
def _():
|
|
9
|
+
class Bits(st.PackedInts):
|
|
10
|
+
a: t.Annotated[int, st.PackedInt(bits=2)]
|
|
11
|
+
|
|
12
|
+
class Object(st.SerializableObject):
|
|
13
|
+
foo: t.Annotated[list[Bits], st.List(st.uint8, Bits)]
|
|
14
|
+
|
|
15
|
+
obj = Object(foo=[Bits(a=1)])
|
|
16
|
+
assert obj == Object.from_bytes(obj.to_bytes())
|
|
17
|
+
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
from utils import test
|
|
2
|
+
import typing as t
|
|
3
|
+
|
|
4
|
+
import structo as st
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@test("SerialiableObject: object")
|
|
8
|
+
def _():
|
|
9
|
+
class Foo(st.SerializableObject):
|
|
10
|
+
a: t.Annotated[int, st.uint8]
|
|
11
|
+
|
|
12
|
+
obj = Foo(a=1)
|
|
13
|
+
assert obj == Foo.from_bytes(obj.to_bytes())
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@test("SerialiableObject: multiple attributes")
|
|
17
|
+
def _():
|
|
18
|
+
class Foo(st.SerializableObject):
|
|
19
|
+
a: t.Annotated[int, st.uint8]
|
|
20
|
+
b: t.Annotated[int, st.uint16_BE]
|
|
21
|
+
|
|
22
|
+
obj = Foo(a=1, b=256)
|
|
23
|
+
assert obj == Foo.from_bytes(obj.to_bytes())
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@test("SerialiableObject: sizeof")
|
|
27
|
+
def _():
|
|
28
|
+
|
|
29
|
+
class Foo(st.SerializableObject):
|
|
30
|
+
a: t.Annotated[int, st.uint8]
|
|
31
|
+
b: t.Annotated[str, st.uint8]
|
|
32
|
+
|
|
33
|
+
assert Foo.sizeof() == 2
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@test("SerialiableObject: sizeof unknowable")
|
|
37
|
+
def _():
|
|
38
|
+
class Foo(st.SerializableObject):
|
|
39
|
+
a: t.Annotated[int, st.uint8]
|
|
40
|
+
b: t.Annotated[str, st.String(st.uint8)]
|
|
41
|
+
|
|
42
|
+
assert Foo.sizeof() is None
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@test("SerialiableObject: nested object")
|
|
46
|
+
def _():
|
|
47
|
+
class Foo(st.SerializableObject):
|
|
48
|
+
a: t.Annotated[int, st.uint8]
|
|
49
|
+
|
|
50
|
+
class Bar(st.SerializableObject):
|
|
51
|
+
foo: Foo
|
|
52
|
+
|
|
53
|
+
obj = Bar(foo=Foo(1))
|
|
54
|
+
assert obj == Bar.from_bytes(obj.to_bytes())
|
|
55
|
+
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|