From a1cde82bc23a8b2404480396413359c5c1280493 Mon Sep 17 00:00:00 2001 From: MatrixEditor <58256046+MatrixEditor@users.noreply.github.com> Date: Sat, 28 Sep 2024 08:31:08 +0200 Subject: [PATCH] Updated stub file --- + Removed field related tests --- src/caterpillar/_C.pyi | 333 ++++++++++-------- src/ccaterpillar/atomimpl/builtins/atoffset.c | 1 + src/ccaterpillar/atomimpl/builtins/switch.c | 2 +- src/ccaterpillar/atomimpl/cstring.c | 7 +- src/ccaterpillar/atomimpl/pstring.c | 2 +- test/_C/test_atom.py | 4 +- test/_C/test_field.py | 100 ------ test/_C/test_parsing.py | 19 +- 8 files changed, 201 insertions(+), 267 deletions(-) delete mode 100644 test/_C/test_field.py diff --git a/src/caterpillar/_C.pyi b/src/caterpillar/_C.pyi index 2078173..9e6703a 100644 --- a/src/caterpillar/_C.pyi +++ b/src/caterpillar/_C.pyi @@ -1,69 +1,95 @@ from __future__ import annotations from typing import Any, Optional, Collection, Union, Callable, IO, TypeVar +from enum import EnumType _Length = Union[int, ContextLambda, slice, Ellipsis] - -DefaultOption: DefaultOptionType = ... -FIELD_OPTIONS: set = ... -F_DYNAMIC: Option = ... -F_SEQUENTIAL: Option = ... -HOST_ARCH: Arch = ... -InvalidDefault: InvalidDefaultType = ... -NATIVE_ENDIAN: Endian = ... -LITTLE_ENDIAN: Endian = ... -BIG_ENDIAN: Endian = ... -STRUCT_OPTIONS: set = ... -S_DISCARD_CONST: Option = ... -S_DISCARD_UNNAMED: Option = ... -S_EVAL_ANNOTATIONS: Option = ... -S_REPLACE_TYPES: Option = ... -S_SLOTS: Option = ... -S_UNION: Option = ... +ContextLambda = Callable[[Context], Any] +_ConstType = Union[Any, ContextLambda] + +BIG_ENDIAN: Endian +DefaultOption: DefaultOptionType +FIELD_OPTIONS: set +F_DYNAMIC: Option +F_SEQUENTIAL: Option +HOST_ARCH: Arch +InvalidDefault: InvalidDefaultType +LITTLE_ENDIAN: Endian +NATIVE_ENDIAN: Endian +STRUCT_OPTIONS: set +S_DISCARD_CONST: Option +S_DISCARD_UNNAMED: Option +S_EVAL_ANNOTATIONS: Option +S_REPLACE_TYPES: Option +S_SLOTS: Option +S_UNION: Option +boolean: Bool +char: Char +f16: Float +f32: Float +f64: Float +i128: Int +i16: Int +i24: Int +i32: Int +i64: Int +i8: Int +lsbvarint: VarInt +padding: Padding +u128: Int +u16: Int +u24: Int +u32: Int +u64: Int +u8: Int +varint: VarInt class Context(dict): - def __init__(self, *args, **kwargs) -> None: ... + def __init__(self, /, **kwargs) -> None: ... def __context_getattr__(self, *args, **kwargs): ... -ContextLambda = Callable[[Context], Any] - class Arch: name: str ptr_size: int def __init__(self, name: str, ptr_size: int) -> None: ... def __hash__(self) -> int: ... -class BinaryExpr: +class binaryexpr: expr: int lhs: Union[ContextLambda, Any] rhs: Union[ContextLambda, Any] - def __init__(self, *args, **kwargs) -> None: ... - def __call__(self, *args, **kwargs): ... + def __init__( + self, + expr: int, + left: Union[ContextLambda, Any], + right: Union[ContextLambda, Any], + ) -> None: ... + def __call__(self, *args, **kwargs) -> Any: ... class ContextPath: path: str def __init__(self, path: str) -> None: ... - def __add__(self, other) -> BinaryExpr: ... - def __and__(self, other) -> BinaryExpr: ... + def __add__(self, other) -> binaryexpr: ... + def __and__(self, other) -> binaryexpr: ... def __call__(self, context: Context) -> Any: ... - def __eq__(self, other: object) -> BinaryExpr: ... - def __floordiv__(self, other) -> BinaryExpr: ... - def __ge__(self, other: object) -> BinaryExpr: ... - def __gt__(self, other: object) -> BinaryExpr: ... + def __eq__(self, other: object) -> binaryexpr: ... + def __floordiv__(self, other) -> binaryexpr: ... + def __ge__(self, other: object) -> binaryexpr: ... + def __gt__(self, other: object) -> binaryexpr: ... def __hash__(self) -> int: ... - def __invert__(self) -> UnaryExpr: ... - def __le__(self, other: object) -> BinaryExpr: ... - def __lshift__(self, other) -> BinaryExpr: ... - def __lt__(self, other: object) -> BinaryExpr: ... - def __mod__(self, other) -> BinaryExpr: ... - def __mul__(self, other) -> BinaryExpr: ... - def __ne__(self, other: object) -> BinaryExpr: ... - def __neg__(self) -> UnaryExpr: ... - def __or__(self, other) -> BinaryExpr: ... - def __sub__(self, other) -> UnaryExpr: ... - def __truediv__(self, other) -> BinaryExpr: ... + def __invert__(self) -> unaryexpr: ... + def __le__(self, other: object) -> binaryexpr: ... + def __lshift__(self, other) -> binaryexpr: ... + def __lt__(self, other: object) -> binaryexpr: ... + def __mod__(self, other) -> binaryexpr: ... + def __mul__(self, other) -> binaryexpr: ... + def __ne__(self, other: object) -> binaryexpr: ... + def __neg__(self) -> unaryexpr: ... + def __or__(self, other) -> binaryexpr: ... + def __sub__(self, other) -> unaryexpr: ... + def __truediv__(self, other) -> binaryexpr: ... def __type__(self) -> type: ... - def __xor__(self, other) -> BinaryExpr: ... + def __xor__(self, other) -> binaryexpr: ... class DefaultOptionType: def __init__(self) -> None: ... @@ -82,19 +108,19 @@ class Endian: class atom: def __init__(self) -> None: ... - def __pack__(self, obj: Any, context: Context) -> None: ... - def __size__(self, context: Context) -> Any: ... + def __pack__(self, obj: Any, context: layer) -> None: ... + def __size__(self, context: layer) -> Any: ... def __type__(self) -> Any: ... - def __unpack__(self, context: Context) -> Any: ... + def __unpack__(self, context: layer) -> Any: ... class catom(atom): def __init__(self) -> None: ... - def __pack__(self, obj: Any, context: Context) -> None: ... - def __pack_many__(self, obj: Collection[Any], context: Context) -> None: ... - def __size__(self, context: Context) -> Any: ... + def __pack__(self, obj: Any, context: layer) -> None: ... + def __pack_many__(self, obj: Collection[Any], layer: layer) -> None: ... + def __size__(self, context: layer) -> Any: ... def __type__(self) -> Any: ... - def __unpack__(self, context: Context) -> Any: ... - def __unpack_many__(self, context: Context) -> Collection[Any]: ... + def __unpack__(self, context: layer) -> Any: ... + def __unpack_many__(self, context: layer, lengthinfo) -> Collection[Any]: ... class builtinatom(catom): def __init__(self, *args, **kwargs) -> None: ... @@ -106,86 +132,24 @@ class builtinatom(catom): def __rrshift__(self, other) -> switch: ... def __rshift__(self, other) -> switch: ... - -class char_t(builtinatom): +class Char(builtinatom): def __init__(self, *args, **kwargs) -> None: ... class condition(builtinatom): atom: Any condition: Union[bool, ContextLambda] - def __init__(self, *args, **kwargs) -> None: ... - def is_enabled(self, *args, **kwargs): ... - def __set_byteorder__(self, *args, **kwargs): ... + def __init__(self, condition: Union[bool, ContextLambda], atom: Any) -> None: ... + def is_enabled(self, context: layer) -> bool: ... + def __set_byteorder__(self, byteorder: Endian) -> condition: ... -class const_t(builtinatom): +class const(builtinatom): def __init__(self, *args, **kwargs) -> None: ... - -class fieldatom(atom): - def __init__(self) -> None: ... - def __add__(self, endian: Endian) -> Field: ... - def __floordiv__(self, condition: Union[bool, ContextLambda]) -> Field: ... - def __getitem__( - self, length: _Length - ) -> Field: ... - def __matmul__(self, offset: Union[ContextLambda, int]) -> Field: ... - def __or__(self, option: Option) -> Field: ... - def __radd__(self, endian: Endian) -> Field: ... - def __rfloordiv__(self, condition: Union[bool, ContextLambda]) -> Field: ... - def __rmatmul__(self, offset: Union[ContextLambda, int]) -> Field: ... - def __ror__(self, option: Option) -> Field: ... - def __rrshift__(self, switch: Union[dict, ContextLambda]) -> Field: ... - def __rshift__(self, switch: Union[dict, ContextLambda]) -> Field: ... - def __rxor__(self, option: Option) -> Field: ... - def __xor__(self, option: Option) -> Field: ... - -class fieldcatom(catom): +class builtinatom(catom): def __init__(self) -> None: ... def __add__(self, endian: Endian) -> Field: ... def __floordiv__(self, condition: Union[bool, ContextLambda]) -> Field: ... - def __getitem__( - self, length: _Length - ) -> Field: ... - def __matmul__(self, offset: Union[ContextLambda, int]) -> Field: ... - def __or__(self, option: Option) -> Field: ... - def __radd__(self, endian: Endian) -> Field: ... - def __rfloordiv__(self, condition: Union[bool, ContextLambda]) -> Field: ... - def __rmatmul__(self, offset: Union[ContextLambda, int]) -> Field: ... - def __ror__(self, option: Option) -> Field: ... - def __rrshift__(self, switch: Union[dict, ContextLambda]) -> Field: ... - def __rshift__(self, switch: Union[dict, ContextLambda]) -> Field: ... - def __rxor__(self, option: Option) -> Field: ... - def __xor__(self, option: Option) -> Field: ... - -class Field: - arch: Arch - atom: atom - condition: Union[bool, ContextLambda] - default: Union[Any, InvalidDefaultType] - endian: Endian - length: _Length - name: str - offset: Union[ContextLambda, int] - options: set[Option] - switch: Union[dict, ContextLambda] - def __init__( - self, - atom: atom, - name: str = ..., - endian: Endian = ..., - offset: Union[ContextLambda, int] = ..., - arch: Arch = ..., - length: _Length = ..., - default: Union[Any, InvalidDefaultType] = ..., - switch: Union[dict, ContextLambda] = ..., - options: set[Option] = ..., - condition: Union[bool, ContextLambda] = ..., - ) -> None: ... - def __add__(self, endian: Endian) -> Field: ... - def __floordiv__(self, condition: Union[bool, ContextLambda]) -> Field: ... - def __getitem__( - self, length: _Length - ) -> Field: ... + def __getitem__(self, length: _Length) -> Field: ... def __matmul__(self, offset: Union[ContextLambda, int]) -> Field: ... def __or__(self, option: Option) -> Field: ... def __radd__(self, endian: Endian) -> Field: ... @@ -224,9 +188,14 @@ class State: class fieldinfo: excluded: bool + default: Any field: atom + name: str def __init__(self, field: atom, excluded: bool = ...) -> None: ... +class lengthinfo: + def __init__(self, *args, **kwargs) -> None: ... + class Struct(builtinatom): members: dict[str, fieldinfo] model: type @@ -240,7 +209,7 @@ class Struct(builtinatom): alter_model: bool = ..., ) -> None: ... -class UnaryExpr: +class unaryexpr: expr: int value: Union[ContextLambda, Any] def __init__(self, expr: int, value: Union[ContextLambda, Any]) -> Any: ... @@ -277,43 +246,25 @@ def pack(__obj: Any, __struct: atom, **globals) -> bytes: ... def sizeof(obj: atom, globals: Optional[dict | Context] = ...): ... def unpack(__io: Any, __struct: atom, **globals) -> Any: ... -class int_t(fieldcatom): +class Int(builtinatom): little_endian: bool nbits: int nbytes: int signed: bool - def __init__(self, nbits: int, signed: bool = ..., little_endian: bool = ...) -> None: ... - -i16: int_t -i24: int_t -i32: int_t -i64: int_t -i8: int_t -u16: int_t -u24: int_t -u32: int_t -u64: int_t -u8: int_t - -class float_t(fieldcatom): + def __init__( + self, nbits: int, signed: bool = ..., little_endian: bool = ... + ) -> None: ... + +class Float(builtinatom): little_endian: bool nbits: int nbytes: int def __init__(self, nbits: int, little_endian: bool = ...) -> None: ... -f16: float_t -f32: float_t -f64: float_t - -class padding_t(fieldcatom): +class Padding(builtinatom): def __init__(self, pad: int) -> None: ... -padding: padding_t - -boolean: bool_t -char: char_t - -class string(fieldcatom): +class string(builtinatom): encoding: str errors: str length: _Length @@ -322,10 +273,11 @@ class string(fieldcatom): class atoffset(builtinatom): offset: Union[int, ContextLambda] whence: int - def __init__(self, *args, **kwargs) -> None: ... + def __init__( + self, offset: Union[int, ContextLambda], atom: atom, whence: int = ... + ) -> None: ... def get_offset(self, layer: layer) -> int: ... - def __set_byteorder__(self, byteorder: Endian): ... - + def __set_byteorder__(self, byteorder: Endian) -> atoffset: ... class objlayer(layer): obj: Context @@ -335,8 +287,8 @@ class objlayer(layer): class repeated(builtinatom): atom: Any length: _Length - def __init__(self, *args, **kwargs) -> None: ... - def __set_byteorder__(self, *args, **kwargs): ... + def __init__(self, atom: atom, length: _Length) -> None: ... + def __set_byteorder__(self, byteorder: Endian) -> repeated: ... class seqlayer(layer): index: int @@ -347,6 +299,81 @@ class seqlayer(layer): class switch(builtinatom): atom: Any cases: Union[dict[Any, Any], ContextLambda] - def __init__(self, *args, **kwargs) -> None: ... - def get_next(self, *args, **kwargs): ... - def __set_byteorder__(self, *args, **kwargs): ... + def __init__( + self, atom: atom, cases: Union[dict[Any, Any], ContextLambda] + ) -> None: ... + def get_next(self, obj: Any, context: layer) -> Any: ... + def __set_byteorder__(self, byteorder: Endian) -> switch: ... + +class cstring(builtinatom): + length: Union[_Length, atom] + encoding: str + errors: str + terminator: str + keep_terminator: bool + + def __init__( + self, + length: Union[_Length, atom], + encoding: str = ..., + errors: str = ..., + sep: str = ..., + keep_terminator: bool = ..., + ) -> None: ... + +class octetstring(builtinatom): + length: _Length + def __init__(self, length: _Length) -> None: ... + +class enumeration(builtinatom): + atom: Any + enum_type: EnumType + members: dict[Any, Any] + default: Any + def __init__( + self, + atom: atom, + enum_type: EnumType, + default: Any = ..., + ) -> None: ... + def __set_byteorder__(self, byteorder: Endian) -> enumeration: ... + +class pstring(builtinatom): + atom: Any + encoding: str + errors: str + def __init__(self, atom: atom, encoding: str = ..., errors: str = ...) -> None: ... + def __set_byteorder__(self, byteorder: Endian) -> pstring: ... + +class VarInt(builtinatom): + little_endian: bool + lsb: bool + def __init__(self, little_endian: bool = ..., lsb: bool = ...) -> None: ... + def __set_byteorder__(self, byteorder: Endian) -> VarInt: ... + +class computed(builtinatom): + value: _ConstType + def __init__(self, value: _ConstType) -> None: ... + +class objlayer(layer): + obj: Context + def __init__( + self, state: State, path: str = ..., parent: layer = ..., obj: Context = ... + ) -> None: ... + def __context_getattr__(self, path: str) -> Any: ... + +class lazy(builtinatom): + always_lazy: bool + fn: Callable[[], atom] + def __init__(self, fn: Callable[[], atom], always_lazy: bool = ...) -> None: ... + def __set_byteorder__(self, byteorder: Endian) -> lazy: ... + +class patom(atom): + def __init__(self) -> None: ... + def __floordiv__(self, other): ... + def __getitem__(self, index): ... + def __matmul__(self, *args, **kwargs): ... + def __rfloordiv__(self, other): ... + def __rmatmul__(self, *args, **kwargs): ... + def __rrshift__(self, other): ... + def __rshift__(self, other): ... diff --git a/src/ccaterpillar/atomimpl/builtins/atoffset.c b/src/ccaterpillar/atomimpl/builtins/atoffset.c index 2d1a897..7b11102 100644 --- a/src/ccaterpillar/atomimpl/builtins/atoffset.c +++ b/src/ccaterpillar/atomimpl/builtins/atoffset.c @@ -166,6 +166,7 @@ CpOffsetAtom_Unpack(CpOffsetAtomObject* self, CpLayerObject* layer) static PyMemberDef CpOffsetAtom_Members[] = { { "offset", T_OBJECT_EX, offsetof(CpOffsetAtomObject, m_offset), READONLY }, { "whence", T_OBJECT_EX, offsetof(CpOffsetAtomObject, m_whence), READONLY }, + { "atom", T_OBJECT_EX, offsetof(CpOffsetAtomObject, m_atom), READONLY }, { NULL } /* Sentinel */ }; diff --git a/src/ccaterpillar/atomimpl/builtins/switch.c b/src/ccaterpillar/atomimpl/builtins/switch.c index 7548e56..5f341a5 100644 --- a/src/ccaterpillar/atomimpl/builtins/switch.c +++ b/src/ccaterpillar/atomimpl/builtins/switch.c @@ -136,7 +136,7 @@ _CpEndian_ImplSetByteorder(CpSwitchAtomObject, switchatom, self->m_atom); static PyObject* cp_switchatom_get_next(CpSwitchAtomObject* self, PyObject* args, PyObject* kw) { - static char* kwlist[] = { "atom", "context", NULL }; + static char* kwlist[] = { "obj", "context", NULL }; PyObject* op = NULL; PyObject* context = NULL; if (!PyArg_ParseTupleAndKeywords(args, kw, "OO", kwlist, &op, &context)) { diff --git a/src/ccaterpillar/atomimpl/cstring.c b/src/ccaterpillar/atomimpl/cstring.c index 3804a7b..25e3795 100644 --- a/src/ccaterpillar/atomimpl/cstring.c +++ b/src/ccaterpillar/atomimpl/cstring.c @@ -295,6 +295,11 @@ static PyMemberDef CpCStringAtom_Members[] = { offsetof(CpCStringAtomObject, s_keep_terminator), 0, "whether to keep the terminator" }, + { "length", + T_OBJECT_EX, + offsetof(CpCStringAtomObject, m_length), + 0, + "the length of the string" }, { NULL } }; @@ -304,7 +309,7 @@ PyTypeObject CpCStringAtom_Type = { .tp_itemsize = 0, .tp_dealloc = (destructor)cp_cstringatom_dealloc, .tp_repr = (reprfunc)cp_cstringatom_repr, - .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, .tp_new = (newfunc)cp_cstringatom_new, .tp_members = CpCStringAtom_Members, .tp_init = (initproc)cp_cstringatom_init, diff --git a/src/ccaterpillar/atomimpl/pstring.c b/src/ccaterpillar/atomimpl/pstring.c index deea57d..7fe1cd1 100644 --- a/src/ccaterpillar/atomimpl/pstring.c +++ b/src/ccaterpillar/atomimpl/pstring.c @@ -158,7 +158,7 @@ PyTypeObject CpPStringAtom_Type = { PyVarObject_HEAD_INIT(NULL, 0) _Cp_NameStr(CpPStringAtom_NAME), .tp_basicsize = sizeof(CpPStringAtomObject), .tp_dealloc = (destructor)cp_pstringatom_dealloc, - .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, .tp_doc = NULL, .tp_members = CpPStringAtom_Members, .tp_init = (initproc)cp_pstringatom_init, diff --git a/test/_C/test_atom.py b/test/_C/test_atom.py index cda36d1..c58eaf0 100644 --- a/test/_C/test_atom.py +++ b/test/_C/test_atom.py @@ -4,7 +4,7 @@ if caterpillar.native_support(): - from caterpillar._C import atom, catom, fieldatom, fieldcatom + from caterpillar._C import atom, catom def test_atom_init(): @@ -26,8 +26,6 @@ class Foo(atom): assert issubclass(Foo, atom) assert issubclass(catom, atom) - assert issubclass(fieldatom, atom) - assert issubclass(fieldcatom, catom) def test_atom_methods(): diff --git a/test/_C/test_field.py b/test/_C/test_field.py deleted file mode 100644 index 449e2ed..0000000 --- a/test/_C/test_field.py +++ /dev/null @@ -1,100 +0,0 @@ -# pylint: disable=unused-import,no-name-in-module,import-error -import pytest - -import caterpillar - -if caterpillar.native_support(): - - from caterpillar._C import Field, fieldatom, atom - from caterpillar._C import NATIVE_ENDIAN, HOST_ARCH, F_DYNAMIC - - - def test_field_init(): - # Just verify that we can instantiate a field - with pytest.raises(TypeError): - Field() - - Field(atom()) - - # use all parameters - Field( - atom(), - name="foo", - offset=1, - length=2, - endian=NATIVE_ENDIAN, - default=3, - switch={1: 2}, - condition=False, - options=set(), - arch=HOST_ARCH, - ) - - - def test_field_offset(): - # The offset may be set using the constructor or by applying - # the special '@' operator. We can apply a constant value or - # a context lambda (callable function) here. - assert Field(atom()).offset is None - assert Field(atom(), offset=1).offset == 1 - assert (Field(atom()) @ 1).offset == 1 - assert (Field(atom()) @ (lambda ctx: 1)).offset(None) == 1 - - - def test_field_length(): - # The length may be set using the constructor or by applying - # the special '[]' operation. Be aware, thatz multiple dimensions - # are not supported yet. - # The length can take the following types: int, ellipsis, slice - # or a context lambda (callable function). - field = Field(atom()) - assert field.length is None - assert Field(atom(), length=1).length == 1 - assert field[1].length == 1 - assert field[lambda ctx: 1].length(None) == 1 - assert field[lambda x: 2 : :].length.start(None) == 2 - assert field[...].length is Ellipsis - - with pytest.raises(TypeError): - # type not supported - _ = field["foo"] - - - def test_field_condition(): - # The condition is somewhat special as it will be deprecated in the - # future. It may be a contant boolean value or a context lambda (callable - # function). Use the '//' operatorto apply a new condition. - field = Field(atom()) - assert field.condition is True # the default value is True - assert Field(atom(), condition=False).condition is False - assert (field // (lambda ctx: False)).condition(None) is False - assert (field // (lambda ctx: True)).condition(None) is True - - with pytest.raises(TypeError): - # type not supported - _ = field // "foo" - - - def test_field_switch(): - # A switch can be defined using the '>>' operation and the - # required value must be a dictionary or a context lambda. - field = Field(atom()) - assert field.switch is None - assert Field(atom(), switch={1: 2}).switch == {1: 2} - - with pytest.raises(TypeError): - # type not supported - _ = field >> "foo" - - # the stored value must be an atom instance, that can be - # called directly. - assert (field >> {1: atom()}).switch[1].__class__ == atom - assert (field >> (lambda x: atom())).switch(None).__class__ == atom - - - def test_field_options(): - # Options can be added with `|` and removed with `^`. - field = Field(atom()) - assert len(field.options) == 1 # keep_pos is inferred - assert F_DYNAMIC in (field | F_DYNAMIC).options - assert F_DYNAMIC not in (field ^ F_DYNAMIC).options diff --git a/test/_C/test_parsing.py b/test/_C/test_parsing.py index ddcb417..1dd7802 100644 --- a/test/_C/test_parsing.py +++ b/test/_C/test_parsing.py @@ -5,7 +5,8 @@ if caterpillar.native_support(): - from caterpillar._C import atom, typeof, Field, sizeof, patom + from caterpillar._C import atom, typeof, sizeof, patom, repeated + from caterpillar._C import switch from caterpillar._C import unpack, layer, Struct, pack, ContextPath @@ -42,16 +43,16 @@ def test_typeof(): # That will change if we have a field with a length or a # switch statement. - field = Field(f, length=2) + field = repeated(f, 2) assert typeof(field) == typing.List[str] - field2 = Field(f, switch={1: atom()}) + field2 = switch(f, {1: atom()})[2] # We can't know the type of a switch atom which does # not implement the __type__ method - assert typeof(Field(atom())) == typing.Any - assert typeof(field2) == typing.Union[typing.Any, str] + assert typeof(atom()) == typing.Any + assert typeof(field2) == typing.List[typing.Any] # switch and length can be combined as well - assert typeof(field2[2]) == typing.List[typing.Union[typing.Any, str]] + assert typeof(field2[2]) == typing.List[typing.List[typing.Any]] def test_sizeof(): @@ -73,8 +74,10 @@ def test_sizeof(): # Calculation is done by first evaluating the length of # the field's atom and then multiply the length of the evalutated # switch atom by the field's length. - field = Field(b, length=2, switch=(lambda ctx: Bar())) - assert sizeof(field) == 2 + (2 * 2) + # REVISIT: switch atoms does not have a static size + with pytest.raises(TypeError): + field = switch(b, (lambda ctx: Bar()))[2] + assert sizeof(field) == 2 + (2 * 2) def test_unpack_basic():