- renamed "TStructField" to "field" and "TUnionField" to "ufield". This makes the dataclass definitions shorter and more readable.

- removed "Opt" and "List" because they are not necessary any more, because covariant is now included for ParsedType.
- added test with typing.List as field
- fix: changed dict to typing.Dict
This commit is contained in:
Tim Rid 2021-03-16 18:51:04 +01:00
parent 084c39a1ff
commit ae440407e9
9 changed files with 72 additions and 66 deletions

View file

@ -74,11 +74,11 @@ class Orientation(cst.EnumBase):
@dataclasses.dataclass
class Image(cst.TContainerBase):
signature: cst.Opt[bytes] = cst.TStructField(cs.Const(b"BMP"))
orientation: Orientation = cst.TStructField(cst.TEnum(cs.Int8ub, Orientation))
width: int = cst.TStructField(cs.Int8ub)
height: int = cst.TStructField(cs.Int8ub)
pixels: cst.List[int] = cst.TStructField(cs.Array(cs.this.width * cs.this.height, cs.Byte))
signature: cst.Opt[bytes] = cst.sfield(cs.Const(b"BMP"))
orientation: Orientation = cst.sfield(cst.TEnum(cs.Int8ub, Orientation))
width: int = cst.sfield(cs.Int8ub)
height: int = cst.sfield(cs.Int8ub)
pixels: cst.List[int] = cst.sfield(cs.Array(cs.this.width * cs.this.height, cs.Byte))
format = cst.TStruct(Image)
obj = Image(orientation=Orientation.VERTICAL, width=3, height=2, pixels=[7, 8, 9, 11, 12, 13])

View file

@ -1049,7 +1049,7 @@ class Lazy(
]
): ...
class LazyContainer(t.Generic[ContainerType], dict[str, ContainerType]):
class LazyContainer(t.Generic[ContainerType], t.Dict[str, ContainerType]):
def __getattr__(self, name: str) -> ContainerType: ...
def __getitem__(self, index: t.Union[str, int]) -> ContainerType: ...
def keys(self) -> t.Iterator[str]: ...

View file

@ -7,6 +7,6 @@ class HexDisplayedBytes(bytes): ...
K = t.TypeVar("K")
V = t.TypeVar("V")
class HexDisplayedDict(dict[K, V]): ...
class HexDisplayedDict(t.Dict[K, V]): ...
class HexDumpDisplayedBytes(bytes): ...
class HexDumpDisplayedDict(dict[K, V]): ...
class HexDumpDisplayedDict(t.Dict[K, V]): ...

View file

@ -7,15 +7,16 @@ from .generic_wrapper import (
PathType,
)
from .tenum import EnumBase, FlagsEnumBase, TEnum, TFlagsEnum
from .tstruct import TBitStruct, TStruct, TStructField, TContainerBase
from .tunion import TUnion, TUnionField
from .helper import List, Opt
from .tstruct import TBitStruct, TStruct, sfield, TStructField, TContainerBase
from .tunion import TUnion, ufield, TUnionField
__all__ = [
"sfield",
"TStructField",
"TStruct",
"TBitStruct",
"TEnum",
"ufield",
"TUnionField",
"TUnion",
"EnumBase",
@ -27,7 +28,6 @@ __all__ = [
"ConstantOrContextLambda",
"PathType",
"TFlagsEnum",
"FlagsEnumBase",
"Opt",
"List"
"FlagsEnumBase"
]

View file

@ -1,9 +0,0 @@
import typing as t
from .generic_wrapper import ListContainer
OptType = t.TypeVar("OptType")
ListType = t.TypeVar("ListType")
Opt = t.Optional[OptType]
List = t.Union[ListContainer[ListType], t.List[ListType]]

View file

@ -50,7 +50,7 @@ class TContainerBase(_TContainerBase):
self.move_to_end(field.name)
def TStructField(
def sfield(
subcon: Construct[ParsedType, t.Any],
doc: t.Optional[str] = None,
parsed: t.Optional[t.Callable[[t.Any, Context], None]] = None,
@ -76,6 +76,7 @@ def TStructField(
return field # type: ignore
TStructField = sfield # also support legacy name
ContainerType = t.TypeVar("ContainerType", bound=TContainerBase)

View file

@ -1,5 +1,4 @@
import dataclasses
import enum
import textwrap
import typing as t
@ -10,7 +9,7 @@ from .generic_wrapper import *
DataclassType = t.TypeVar("DataclassType")
def TUnionField(
def ufield(
subcon: Construct[ParsedType, t.Any],
doc: t.Optional[str] = None,
parsed: t.Optional[t.Callable[[t.Any, "cs.Context"], None]] = None,
@ -43,6 +42,7 @@ def TUnionField(
return field # type: ignore
TUnionField = ufield # also support legacy name
class TUnion(Adapter[t.Any, t.Any, DataclassType, DataclassType]):
pass # TODO

View file

@ -49,6 +49,7 @@ def common(format, datasample, objsample, sizesample=SizeofError, **kw):
def setattrs(obj, **kwargs):
""" Set multiple named values of an object """
for name, value in kwargs.items():
setattr(obj, name, value)
return obj

View file

@ -6,6 +6,7 @@ import enum
import construct as cs
import construct_typed as cst
import pytest
import typing as t
from .declarativeunittest import common, raises, setattrs
@ -13,13 +14,13 @@ from .declarativeunittest import common, raises, setattrs
def test_tcontainer_compare_with_dataclass() -> None:
@dataclasses.dataclass
class TestContainer:
a: cst.Opt[int] = cst.TStructField(cs.Const(1, cs.Byte))
b: int = cst.TStructField(cs.Int8ub)
a: t.Optional[int] = cst.sfield(cs.Const(1, cs.Byte))
b: int = cst.sfield(cs.Int8ub)
@dataclasses.dataclass
class TestTContainer(cst.TContainerBase):
a: cst.Opt[int] = cst.TStructField(cs.Const(1, cs.Byte))
b: int = cst.TStructField(cs.Int8ub)
a: t.Optional[int] = cst.sfield(cs.Const(1, cs.Byte))
b: int = cst.sfield(cs.Int8ub)
datacls = TestContainer(b=1)
tcontainer = TestTContainer(b=1)
@ -66,9 +67,9 @@ def test_tcontainer_compare_with_dataclass() -> None:
def test_tcontainer_order() -> None:
@dataclasses.dataclass
class Image(cst.TContainerBase):
signature: cst.Opt[bytes] = cst.TStructField(cs.Const(b"BMP"))
width: int = cst.TStructField(cs.Int8ub)
height: int = cst.TStructField(cs.Int8ub)
signature: t.Optional[bytes] = cst.sfield(cs.Const(b"BMP"))
width: int = cst.sfield(cs.Int8ub)
height: int = cst.sfield(cs.Int8ub)
format = cst.TStruct(Image)
obj = Image(width=3, height=2)
@ -85,8 +86,8 @@ def test_tcontainer_order() -> None:
def test_tstruct() -> None:
@dataclasses.dataclass
class TestContainer(cst.TContainerBase):
a: int = cst.TStructField(cs.Int16ub)
b: int = cst.TStructField(cs.Int8ub)
a: int = cst.sfield(cs.Int16ub)
b: int = cst.sfield(cs.Int8ub)
common(cst.TStruct(TestContainer), b"\x00\x01\x02", TestContainer(a=1, b=2), 3)
@ -101,8 +102,8 @@ def test_tstruct() -> None:
def test_tstruct_swapped() -> None:
@dataclasses.dataclass
class TestContainer(cst.TContainerBase):
a: int = cst.TStructField(cs.Int16ub)
b: int = cst.TStructField(cs.Int8ub)
a: int = cst.sfield(cs.Int16ub)
b: int = cst.sfield(cs.Int8ub)
common(
cst.TStruct(TestContainer, swapped=True),
@ -118,8 +119,8 @@ def test_tstruct_swapped() -> None:
def test_tstruct_add_offsets() -> None:
@dataclasses.dataclass
class TestContainer(cst.TContainerBase):
a: int = cst.TStructField(cs.Int16ub)
b: int = cst.TStructField(cs.Int8ub)
a: int = cst.sfield(cs.Int16ub)
b: int = cst.sfield(cs.Int8ub)
common(
cst.TStruct(TestContainer, add_offsets=True),
@ -140,9 +141,9 @@ def test_tstruct_nested() -> None:
class TestContainer(cst.TContainerBase):
@dataclasses.dataclass
class InnerDataclass(cst.TContainerBase):
b: int = cst.TStructField(cs.Byte)
b: int = cst.sfield(cs.Byte)
a: InnerDataclass = cst.TStructField(cst.TStruct(InnerDataclass))
a: InnerDataclass = cst.sfield(cst.TStruct(InnerDataclass))
common(
cst.TStruct(TestContainer),
@ -155,9 +156,9 @@ def test_tstruct_nested() -> None:
def test_tstruct_default_field() -> None:
@dataclasses.dataclass
class Image(cst.TContainerBase):
width: int = cst.TStructField(cs.Int8ub)
height: int = cst.TStructField(cs.Int8ub)
pixels: cst.Opt[bytes] = cst.TStructField(
width: int = cst.sfield(cs.Int8ub)
height: int = cst.sfield(cs.Int8ub)
pixels: t.Optional[bytes] = cst.sfield(
cs.Default(
cs.Bytes(cs.this.width * cs.this.height),
lambda ctx: bytes(ctx.width * ctx.height),
@ -175,7 +176,7 @@ def test_tstruct_default_field() -> None:
def test_tstruct_const_field() -> None:
@dataclasses.dataclass
class TestContainer(cst.TContainerBase):
const_field: cst.Opt[bytes] = cst.TStructField(cs.Const(b"\x00"))
const_field: t.Optional[bytes] = cst.sfield(cs.Const(b"\x00"))
common(
cst.TStruct(TestContainer),
@ -192,14 +193,26 @@ def test_tstruct_const_field() -> None:
== cs.ConstError
)
def test_tstruct_array_field() -> None:
@dataclasses.dataclass
class TestContainer(cst.TContainerBase):
array_field: t.List[int] = cst.sfield(cs.Array(5, cs.Int8ub))
common(
cst.TStruct(TestContainer),
bytes(5),
TestContainer(array_field=[0,0,0,0,0]),
5,
)
def test_tstruct_anonymus_fields_1() -> None:
@dataclasses.dataclass
class TestContainer(cst.TContainerBase):
_1: cst.Opt[bytes] = cst.TStructField(cs.Const(b"\x00"))
_2: None = cst.TStructField(cs.Padding(1))
_3: None = cst.TStructField(cs.Pass)
_4: None = cst.TStructField(cs.Terminated)
_1: t.Optional[bytes] = cst.sfield(cs.Const(b"\x00"))
_2: None = cst.sfield(cs.Padding(1))
_3: None = cst.sfield(cs.Pass)
_4: None = cst.sfield(cs.Terminated)
common(
cst.TStruct(TestContainer),
@ -212,10 +225,10 @@ def test_tstruct_anonymus_fields_1() -> None:
def test_tstruct_anonymus_fields_2() -> None:
@dataclasses.dataclass
class TestContainer(cst.TContainerBase):
_1: int = cst.TStructField(cs.Computed(7))
_2: cst.Opt[bytes] = cst.TStructField(cs.Const(b"JPEG"))
_3: None = cst.TStructField(cs.Pass)
_4: None = cst.TStructField(cs.Terminated)
_1: int = cst.sfield(cs.Computed(7))
_2: t.Optional[bytes] = cst.sfield(cs.Const(b"JPEG"))
_3: None = cst.sfield(cs.Pass)
_4: None = cst.sfield(cs.Terminated)
d = cst.TStruct(TestContainer)
assert d.build(TestContainer()) == d.build(TestContainer())
@ -223,8 +236,8 @@ def test_tstruct_anonymus_fields_2() -> None:
def test_tstruct_no_dataclass() -> None:
class TestContainer(cst.TContainerBase):
a: int = cst.TStructField(cs.Int16ub)
b: int = cst.TStructField(cs.Int8ub)
a: int = cst.sfield(cs.Int16ub)
b: int = cst.sfield(cs.Int8ub)
assert raises(lambda: cst.TStruct(TestContainer)) == TypeError
@ -232,8 +245,8 @@ def test_tstruct_no_dataclass() -> None:
def test_tstruct_no_tcontainerbase() -> None:
@dataclasses.dataclass
class TestContainer:
a: int = cst.TStructField(cs.Int16ub)
b: int = cst.TStructField(cs.Int8ub)
a: int = cst.sfield(cs.Int16ub)
b: int = cst.sfield(cs.Int8ub)
assert raises(lambda: cst.TStruct(TestContainer)) == TypeError
@ -241,13 +254,13 @@ def test_tstruct_no_tcontainerbase() -> None:
def test_tstruct_wrong_container() -> None:
@dataclasses.dataclass
class TestContainer1(cst.TContainerBase):
a: int = cst.TStructField(cs.Int16ub)
b: int = cst.TStructField(cs.Int8ub)
a: int = cst.sfield(cs.Int16ub)
b: int = cst.sfield(cs.Int8ub)
@dataclasses.dataclass
class TestContainer2(cst.TContainerBase):
a: int = cst.TStructField(cs.Int16ub)
b: int = cst.TStructField(cs.Int8ub)
a: int = cst.sfield(cs.Int16ub)
b: int = cst.sfield(cs.Int8ub)
assert (
raises(cst.TStruct(TestContainer1).build, TestContainer2(a=1, b=2)) == TypeError
@ -257,11 +270,11 @@ def test_tstruct_wrong_container() -> None:
def test_tstruct_doc() -> None:
@dataclasses.dataclass
class TestContainer(cst.TContainerBase):
a: int = cst.TStructField(cs.Int16ub, "This is the documentation of a")
b: int = cst.TStructField(
a: int = cst.sfield(cs.Int16ub, "This is the documentation of a")
b: int = cst.sfield(
cs.Int8ub, doc="This is the documentation of b\nwhich is multiline"
)
c: int = cst.TStructField(
c: int = cst.sfield(
cs.Int8ub,
"""
This is the documentation of c
@ -332,8 +345,8 @@ def test_tenum_in_tstruct() -> None:
@dataclasses.dataclass
class TestContainer(cst.TContainerBase):
a: TestEnum = cst.TStructField(cst.TEnum(cs.Int8ub, TestEnum))
b: int = cst.TStructField(cs.Int8ub)
a: TestEnum = cst.sfield(cst.TEnum(cs.Int8ub, TestEnum))
b: int = cst.sfield(cs.Int8ub)
common(
cst.TStruct(TestContainer),