From 6550e59dd3d9ad51659c3ffcbffbc45e8d65b57f Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Fri, 30 Jun 2023 13:06:29 +0200 Subject: [PATCH 01/42] added missing __new__ methods --- construct-stubs/core.pyi | 125 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/construct-stubs/core.pyi b/construct-stubs/core.pyi index 392c8fc..adcc1d8 100644 --- a/construct-stubs/core.pyi +++ b/construct-stubs/core.pyi @@ -200,6 +200,9 @@ class Subconstruct( class Adapter( Subconstruct[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes], ): + def __new__( + cls, subcon: Construct[SubconParsedType, SubconBuildTypes] + ) -> Adapter[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]: ... def __init__( self, subcon: Construct[SubconParsedType, SubconBuildTypes] ) -> None: ... @@ -671,6 +674,13 @@ class RepeatUntil( class Renamed( Subconstruct[SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes] ): + def __new__( + cls, + subcon: Construct[SubconParsedType, SubconBuildTypes], + newname: t.Optional[str] = ..., + newdocs: t.Optional[str] = ..., + newparsed: t.Optional[t.Callable[[t.Any, Context], None]] = ..., + ) -> Renamed[SubconParsedType, SubconBuildTypes]: ... def __init__( self, subcon: Construct[SubconParsedType, SubconBuildTypes], @@ -1084,6 +1094,12 @@ class Padded( ): length: ConstantOrContextLambda[int] pattern: bytes + def __new__( + cls, + length: ConstantOrContextLambda[int], + subcon: Construct[SubconParsedType, SubconBuildTypes], + pattern: bytes = ..., + ) -> Padded[SubconParsedType, SubconBuildTypes]: ... def __init__( self, length: ConstantOrContextLambda[int], @@ -1096,6 +1112,12 @@ class Aligned( ): modulus: ConstantOrContextLambda[int] pattern: bytes + def __new__( + cls, + modulus: ConstantOrContextLambda[int], + subcon: Construct[SubconParsedType, SubconBuildTypes], + pattern: bytes = ..., + ) -> Aligned[SubconParsedType, SubconBuildTypes]: ... def __init__( self, modulus: ConstantOrContextLambda[int], @@ -1123,6 +1145,12 @@ class Pointer( ): offset: ConstantOrContextLambda[int] stream: t.Optional[t.Callable[[Context], StreamType]] + def __new__( + cls, + offset: ConstantOrContextLambda[int], + subcon: Construct[SubconParsedType, SubconBuildTypes], + stream: t.Optional[t.Callable[[Context], StreamType]] = ..., + ) -> Pointer[SubconParsedType, SubconBuildTypes]: ... def __init__( self, offset: ConstantOrContextLambda[int], @@ -1213,6 +1241,12 @@ class Prefixed( ): lengthfield: Construct[SubconParsedType, SubconBuildTypes] includelength: t.Optional[bool] + def __new__( + cls, + lengthfield: Construct[int, int], + subcon: Construct[SubconParsedType, SubconBuildTypes], + includelength: t.Optional[bool] = ..., + ) -> Prefixed[SubconParsedType, SubconBuildTypes]: ... def __init__( self, lengthfield: Construct[int, int], @@ -1234,6 +1268,11 @@ class FixedSized( Subconstruct[SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes] ): length: ConstantOrContextLambda[int] + def __new__( + cls, + length: ConstantOrContextLambda[int], + subcon: Construct[SubconParsedType, SubconBuildTypes], + ) -> FixedSized[SubconParsedType, SubconBuildTypes]: ... def __init__( self, length: ConstantOrContextLambda[int], @@ -1247,6 +1286,14 @@ class NullTerminated( include: t.Optional[bool] consume: t.Optional[bool] require: t.Optional[bool] + def __new__( + cls, + subcon: Construct[SubconParsedType, SubconBuildTypes], + term: bytes = ..., + include: t.Optional[bool] = ..., + consume: t.Optional[bool] = ..., + require: t.Optional[bool] = ..., + ) -> NullTerminated[SubconParsedType, SubconBuildTypes]: ... def __init__( self, subcon: Construct[SubconParsedType, SubconBuildTypes], @@ -1260,6 +1307,9 @@ class NullStripped( Subconstruct[SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes] ): pad: bytes + def __new__( + cls, subcon: Construct[SubconParsedType, SubconBuildTypes], pad: bytes = ... + ) -> NullStripped[SubconParsedType, SubconBuildTypes]: ... def __init__( self, subcon: Construct[SubconParsedType, SubconBuildTypes], pad: bytes = ... ) -> None: ... @@ -1270,6 +1320,13 @@ class RestreamData( datafunc: t.Union[ bytes, io.BytesIO, Construct[bytes, t.Any], t.Callable[[Context], bytes] ] + def __new__( + cls, + datafunc: t.Union[ + bytes, io.BytesIO, Construct[bytes, t.Any], t.Callable[[Context], bytes] + ], + subcon: Construct[SubconParsedType, SubconBuildTypes], + ) -> RestreamData[SubconParsedType, SubconBuildTypes]: ... def __init__( self, datafunc: t.Union[ @@ -1285,6 +1342,14 @@ class Transformed( decodeamount: t.Optional[int] encodefunc: t.Callable[[bytes], bytes] encodeamount: t.Optional[int] + def __new__( + cls, + subcon: Construct[SubconParsedType, SubconBuildTypes], + decodefunc: t.Callable[[bytes], bytes], + decodeamount: t.Optional[int], + encodefunc: t.Callable[[bytes], bytes], + encodeamount: t.Optional[int], + ) -> Transformed[SubconParsedType, SubconBuildTypes]: ... def __init__( self, subcon: Construct[SubconParsedType, SubconBuildTypes], @@ -1302,6 +1367,15 @@ class Restreamed( encoder: t.Callable[[bytes], bytes] encoderunit: int sizecomputer: t.Callable[[int], int] + def __new__( + cls, + subcon: Construct[SubconParsedType, SubconBuildTypes], + decoder: t.Callable[[bytes], bytes], + decoderunit: int, + encoder: t.Callable[[bytes], bytes], + encoderunit: int, + sizecomputer: t.Callable[[int], int], + ) -> Restreamed[SubconParsedType, SubconBuildTypes]: ... def __init__( self, subcon: Construct[SubconParsedType, SubconBuildTypes], @@ -1362,6 +1436,12 @@ class Compressed(Tunnel[SubconParsedType, SubconBuildTypes]): encoding: str level: t.Optional[int] lib: t.Any + def __new__( + cls, + subcon: Construct[SubconParsedType, SubconBuildTypes], + encoding: str, + level: t.Optional[int] = ..., + ) -> Compressed[SubconParsedType, SubconBuildTypes]: ... def __init__( self, subcon: Construct[SubconParsedType, SubconBuildTypes], @@ -1371,6 +1451,10 @@ class Compressed(Tunnel[SubconParsedType, SubconBuildTypes]): class CompressedLZ4(Tunnel[SubconParsedType, SubconBuildTypes]): lib: t.Any + def __new__( + cls, + subcon: Construct[SubconParsedType, SubconBuildTypes], + ) -> CompressedLZ4[SubconParsedType, SubconBuildTypes]: ... def __init__( self, subcon: Construct[SubconParsedType, SubconBuildTypes], @@ -1380,6 +1464,11 @@ class Rebuffered( Subconstruct[SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes] ): stream2: RebufferedBytesIO + def __new__( + cls, + subcon: Construct[SubconParsedType, SubconBuildTypes], + tailcutoff: t.Optional[int] = ..., + ) -> Rebuffered[SubconParsedType, SubconBuildTypes]: ... def __init__( self, subcon: Construct[SubconParsedType, SubconBuildTypes], @@ -1479,6 +1568,12 @@ class LazyBound(Construct[ParsedType, BuildTypes]): # adapters and validators # =============================================================================== class ExprAdapter(Adapter[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]): + def __new__( + cls, + subcon: Construct[SubconParsedType, SubconBuildTypes], + decoder: t.Callable[[SubconParsedType, Context], ParsedType], + encoder: t.Callable[[BuildTypes, Context], SubconBuildTypes], + ) -> ExprAdapter[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]: ... def __init__( self, subcon: Construct[SubconParsedType, SubconBuildTypes], @@ -1489,6 +1584,11 @@ class ExprAdapter(Adapter[SubconParsedType, SubconBuildTypes, ParsedType, BuildT class ExprSymmetricAdapter( ExprAdapter[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes] ): + def __new__( + cls, + subcon: Construct[SubconParsedType, SubconBuildTypes], + encoder: t.Callable[[BuildTypes, Context], SubconBuildTypes], + ) -> ExprSymmetricAdapter[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]: ... def __init__( self, subcon: Construct[SubconParsedType, SubconBuildTypes], @@ -1496,6 +1596,11 @@ class ExprSymmetricAdapter( ) -> None: ... class ExprValidator(Validator[SubconParsedType, SubconBuildTypes]): + def __new__( + cls, + subcon: Construct[SubconParsedType, SubconBuildTypes], + validator: t.Callable[[SubconParsedType, Context], bool], + ) -> ExprValidator[SubconParsedType, SubconBuildTypes]: ... def __init__( self, subcon: Construct[SubconParsedType, SubconBuildTypes], @@ -1568,6 +1673,26 @@ class Slicing( class Indexing( Adapter[SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes] ): + def __new__( + cls, + subcon: t.Union[ + Array[ + SubconParsedType, + SubconBuildTypes, + ListContainer[SubconParsedType], + t.List[SubconBuildTypes], + ], + GreedyRange[ + SubconParsedType, + SubconBuildTypes, + ListContainer[SubconParsedType], + t.List[SubconBuildTypes], + ], + ], + count: int, + index: int, + empty: t.Optional[SubconParsedType] = ..., + ) -> Indexing[SubconParsedType, SubconBuildTypes]: ... def __init__( self, subcon: t.Union[ From dcdeeca39fb7880d5eac323d1888828394fd2e1d Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Fri, 30 Jun 2023 14:13:01 +0200 Subject: [PATCH 02/42] removed all __new__ methods. mypy v1.4.1 is working. --- construct-stubs/core.pyi | 550 +++------------------------- construct_typed/dataclass_struct.py | 2 +- 2 files changed, 47 insertions(+), 505 deletions(-) diff --git a/construct-stubs/core.pyi b/construct-stubs/core.pyi index adcc1d8..d3b46fa 100644 --- a/construct-stubs/core.pyi +++ b/construct-stubs/core.pyi @@ -25,11 +25,6 @@ from construct.lib import ( # - Higher Kinded Types: https://github.com/python/typing/issues/548 # - Higher Kinded Types: https://sobolevn.me/2020/10/higher-kinded-types-in-python -# The type checkers mypy and pyright/pylance unfortunately work a little bit different with __init__ and __new__. -# For supporting some constructs (eg. Enum, NamedTuple, Slicing) in mypy the __init__ self parameter has to have a -# type hint. But for supporting pyright/pylance, the same type hint has to be used as the return type of __new__. -# (see discussion here: https://github.com/python/typeshed/issues/4846). - StreamType = t.IO[bytes] FilenameType = t.Union[str, bytes, os.PathLike[str], os.PathLike[bytes]] PathType = str @@ -174,25 +169,13 @@ class Subconstruct( ): subcon: Construct[SubconParsedType, SubconBuildTypes] @t.overload - def __new__( - cls, subcon: Construct[SubconParsedType, SubconBuildTypes] - ) -> Subconstruct[ - SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes - ]: ... - @t.overload - def __new__( - cls, *args: t.Any, **kwargs: t.Any - ) -> Subconstruct[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]: ... - @t.overload def __init__( - self: Subconstruct[ - SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes - ], + self: t.Self, subcon: Construct[SubconParsedType, SubconBuildTypes], ) -> None: ... @t.overload def __init__( - self: Subconstruct[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes], + self: t.Self, *args: t.Any, **kwargs: t.Any, ) -> None: ... @@ -200,11 +183,8 @@ class Subconstruct( class Adapter( Subconstruct[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes], ): - def __new__( - cls, subcon: Construct[SubconParsedType, SubconBuildTypes] - ) -> Adapter[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]: ... def __init__( - self, subcon: Construct[SubconParsedType, SubconBuildTypes] + self: t.Self, subcon: Construct[SubconParsedType, SubconBuildTypes] ) -> None: ... def _decode( self, obj: SubconBuildTypes, context: Context, path: PathType @@ -239,10 +219,6 @@ class Tunnel( # =============================================================================== class Bytes(Construct[ParsedType, BuildTypes]): length: ConstantOrContextLambda[int] - def __new__( - cls, - length: ConstantOrContextLambda[int], - ) -> Bytes[bytes, t.Union[bytes, int]]: ... def __init__( self: Bytes[bytes, t.Union[bytes, int]], length: ConstantOrContextLambda[int], @@ -275,30 +251,6 @@ class FormatField(Construct[ParsedType, BuildTypes]): FORMAT_FLOAT = t.Literal["f", "d", "e"] FORMAT_BOOL = t.Literal["?"] @t.overload - def __new__( - cls, - endianity: str, - format: FORMAT_INT, - ) -> FormatField[int, int]: ... - @t.overload - def __new__( - cls, - endianity: str, - format: FORMAT_FLOAT, - ) -> FormatField[float, float]: ... - @t.overload - def __new__( - cls, - endianity: str, - format: FORMAT_BOOL, - ) -> FormatField[bool, bool]: ... - @t.overload - def __new__( - cls, - endianity: str, - format: str, - ) -> FormatField[t.Any, t.Any]: ... - @t.overload def __init__( self: FormatField[int, int], endianity: str, @@ -323,11 +275,6 @@ class FormatField(Construct[ParsedType, BuildTypes]): format: str, ) -> None: ... else: - def __new__( - cls, - endianity: str, - format: str, - ) -> FormatField[t.Any, t.Any]: ... def __init__( self: FormatField[t.Any, t.Any], endianity: str, @@ -338,12 +285,6 @@ class BytesInteger(Construct[ParsedType, BuildTypes]): length: ConstantOrContextLambda[int] signed: bool swapped: ConstantOrContextLambda[bool] - def __new__( - cls, - length: ConstantOrContextLambda[int], - signed: bool = ..., - swapped: ConstantOrContextLambda[bool] = ..., - ) -> BytesInteger[int, int]: ... def __init__( self: BytesInteger[int, int], length: ConstantOrContextLambda[int], @@ -355,12 +296,6 @@ class BitsInteger(Construct[ParsedType, BuildTypes]): length: ConstantOrContextLambda[int] signed: bool swapped: ConstantOrContextLambda[bool] - def __new__( - cls, - length: ConstantOrContextLambda[int], - signed: bool = ..., - swapped: ConstantOrContextLambda[bool] = ..., - ) -> BitsInteger[int, int]: ... def __init__( self: BitsInteger[int, int], length: ConstantOrContextLambda[int], @@ -438,11 +373,6 @@ class StringEncoded(Construct[ParsedType, BuildTypes]): else: ENCODING = str encoding: ENCODING - def __new__( - cls, - subcon: Construct[ParsedType, BuildTypes], - encoding: ENCODING, - ) -> StringEncoded[str, str]: ... def __init__( self: StringEncoded[str, str], subcon: Construct[ParsedType, BuildTypes], @@ -469,18 +399,12 @@ class EnumIntegerString(str): @staticmethod def new(intvalue: int, stringvalue: str) -> EnumIntegerString: ... -class Enum(Adapter[int, int, ParsedType, BuildTypes]): +class Enum(Adapter[int, int, t.Union[EnumInteger, EnumIntegerString], t.Union[int, str]]): encmapping: t.Dict[str, int] decmapping: t.Dict[int, EnumIntegerString] ksymapping: t.Dict[int, str] - def __new__( - cls, - subcon: Construct[int, int], - *merge: t.Union[t.Type[enum.IntEnum], t.Type[enum.IntFlag]], - **mapping: int, - ) -> Enum[t.Union[EnumInteger, EnumIntegerString], t.Union[int, str]]: ... def __init__( - self: Enum[t.Union[EnumInteger, EnumIntegerString], t.Union[int, str]], + self: t.Self, subcon: Construct[int, int], *merge: t.Union[t.Type[enum.IntEnum], t.Type[enum.IntFlag]], **mapping: int, @@ -490,17 +414,11 @@ class Enum(Adapter[int, int, ParsedType, BuildTypes]): class BitwisableString(str): def __or__(self, other: BitwisableString) -> BitwisableString: ... -class FlagsEnum(Adapter[int, int, ParsedType, BuildTypes]): +class FlagsEnum(Adapter[int, int, Container[bool], t.Union[int, str, t.Dict[str, bool]]]): flags: t.Dict[str, int] reverseflags: t.Dict[int, str] - def __new__( - cls, - subcon: Construct[int, int], - *merge: t.Union[t.Type[enum.IntEnum], t.Type[enum.IntFlag]], - **flags: int, - ) -> FlagsEnum[Container[bool], t.Union[int, str, t.Dict[str, bool]]]: ... def __init__( - self: FlagsEnum[Container[bool], t.Union[int, str, t.Dict[str, bool]]], + self: t.Self, subcon: Construct[int, int], *merge: t.Union[t.Type[enum.IntEnum], t.Type[enum.IntFlag]], **flags: int, @@ -510,13 +428,8 @@ class FlagsEnum(Adapter[int, int, ParsedType, BuildTypes]): class Mapping(Adapter[SubconParsedType, SubconBuildTypes, t.Any, t.Any]): decmapping: t.Dict[int, str] encmapping: t.Dict[str, int] - def __new__( - cls, - subcon: Construct[SubconParsedType, SubconBuildTypes], - mapping: t.Dict[t.Any, t.Any], - ) -> Mapping[t.Any, t.Any]: ... def __init__( - self: Mapping[t.Any, t.Any], + self: t.Self, subcon: Construct[SubconParsedType, SubconBuildTypes], mapping: t.Dict[t.Any, t.Any], ) -> None: ... @@ -525,32 +438,22 @@ class Mapping(Adapter[SubconParsedType, SubconBuildTypes, t.Any, t.Any]): # structures and sequences # =============================================================================== # this can maybe made better when variadic generics are available -class Struct(Construct[ParsedType, BuildTypes]): +class Struct(Construct[Container[t.Any], t.Optional[t.Dict[str, t.Any]]]): subcons: t.List[Construct[t.Any, t.Any]] _subcons: t.Dict[str, Construct[t.Any, t.Any]] - def __new__( - cls, - *subcons: Construct[t.Any, t.Any], - **subconskw: Construct[t.Any, t.Any], - ) -> Struct[Container[t.Any], t.Optional[t.Dict[str, t.Any]]]: ... def __init__( - self: Struct[Container[t.Any], t.Optional[t.Dict[str, t.Any]]], + self: t.Self, *subcons: Construct[t.Any, t.Any], **subconskw: Construct[t.Any, t.Any], ) -> None: ... def __getattr__(self, name: str) -> t.Any: ... # this can maybe made better when variadic generics are available -class Sequence(Construct[ParsedType, BuildTypes]): +class Sequence(Construct[ListContainer[t.Any], t.Optional[t.List[t.Any]]]): subcons: t.List[Construct[t.Any, t.Any]] _subcons: t.Dict[str, Construct[t.Any, t.Any]] - def __new__( - cls, - *subcons: Construct[t.Any, t.Any], - **subconskw: Construct[t.Any, t.Any], - ) -> Sequence[ListContainer[t.Any], t.Optional[t.List[t.Any]]]: ... def __init__( - self: Sequence[ListContainer[t.Any], t.Optional[t.List[t.Any]]], + self: t.Self, *subcons: Construct[t.Any, t.Any], **subconskw: Construct[t.Any, t.Any], ) -> None: ... @@ -569,17 +472,6 @@ class Array( ): count: ConstantOrContextLambda[int] discard: bool - def __new__( - cls, - count: ConstantOrContextLambda[int], - subcon: Construct[SubconParsedType, SubconBuildTypes], - discard: bool = ..., - ) -> Array[ - SubconParsedType, - SubconBuildTypes, - ListContainer[SubconParsedType], - t.List[SubconBuildTypes], - ]: ... def __init__( self: Array[ SubconParsedType, @@ -601,16 +493,6 @@ class GreedyRange( ] ): discard: bool - def __new__( - cls, - subcon: Construct[SubconParsedType, SubconBuildTypes], - discard: bool = ..., - ) -> GreedyRange[ - SubconParsedType, - SubconBuildTypes, - ListContainer[SubconParsedType], - t.List[SubconBuildTypes], - ]: ... def __init__( self: GreedyRange[ SubconParsedType, @@ -635,22 +517,6 @@ class RepeatUntil( t.Callable[[SubconParsedType, ListContainer[SubconParsedType], Context], bool], ] discard: bool - def __new__( - cls, - predicate: t.Union[ - bool, - t.Callable[ - [SubconParsedType, ListContainer[SubconParsedType], Context], bool - ], - ], - subcon: Construct[SubconParsedType, SubconBuildTypes], - discard: bool = ..., - ) -> RepeatUntil[ - SubconParsedType, - SubconBuildTypes, - ListContainer[SubconParsedType], - t.List[SubconBuildTypes], - ]: ... def __init__( self: RepeatUntil[ SubconParsedType, @@ -674,15 +540,8 @@ class RepeatUntil( class Renamed( Subconstruct[SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes] ): - def __new__( - cls, - subcon: Construct[SubconParsedType, SubconBuildTypes], - newname: t.Optional[str] = ..., - newdocs: t.Optional[str] = ..., - newparsed: t.Optional[t.Callable[[t.Any, Context], None]] = ..., - ) -> Renamed[SubconParsedType, SubconBuildTypes]: ... def __init__( - self, + self: t.Self, subcon: Construct[SubconParsedType, SubconBuildTypes], newname: t.Optional[str] = ..., newdocs: t.Optional[str] = ..., @@ -695,30 +554,21 @@ class Renamed( class Const(Subconstruct[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]): value: SubconBuildTypes @t.overload - def __new__( - cls, + def __init__( + self: Const[None, None, bytes, t.Optional[bytes]], value: bytes, - ) -> Const[None, None, bytes, t.Optional[bytes]]: ... + ) -> None: ... @t.overload - def __new__( - cls, + def __init__( + self: Const[None, None, SubconParsedType, t.Optional[SubconBuildTypes]], value: SubconBuildTypes, subcon: Construct[SubconParsedType, SubconBuildTypes], - ) -> Const[None, None, SubconParsedType, t.Optional[SubconBuildTypes]]: ... + ) -> None: ... + class Computed(Construct[ParsedType, BuildTypes]): func: ConstantOrContextLambda2[ParsedType] @t.overload - def __new__( - cls, - func: ConstantOrContextLambda2[ParsedType], - ) -> Computed[ParsedType, None]: ... - @t.overload - def __new__( - cls, - func: ConstantOrContextLambda2[t.Any], - ) -> Computed[t.Any, None]: ... - @t.overload def __init__( self: Computed[ParsedType, None], func: ConstantOrContextLambda2[ParsedType], @@ -733,11 +583,6 @@ Index: Construct[int, t.Any] class Rebuild(Subconstruct[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]): func: ConstantOrContextLambda[SubconBuildTypes] - def __new__( - cls, - subcon: Construct[SubconParsedType, SubconBuildTypes], - func: ConstantOrContextLambda[SubconBuildTypes], - ) -> Rebuild[SubconParsedType, SubconBuildTypes, SubconParsedType, None]: ... def __init__( self: Rebuild[SubconParsedType, SubconBuildTypes, SubconParsedType, None], subcon: Construct[SubconParsedType, SubconBuildTypes], @@ -746,16 +591,6 @@ class Rebuild(Subconstruct[SubconParsedType, SubconBuildTypes, ParsedType, Build class Default(Subconstruct[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]): value: ConstantOrContextLambda[SubconBuildTypes] - def __new__( - cls, - subcon: Construct[SubconParsedType, SubconBuildTypes], - value: ConstantOrContextLambda[SubconBuildTypes], - ) -> Default[ - SubconParsedType, - SubconBuildTypes, - SubconParsedType, - t.Optional[SubconBuildTypes], - ]: ... def __init__( self: Default[ SubconParsedType, @@ -769,10 +604,6 @@ class Default(Subconstruct[SubconParsedType, SubconBuildTypes, ParsedType, Build class Check(Construct[ParsedType, BuildTypes]): func: ConstantOrContextLambda[bool] - def __new__( - cls, - func: ConstantOrContextLambda[bool], - ) -> Check[None, None]: ... def __init__( self: Check[None, None], func: ConstantOrContextLambda[bool], @@ -806,17 +637,6 @@ class NamedTuple( tuplename: str tuplefields: str factory: Construct[SubconParsedType, SubconBuildTypes] - def __new__( - cls, - tuplename: str, - tuplefields: str, - subcon: Construct[SubconParsedType, SubconBuildTypes], - ) -> NamedTuple[ - SubconParsedType, - SubconBuildTypes, - t.Tuple[t.Any, ...], - t.Union[t.Tuple[t.Any, ...], t.List[t.Any], t.Dict[str, t.Any]], - ]: ... def __init__( self: NamedTuple[ SubconParsedType, @@ -859,35 +679,6 @@ K = t.TypeVar("K") V = t.TypeVar("V") class Hex(Adapter[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]): - @t.overload - def __new__( - cls, subcon: Construct[int, BuildTypes] - ) -> Hex[int, BuildTypes, HexDisplayedInteger, BuildTypes]: ... - @t.overload - def __new__( - cls, subcon: Construct[bytes, BuildTypes] - ) -> Hex[bytes, BuildTypes, HexDisplayedBytes, BuildTypes]: ... - @t.overload - def __new__( - cls, subcon: Construct[RawCopyObj[SubconParsedType], BuildTypes] - ) -> Hex[ - RawCopyObj[SubconParsedType], - BuildTypes, - HexDisplayedDict[str, t.Union[int, bytes, SubconParsedType]], - BuildTypes, - ]: ... - @t.overload - def __new__( - cls, subcon: Construct[Container[t.Any], BuildTypes] - ) -> Hex[ - Container[t.Any], BuildTypes, HexDisplayedDict[str, t.Any], BuildTypes - ]: ... - @t.overload - def __new__( - cls, subcon: Construct[SubconParsedType, SubconBuildTypes] - ) -> Hex[ - SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes - ]: ... @t.overload def __init__( self: Hex[int, BuildTypes, HexDisplayedInteger, BuildTypes], @@ -924,31 +715,6 @@ class Hex(Adapter[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]): ) -> None: ... class HexDump(Adapter[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]): - @t.overload - def __new__( - cls, subcon: Construct[bytes, BuildTypes] - ) -> HexDump[bytes, BuildTypes, HexDumpDisplayedBytes, BuildTypes]: ... - @t.overload - def __new__( - cls, subcon: Construct[RawCopyObj[SubconParsedType], BuildTypes] - ) -> HexDump[ - RawCopyObj[SubconParsedType], - BuildTypes, - HexDumpDisplayedDict[str, t.Union[int, bytes, SubconParsedType]], - BuildTypes, - ]: ... - @t.overload - def __new__( - cls, subcon: Construct[Container[t.Any], BuildTypes] - ) -> HexDump[ - Container[t.Any], BuildTypes, HexDumpDisplayedDict[str, t.Any], BuildTypes - ]: ... - @t.overload - def __new__( - cls, subcon: Construct[SubconParsedType, SubconBuildTypes] - ) -> HexDump[ - SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes - ]: ... @t.overload def __init__( self: HexDump[bytes, BuildTypes, HexDumpDisplayedBytes, BuildTypes], @@ -998,11 +764,6 @@ class Union(Construct[Container[t.Any], t.Dict[str, t.Any]]): # this can maybe made better when variadic generics are available class Select(Construct[ParsedType, BuildTypes]): subcons: t.List[Construct[t.Any, t.Any]] - def __new__( - cls, - *subcons: Construct[t.Any, t.Any], - **subconskw: Construct[t.Any, t.Any], - ) -> Select[t.Any, t.Any]: ... def __init__( self: Select[t.Any, t.Any], *subcons: Construct[t.Any, t.Any], @@ -1018,23 +779,21 @@ ThenBuildTypes = t.TypeVar("ThenBuildTypes") ElseParsedType = t.TypeVar("ElseParsedType") ElseBuildTypes = t.TypeVar("ElseBuildTypes") -class IfThenElse(Construct[ParsedType, BuildTypes]): +class IfThenElse(Construct[t.Union[ThenParsedType, ElseParsedType], t.Union[ThenBuildTypes, ElseBuildTypes]]): condfunc: ConstantOrContextLambda[bool] - thensubcon: Construct[ParsedType, BuildTypes] - elsesubcon: Construct[ParsedType, BuildTypes] - def __new__( - cls, + thensubcon: Construct[ThenParsedType, ThenBuildTypes] + elsesubcon: Construct[ElseParsedType, ElseBuildTypes] + def __init__( + self: t.Self, condfunc: ConstantOrContextLambda[bool], thensubcon: Construct[ThenParsedType, ThenBuildTypes], elsesubcon: Construct[ElseParsedType, ElseBuildTypes], - ) -> IfThenElse[ - t.Union[ThenParsedType, ElseParsedType], t.Union[ThenBuildTypes, ElseBuildTypes] - ]: ... + ) -> None: ... def If( condfunc: ConstantOrContextLambda[bool], subcon: Construct[ThenParsedType, ThenBuildTypes], -) -> IfThenElse[t.Union[ThenParsedType, None], t.Union[ThenBuildTypes, None]]: ... +) -> IfThenElse[ThenParsedType, None, ThenBuildTypes, None]: ... SwitchType = t.TypeVar("SwitchType") @@ -1043,20 +802,6 @@ class Switch(Construct[ParsedType, BuildTypes]): cases: t.Dict[t.Any, Construct[t.Any, t.Any]] default: Construct[t.Any, t.Any] @t.overload - def __new__( - cls, - keyfunc: ConstantOrContextLambda[SwitchType], - cases: t.Dict[SwitchType, Construct[int, int]], - default: t.Optional[Construct[int, int]] = ..., - ) -> Switch[int, t.Optional[int]]: ... - @t.overload - def __new__( - cls, - keyfunc: ConstantOrContextLambda[t.Any], - cases: t.Dict[t.Any, Construct[t.Any, t.Any]], - default: t.Optional[Construct[t.Any, t.Any]] = ..., - ) -> Switch[t.Any, t.Any]: ... - @t.overload def __init__( self: Switch[int, t.Optional[int]], keyfunc: ConstantOrContextLambda[SwitchType], @@ -1071,14 +816,10 @@ class Switch(Construct[ParsedType, BuildTypes]): default: t.Optional[Construct[t.Any, t.Any]] = ..., ) -> None: ... -class StopIf(Construct[ParsedType, BuildTypes]): +class StopIf(Construct[None, None]): condfunc: ConstantOrContextLambda[bool] - def __new__( - cls, - condfunc: ConstantOrContextLambda[bool], - ) -> StopIf[None, None]: ... def __init__( - self: StopIf[None, None], + self: t.Self, condfunc: ConstantOrContextLambda[bool], ) -> None: ... @@ -1094,14 +835,8 @@ class Padded( ): length: ConstantOrContextLambda[int] pattern: bytes - def __new__( - cls, - length: ConstantOrContextLambda[int], - subcon: Construct[SubconParsedType, SubconBuildTypes], - pattern: bytes = ..., - ) -> Padded[SubconParsedType, SubconBuildTypes]: ... def __init__( - self, + self: t.Self, length: ConstantOrContextLambda[int], subcon: Construct[SubconParsedType, SubconBuildTypes], pattern: bytes = ..., @@ -1112,14 +847,8 @@ class Aligned( ): modulus: ConstantOrContextLambda[int] pattern: bytes - def __new__( - cls, - modulus: ConstantOrContextLambda[int], - subcon: Construct[SubconParsedType, SubconBuildTypes], - pattern: bytes = ..., - ) -> Aligned[SubconParsedType, SubconBuildTypes]: ... def __init__( - self, + self: t.Self, modulus: ConstantOrContextLambda[int], subcon: Construct[SubconParsedType, SubconBuildTypes], pattern: bytes = ..., @@ -1145,36 +874,16 @@ class Pointer( ): offset: ConstantOrContextLambda[int] stream: t.Optional[t.Callable[[Context], StreamType]] - def __new__( - cls, - offset: ConstantOrContextLambda[int], - subcon: Construct[SubconParsedType, SubconBuildTypes], - stream: t.Optional[t.Callable[[Context], StreamType]] = ..., - ) -> Pointer[SubconParsedType, SubconBuildTypes]: ... def __init__( - self, + self: t.Self, offset: ConstantOrContextLambda[int], subcon: Construct[SubconParsedType, SubconBuildTypes], stream: t.Optional[t.Callable[[Context], StreamType]] = ..., ) -> None: ... -class Peek(Subconstruct[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]): - def __new__( - cls, - subcon: Construct[SubconParsedType, SubconBuildTypes], - ) -> Peek[ - SubconParsedType, - SubconBuildTypes, - SubconParsedType, - t.Union[SubconBuildTypes, None], - ]: ... +class Peek(Subconstruct[SubconParsedType, SubconBuildTypes, SubconParsedType, t.Union[SubconBuildTypes, None]]): def __init__( - self: Peek[ - SubconParsedType, - SubconBuildTypes, - SubconParsedType, - t.Union[SubconBuildTypes, None], - ], + self: t.Self, subcon: Construct[SubconParsedType, SubconBuildTypes], ) -> None: ... @@ -1207,15 +916,6 @@ class RawCopyObj(t.Generic[ParsedType], Container[t.Any]): length: int class RawCopy(Subconstruct[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]): - def __new__( - cls, - subcon: Construct[SubconParsedType, SubconBuildTypes], - ) -> RawCopy[ - SubconParsedType, - SubconBuildTypes, - RawCopyObj[SubconParsedType], - t.Optional[t.Dict[str, t.Union[SubconBuildTypes, bytes]]], - ]: ... def __init__( self: RawCopy[ SubconParsedType, @@ -1241,14 +941,8 @@ class Prefixed( ): lengthfield: Construct[SubconParsedType, SubconBuildTypes] includelength: t.Optional[bool] - def __new__( - cls, - lengthfield: Construct[int, int], - subcon: Construct[SubconParsedType, SubconBuildTypes], - includelength: t.Optional[bool] = ..., - ) -> Prefixed[SubconParsedType, SubconBuildTypes]: ... def __init__( - self, + self: t.Self, lengthfield: Construct[int, int], subcon: Construct[SubconParsedType, SubconBuildTypes], includelength: t.Optional[bool] = ..., @@ -1268,13 +962,8 @@ class FixedSized( Subconstruct[SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes] ): length: ConstantOrContextLambda[int] - def __new__( - cls, - length: ConstantOrContextLambda[int], - subcon: Construct[SubconParsedType, SubconBuildTypes], - ) -> FixedSized[SubconParsedType, SubconBuildTypes]: ... def __init__( - self, + self: t.Self, length: ConstantOrContextLambda[int], subcon: Construct[SubconParsedType, SubconBuildTypes], ) -> None: ... @@ -1286,16 +975,8 @@ class NullTerminated( include: t.Optional[bool] consume: t.Optional[bool] require: t.Optional[bool] - def __new__( - cls, - subcon: Construct[SubconParsedType, SubconBuildTypes], - term: bytes = ..., - include: t.Optional[bool] = ..., - consume: t.Optional[bool] = ..., - require: t.Optional[bool] = ..., - ) -> NullTerminated[SubconParsedType, SubconBuildTypes]: ... def __init__( - self, + self: t.Self, subcon: Construct[SubconParsedType, SubconBuildTypes], term: bytes = ..., include: t.Optional[bool] = ..., @@ -1307,11 +988,8 @@ class NullStripped( Subconstruct[SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes] ): pad: bytes - def __new__( - cls, subcon: Construct[SubconParsedType, SubconBuildTypes], pad: bytes = ... - ) -> NullStripped[SubconParsedType, SubconBuildTypes]: ... def __init__( - self, subcon: Construct[SubconParsedType, SubconBuildTypes], pad: bytes = ... + self: t.Self, subcon: Construct[SubconParsedType, SubconBuildTypes], pad: bytes = ... ) -> None: ... class RestreamData( @@ -1320,15 +998,8 @@ class RestreamData( datafunc: t.Union[ bytes, io.BytesIO, Construct[bytes, t.Any], t.Callable[[Context], bytes] ] - def __new__( - cls, - datafunc: t.Union[ - bytes, io.BytesIO, Construct[bytes, t.Any], t.Callable[[Context], bytes] - ], - subcon: Construct[SubconParsedType, SubconBuildTypes], - ) -> RestreamData[SubconParsedType, SubconBuildTypes]: ... def __init__( - self, + self: t.Self, datafunc: t.Union[ bytes, io.BytesIO, Construct[bytes, t.Any], t.Callable[[Context], bytes] ], @@ -1342,16 +1013,8 @@ class Transformed( decodeamount: t.Optional[int] encodefunc: t.Callable[[bytes], bytes] encodeamount: t.Optional[int] - def __new__( - cls, - subcon: Construct[SubconParsedType, SubconBuildTypes], - decodefunc: t.Callable[[bytes], bytes], - decodeamount: t.Optional[int], - encodefunc: t.Callable[[bytes], bytes], - encodeamount: t.Optional[int], - ) -> Transformed[SubconParsedType, SubconBuildTypes]: ... def __init__( - self, + self: t.Self, subcon: Construct[SubconParsedType, SubconBuildTypes], decodefunc: t.Callable[[bytes], bytes], decodeamount: t.Optional[int], @@ -1367,17 +1030,8 @@ class Restreamed( encoder: t.Callable[[bytes], bytes] encoderunit: int sizecomputer: t.Callable[[int], int] - def __new__( - cls, - subcon: Construct[SubconParsedType, SubconBuildTypes], - decoder: t.Callable[[bytes], bytes], - decoderunit: int, - encoder: t.Callable[[bytes], bytes], - encoderunit: int, - sizecomputer: t.Callable[[int], int], - ) -> Restreamed[SubconParsedType, SubconBuildTypes]: ... def __init__( - self, + self: t.Self, subcon: Construct[SubconParsedType, SubconBuildTypes], decoder: t.Callable[[bytes], bytes], decoderunit: int, @@ -1390,13 +1044,8 @@ class ProcessXor( Subconstruct[SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes] ): padfunc: ConstantOrContextLambda2[t.Union[int, bytes]] - def __new__( - cls, - padfunc: ConstantOrContextLambda2[t.Union[int, bytes]], - subcon: Construct[SubconParsedType, SubconBuildTypes], - ) -> ProcessXor[SubconParsedType, SubconBuildTypes]: ... def __init__( - self: ProcessXor[SubconParsedType, SubconBuildTypes], + self: t.Self, padfunc: ConstantOrContextLambda2[t.Union[int, bytes]], subcon: Construct[SubconParsedType, SubconBuildTypes], ) -> None: ... @@ -1406,14 +1055,8 @@ class ProcessRotateLeft( ): amount: ConstantOrContextLambda2[int] group: ConstantOrContextLambda2[int] - def __new__( - cls, - amount: ConstantOrContextLambda2[int], - group: ConstantOrContextLambda2[int], - subcon: Construct[SubconParsedType, SubconBuildTypes], - ) -> ProcessRotateLeft[SubconParsedType, SubconBuildTypes]: ... def __init__( - self: ProcessRotateLeft[SubconParsedType, SubconBuildTypes], + self: t.Self, amount: ConstantOrContextLambda2[int], group: ConstantOrContextLambda2[int], subcon: Construct[SubconParsedType, SubconBuildTypes], @@ -1436,14 +1079,8 @@ class Compressed(Tunnel[SubconParsedType, SubconBuildTypes]): encoding: str level: t.Optional[int] lib: t.Any - def __new__( - cls, - subcon: Construct[SubconParsedType, SubconBuildTypes], - encoding: str, - level: t.Optional[int] = ..., - ) -> Compressed[SubconParsedType, SubconBuildTypes]: ... def __init__( - self, + self: t.Self, subcon: Construct[SubconParsedType, SubconBuildTypes], encoding: str, level: t.Optional[int] = ..., @@ -1451,12 +1088,8 @@ class Compressed(Tunnel[SubconParsedType, SubconBuildTypes]): class CompressedLZ4(Tunnel[SubconParsedType, SubconBuildTypes]): lib: t.Any - def __new__( - cls, - subcon: Construct[SubconParsedType, SubconBuildTypes], - ) -> CompressedLZ4[SubconParsedType, SubconBuildTypes]: ... def __init__( - self, + self: t.Self, subcon: Construct[SubconParsedType, SubconBuildTypes], ) -> None: ... @@ -1464,13 +1097,8 @@ class Rebuffered( Subconstruct[SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes] ): stream2: RebufferedBytesIO - def __new__( - cls, - subcon: Construct[SubconParsedType, SubconBuildTypes], - tailcutoff: t.Optional[int] = ..., - ) -> Rebuffered[SubconParsedType, SubconBuildTypes]: ... def __init__( - self, + self: t.Self, subcon: Construct[SubconParsedType, SubconBuildTypes], tailcutoff: t.Optional[int] = ..., ) -> None: ... @@ -1479,15 +1107,6 @@ class Rebuffered( # lazy equivalents # =============================================================================== class Lazy(Subconstruct[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]): - def __new__( - cls, - subcon: Construct[SubconParsedType, SubconBuildTypes], - ) -> Lazy[ - SubconParsedType, - SubconBuildTypes, - t.Callable[[], SubconParsedType], - t.Union[t.Callable[[], SubconParsedType], SubconParsedType], - ]: ... def __init__( self: Lazy[ SubconParsedType, @@ -1509,11 +1128,6 @@ class LazyStruct(Construct[ParsedType, BuildTypes]): subcons: t.List[Construct[t.Any, t.Any]] _subcons: t.Dict[str, Construct[t.Any, t.Any]] _subconsindexes: t.Dict[str, int] - def __new__( - cls, - *subcons: Construct[t.Any, t.Any], - **subconskw: Construct[t.Any, t.Any], - ) -> LazyStruct[LazyContainer[t.Any], t.Optional[t.Dict[str, t.Any]]]: ... def __init__( self: LazyStruct[LazyContainer[t.Any], t.Optional[t.Dict[str, t.Any]]], *subcons: Construct[t.Any, t.Any], @@ -1532,16 +1146,6 @@ class LazyArray( ] ): count: ConstantOrContextLambda[int] - def __new__( - cls, - count: ConstantOrContextLambda[int], - subcon: Construct[SubconParsedType, SubconBuildTypes], - ) -> LazyArray[ - SubconParsedType, - SubconBuildTypes, - ListContainer[SubconParsedType], - t.List[SubconBuildTypes], - ]: ... def __init__( self: LazyArray[ SubconParsedType, @@ -1555,10 +1159,6 @@ class LazyArray( class LazyBound(Construct[ParsedType, BuildTypes]): subconfunc: t.Callable[[], Construct[ParsedType, BuildTypes]] - def __new__( - cls, - subconfunc: t.Callable[[], Construct[ParsedType, BuildTypes]], - ) -> LazyBound[ParsedType, BuildTypes]: ... def __init__( self: LazyBound[ParsedType, BuildTypes], subconfunc: t.Callable[[], Construct[ParsedType, BuildTypes]], @@ -1568,12 +1168,6 @@ class LazyBound(Construct[ParsedType, BuildTypes]): # adapters and validators # =============================================================================== class ExprAdapter(Adapter[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]): - def __new__( - cls, - subcon: Construct[SubconParsedType, SubconBuildTypes], - decoder: t.Callable[[SubconParsedType, Context], ParsedType], - encoder: t.Callable[[BuildTypes, Context], SubconBuildTypes], - ) -> ExprAdapter[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]: ... def __init__( self, subcon: Construct[SubconParsedType, SubconBuildTypes], @@ -1584,11 +1178,6 @@ class ExprAdapter(Adapter[SubconParsedType, SubconBuildTypes, ParsedType, BuildT class ExprSymmetricAdapter( ExprAdapter[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes] ): - def __new__( - cls, - subcon: Construct[SubconParsedType, SubconBuildTypes], - encoder: t.Callable[[BuildTypes, Context], SubconBuildTypes], - ) -> ExprSymmetricAdapter[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]: ... def __init__( self, subcon: Construct[SubconParsedType, SubconBuildTypes], @@ -1596,11 +1185,6 @@ class ExprSymmetricAdapter( ) -> None: ... class ExprValidator(Validator[SubconParsedType, SubconBuildTypes]): - def __new__( - cls, - subcon: Construct[SubconParsedType, SubconBuildTypes], - validator: t.Callable[[SubconParsedType, Context], bool], - ) -> ExprValidator[SubconParsedType, SubconBuildTypes]: ... def __init__( self, subcon: Construct[SubconParsedType, SubconBuildTypes], @@ -1625,28 +1209,6 @@ def Filter( class Slicing( Adapter[SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes] ): - def __new__( - cls, - subcon: t.Union[ - Array[ - SubconParsedType, - SubconBuildTypes, - ListContainer[SubconParsedType], - t.List[SubconBuildTypes], - ], - GreedyRange[ - SubconParsedType, - SubconBuildTypes, - ListContainer[SubconParsedType], - t.List[SubconBuildTypes], - ], - ], - count: int, - start: t.Optional[int], - stop: t.Optional[int], - step: int = ..., - empty: t.Optional[SubconParsedType] = ..., - ) -> Slicing[ListContainer[SubconParsedType], t.List[SubconBuildTypes]]: ... def __init__( self: Slicing[ListContainer[SubconParsedType], t.List[SubconBuildTypes]], subcon: t.Union[ @@ -1673,26 +1235,6 @@ class Slicing( class Indexing( Adapter[SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes] ): - def __new__( - cls, - subcon: t.Union[ - Array[ - SubconParsedType, - SubconBuildTypes, - ListContainer[SubconParsedType], - t.List[SubconBuildTypes], - ], - GreedyRange[ - SubconParsedType, - SubconBuildTypes, - ListContainer[SubconParsedType], - t.List[SubconBuildTypes], - ], - ], - count: int, - index: int, - empty: t.Optional[SubconParsedType] = ..., - ) -> Indexing[SubconParsedType, SubconBuildTypes]: ... def __init__( self, subcon: t.Union[ diff --git a/construct_typed/dataclass_struct.py b/construct_typed/dataclass_struct.py index 6ecae05..f79fc7e 100644 --- a/construct_typed/dataclass_struct.py +++ b/construct_typed/dataclass_struct.py @@ -152,7 +152,7 @@ class DataclassStruct(Adapter[t.Any, t.Any, DataclassType, DataclassType]): Image(width=1, height=2, pixels=b'12') """ - subcon: "cs.Struct[t.Any, t.Any]" + subcon: "cs.Struct" if t.TYPE_CHECKING: def __new__( From 1e7ced992d6c4e97622f0ec31b75a4e845f47fae Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Tue, 18 Jul 2023 15:38:01 +0200 Subject: [PATCH 03/42] removed all self type annotations of __init__ methods --- construct-stubs/core.pyi | 625 ++++++++++++++++++--------------------- 1 file changed, 294 insertions(+), 331 deletions(-) diff --git a/construct-stubs/core.pyi b/construct-stubs/core.pyi index d3b46fa..a19686b 100644 --- a/construct-stubs/core.pyi +++ b/construct-stubs/core.pyi @@ -25,6 +25,10 @@ from construct.lib import ( # - Higher Kinded Types: https://github.com/python/typing/issues/548 # - Higher Kinded Types: https://sobolevn.me/2020/10/higher-kinded-types-in-python +# unfortunalty the static type checkers "pyright" and "mypy" are slight different. pyright is not fully analysing the type hint of the +# self type in the __init__ (eg. self: Construct[int, int] is not working). but pyright would support such type hints of the return type +# of __new__. indeed mypy doens not support the type inference for the method __new__, but fully supports the annotation of self in __init__... + StreamType = t.IO[bytes] FilenameType = t.Union[str, bytes, os.PathLike[str], os.PathLike[bytes]] PathType = str @@ -129,20 +133,11 @@ class Construct(t.Generic[ParsedType, BuildTypes]): self, other: t.Union[str, bytes, t.Callable[[ParsedType, Context], None]], ) -> Renamed[ParsedType, BuildTypes]: ... - def __add__( - self, other: Construct[t.Any, t.Any] - ) -> Struct[Container[t.Any], t.Optional[t.Dict[str, t.Any]]]: ... - def __rshift__( - self, other: Construct[t.Any, t.Any] - ) -> Sequence[ListContainer[t.Any], t.Optional[t.List[t.Any]]]: ... + def __add__(self, other: Construct[t.Any, t.Any]) -> Struct: ... + def __rshift__(self, other: Construct[t.Any, t.Any]) -> Sequence: ... def __getitem__( self, count: t.Union[int, t.Callable[[Context], int]] - ) -> Array[ - ParsedType, - BuildTypes, - ListContainer[ParsedType], - t.List[BuildTypes], - ]: ... + ) -> Array[ParsedType, BuildTypes,]: ... @t.type_check_only class Context(Container[t.Any]): @@ -170,12 +165,12 @@ class Subconstruct( subcon: Construct[SubconParsedType, SubconBuildTypes] @t.overload def __init__( - self: t.Self, + self, subcon: Construct[SubconParsedType, SubconBuildTypes], ) -> None: ... @t.overload def __init__( - self: t.Self, + self, *args: t.Any, **kwargs: t.Any, ) -> None: ... @@ -184,7 +179,7 @@ class Adapter( Subconstruct[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes], ): def __init__( - self: t.Self, subcon: Construct[SubconParsedType, SubconBuildTypes] + self, subcon: Construct[SubconParsedType, SubconBuildTypes] ) -> None: ... def _decode( self, obj: SubconBuildTypes, context: Context, path: PathType @@ -217,10 +212,10 @@ class Tunnel( # =============================================================================== # bytes and bits # =============================================================================== -class Bytes(Construct[ParsedType, BuildTypes]): +class Bytes(Construct[bytes, t.Union[bytes, int]]): length: ConstantOrContextLambda[int] def __init__( - self: Bytes[bytes, t.Union[bytes, int]], + self, length: ConstantOrContextLambda[int], ) -> None: ... @@ -242,121 +237,118 @@ def Bytewise( # =============================================================================== # integers and floats # =============================================================================== -class FormatField(Construct[ParsedType, BuildTypes]): +class _FormatField(Construct[ParsedType, BuildTypes]): fmtstr: str length: int - if sys.version_info >= (3, 8): - ENDIANITY = t.Union[t.Literal["=", "<", ">"], str] - FORMAT_INT = t.Literal["B", "H", "L", "Q", "b", "h", "l", "q"] - FORMAT_FLOAT = t.Literal["f", "d", "e"] - FORMAT_BOOL = t.Literal["?"] - @t.overload - def __init__( - self: FormatField[int, int], - endianity: str, - format: FORMAT_INT, - ) -> None: ... - @t.overload - def __init__( - self: FormatField[float, float], - endianity: str, - format: FORMAT_FLOAT, - ) -> None: ... - @t.overload - def __init__( - self: FormatField[bool, bool], - endianity: str, - format: FORMAT_BOOL, - ) -> None: ... - @t.overload - def __init__( - self: FormatField[t.Any, t.Any], - endianity: str, - format: str, - ) -> None: ... - else: - def __init__( - self: FormatField[t.Any, t.Any], - endianity: str, - format: str, - ) -> None: ... -class BytesInteger(Construct[ParsedType, BuildTypes]): +if sys.version_info >= (3, 8): + ENDIANITY = t.Union[t.Literal["=", "<", ">"], str] + FORMAT_INT = t.Literal["B", "H", "L", "Q", "b", "h", "l", "q"] + FORMAT_FLOAT = t.Literal["f", "d", "e"] + FORMAT_BOOL = t.Literal["?"] + @t.overload + def FormatField( + endianity: str, + format: FORMAT_INT, + ) -> _FormatField[int, int]: ... + @t.overload + def FormatField( + endianity: str, + format: FORMAT_FLOAT, + ) -> _FormatField[float, float]: ... + @t.overload + def FormatField( + endianity: str, + format: FORMAT_BOOL, + ) -> _FormatField[bool, bool]: ... + @t.overload + def FormatField( + endianity: str, + format: str, + ) -> _FormatField[t.Any, t.Any]: ... + +else: + def FormatField( + endianity: str, + format: str, + ) -> _FormatField[t.Any, t.Any]: ... + +class BytesInteger(Construct[int, int]): length: ConstantOrContextLambda[int] signed: bool swapped: ConstantOrContextLambda[bool] def __init__( - self: BytesInteger[int, int], + self, length: ConstantOrContextLambda[int], signed: bool = ..., swapped: ConstantOrContextLambda[bool] = ..., ) -> None: ... -class BitsInteger(Construct[ParsedType, BuildTypes]): +class BitsInteger(Construct[int, int]): length: ConstantOrContextLambda[int] signed: bool swapped: ConstantOrContextLambda[bool] def __init__( - self: BitsInteger[int, int], + self, length: ConstantOrContextLambda[int], signed: bool = ..., swapped: ConstantOrContextLambda[bool] = ..., ) -> None: ... -Bit: BitsInteger[int, int] -Nibble: BitsInteger[int, int] -Octet: BitsInteger[int, int] +Bit: BitsInteger +Nibble: BitsInteger +Octet: BitsInteger -Int8ub: FormatField[int, int] -Int16ub: FormatField[int, int] -Int32ub: FormatField[int, int] -Int64ub: FormatField[int, int] -Int8sb: FormatField[int, int] -Int16sb: FormatField[int, int] -Int32sb: FormatField[int, int] -Int64sb: FormatField[int, int] -Int8ul: FormatField[int, int] -Int16ul: FormatField[int, int] -Int32ul: FormatField[int, int] -Int64ul: FormatField[int, int] -Int8sl: FormatField[int, int] -Int16sl: FormatField[int, int] -Int32sl: FormatField[int, int] -Int64sl: FormatField[int, int] -Int8un: FormatField[int, int] -Int16un: FormatField[int, int] -Int32un: FormatField[int, int] -Int64un: FormatField[int, int] -Int8sn: FormatField[int, int] -Int16sn: FormatField[int, int] -Int32sn: FormatField[int, int] -Int64sn: FormatField[int, int] +Int8ub: _FormatField[int, int] +Int16ub: _FormatField[int, int] +Int32ub: _FormatField[int, int] +Int64ub: _FormatField[int, int] +Int8sb: _FormatField[int, int] +Int16sb: _FormatField[int, int] +Int32sb: _FormatField[int, int] +Int64sb: _FormatField[int, int] +Int8ul: _FormatField[int, int] +Int16ul: _FormatField[int, int] +Int32ul: _FormatField[int, int] +Int64ul: _FormatField[int, int] +Int8sl: _FormatField[int, int] +Int16sl: _FormatField[int, int] +Int32sl: _FormatField[int, int] +Int64sl: _FormatField[int, int] +Int8un: _FormatField[int, int] +Int16un: _FormatField[int, int] +Int32un: _FormatField[int, int] +Int64un: _FormatField[int, int] +Int8sn: _FormatField[int, int] +Int16sn: _FormatField[int, int] +Int32sn: _FormatField[int, int] +Int64sn: _FormatField[int, int] -Byte: FormatField[int, int] -Short: FormatField[int, int] -Int: FormatField[int, int] -Long: FormatField[int, int] +Byte: _FormatField[int, int] +Short: _FormatField[int, int] +Int: _FormatField[int, int] +Long: _FormatField[int, int] -Float16b: FormatField[float, float] -Float16l: FormatField[float, float] -Float16n: FormatField[float, float] -Float32b: FormatField[float, float] -Float32l: FormatField[float, float] -Float32n: FormatField[float, float] -Float64b: FormatField[float, float] -Float64l: FormatField[float, float] -Float64n: FormatField[float, float] +Float16b: _FormatField[float, float] +Float16l: _FormatField[float, float] +Float16n: _FormatField[float, float] +Float32b: _FormatField[float, float] +Float32l: _FormatField[float, float] +Float32n: _FormatField[float, float] +Float64b: _FormatField[float, float] +Float64l: _FormatField[float, float] +Float64n: _FormatField[float, float] -Half: FormatField[float, float] -Single: FormatField[float, float] -Double: FormatField[float, float] +Half: _FormatField[float, float] +Single: _FormatField[float, float] +Double: _FormatField[float, float] -Int24ub: BytesInteger[int, int] -Int24ul: BytesInteger[int, int] -Int24un: BytesInteger[int, int] -Int24sb: BytesInteger[int, int] -Int24sl: BytesInteger[int, int] -Int24sn: BytesInteger[int, int] +Int24ub: BytesInteger +Int24ul: BytesInteger +Int24un: BytesInteger +Int24sb: BytesInteger +Int24sl: BytesInteger +Int24sn: BytesInteger VarInt: Construct[int, int] ZigZag: Construct[int, int] @@ -364,7 +356,7 @@ ZigZag: Construct[int, int] # =============================================================================== # strings # =============================================================================== -class StringEncoded(Construct[ParsedType, BuildTypes]): +class StringEncoded(Construct[str, str]): if sys.version_info >= (3, 8): ENCODING_1 = t.Literal["ascii", "utf8", "utf_8", "u8"] ENCODING_2 = t.Literal["utf16", "utf_16", "u16", "utf_16_be", "utf_16_le"] @@ -374,19 +366,19 @@ class StringEncoded(Construct[ParsedType, BuildTypes]): ENCODING = str encoding: ENCODING def __init__( - self: StringEncoded[str, str], - subcon: Construct[ParsedType, BuildTypes], + self, + subcon: Construct[bytes, bytes], encoding: ENCODING, ) -> None: ... def PaddedString( length: ConstantOrContextLambda[int], encoding: StringEncoded.ENCODING -) -> StringEncoded[str, str]: ... +) -> StringEncoded: ... def PascalString( lengthfield: Construct[int, int], encoding: StringEncoded.ENCODING -) -> StringEncoded[str, str]: ... -def CString(encoding: StringEncoded.ENCODING) -> StringEncoded[str, str]: ... -def GreedyString(encoding: StringEncoded.ENCODING) -> StringEncoded[str, str]: ... +) -> StringEncoded: ... +def CString(encoding: StringEncoded.ENCODING) -> StringEncoded: ... +def GreedyString(encoding: StringEncoded.ENCODING) -> StringEncoded: ... # =============================================================================== # mappings @@ -399,12 +391,14 @@ class EnumIntegerString(str): @staticmethod def new(intvalue: int, stringvalue: str) -> EnumIntegerString: ... -class Enum(Adapter[int, int, t.Union[EnumInteger, EnumIntegerString], t.Union[int, str]]): +class Enum( + Adapter[int, int, t.Union[EnumInteger, EnumIntegerString], t.Union[int, str]] +): encmapping: t.Dict[str, int] decmapping: t.Dict[int, EnumIntegerString] ksymapping: t.Dict[int, str] def __init__( - self: t.Self, + self, subcon: Construct[int, int], *merge: t.Union[t.Type[enum.IntEnum], t.Type[enum.IntFlag]], **mapping: int, @@ -414,11 +408,13 @@ class Enum(Adapter[int, int, t.Union[EnumInteger, EnumIntegerString], t.Union[in class BitwisableString(str): def __or__(self, other: BitwisableString) -> BitwisableString: ... -class FlagsEnum(Adapter[int, int, Container[bool], t.Union[int, str, t.Dict[str, bool]]]): +class FlagsEnum( + Adapter[int, int, Container[bool], t.Union[int, str, t.Dict[str, bool]]] +): flags: t.Dict[str, int] reverseflags: t.Dict[int, str] def __init__( - self: t.Self, + self, subcon: Construct[int, int], *merge: t.Union[t.Type[enum.IntEnum], t.Type[enum.IntFlag]], **flags: int, @@ -429,7 +425,7 @@ class Mapping(Adapter[SubconParsedType, SubconBuildTypes, t.Any, t.Any]): decmapping: t.Dict[int, str] encmapping: t.Dict[str, int] def __init__( - self: t.Self, + self, subcon: Construct[SubconParsedType, SubconBuildTypes], mapping: t.Dict[t.Any, t.Any], ) -> None: ... @@ -442,7 +438,7 @@ class Struct(Construct[Container[t.Any], t.Optional[t.Dict[str, t.Any]]]): subcons: t.List[Construct[t.Any, t.Any]] _subcons: t.Dict[str, Construct[t.Any, t.Any]] def __init__( - self: t.Self, + self, *subcons: Construct[t.Any, t.Any], **subconskw: Construct[t.Any, t.Any], ) -> None: ... @@ -453,7 +449,7 @@ class Sequence(Construct[ListContainer[t.Any], t.Optional[t.List[t.Any]]]): subcons: t.List[Construct[t.Any, t.Any]] _subcons: t.Dict[str, Construct[t.Any, t.Any]] def __init__( - self: t.Self, + self, *subcons: Construct[t.Any, t.Any], **subconskw: Construct[t.Any, t.Any], ) -> None: ... @@ -466,19 +462,14 @@ class Array( Subconstruct[ SubconParsedType, SubconBuildTypes, - ParsedType, - BuildTypes, + ListContainer[SubconParsedType], # type: ignore + t.List[SubconBuildTypes], # type: ignore ] ): count: ConstantOrContextLambda[int] discard: bool def __init__( - self: Array[ - SubconParsedType, - SubconBuildTypes, - ListContainer[SubconParsedType], - t.List[SubconBuildTypes], - ], + self, count: ConstantOrContextLambda[int], subcon: Construct[SubconParsedType, SubconBuildTypes], discard: bool = ..., @@ -488,18 +479,13 @@ class GreedyRange( Subconstruct[ SubconParsedType, SubconBuildTypes, - ParsedType, - BuildTypes, + ListContainer[SubconParsedType], # type: ignore + t.List[SubconBuildTypes], # type: ignore ] ): discard: bool def __init__( - self: GreedyRange[ - SubconParsedType, - SubconBuildTypes, - ListContainer[SubconParsedType], - t.List[SubconBuildTypes], - ], + self, subcon: Construct[SubconParsedType, SubconBuildTypes], discard: bool = ..., ) -> None: ... @@ -508,8 +494,8 @@ class RepeatUntil( Subconstruct[ SubconParsedType, SubconBuildTypes, - ParsedType, - BuildTypes, + ListContainer[SubconParsedType], # type: ignore + t.List[SubconBuildTypes], # type: ignore ] ): predicate: t.Union[ @@ -518,12 +504,7 @@ class RepeatUntil( ] discard: bool def __init__( - self: RepeatUntil[ - SubconParsedType, - SubconBuildTypes, - ListContainer[SubconParsedType], - t.List[SubconBuildTypes], - ], + self, predicate: t.Union[ bool, t.Callable[ @@ -541,7 +522,7 @@ class Renamed( Subconstruct[SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes] ): def __init__( - self: t.Self, + self, subcon: Construct[SubconParsedType, SubconBuildTypes], newname: t.Optional[str] = ..., newdocs: t.Optional[str] = ..., @@ -551,61 +532,54 @@ class Renamed( # =============================================================================== # miscellaneous # =============================================================================== -class Const(Subconstruct[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]): - value: SubconBuildTypes - @t.overload - def __init__( - self: Const[None, None, bytes, t.Optional[bytes]], - value: bytes, - ) -> None: ... - @t.overload - def __init__( - self: Const[None, None, SubconParsedType, t.Optional[SubconBuildTypes]], - value: SubconBuildTypes, - subcon: Construct[SubconParsedType, SubconBuildTypes], - ) -> None: ... - +class _Const(Subconstruct[None, None, SubconParsedType, SubconBuildTypes]): ... -class Computed(Construct[ParsedType, BuildTypes]): +@t.overload +def Const( + value: bytes, +) -> _Const[bytes, t.Optional[bytes]]: ... +@t.overload +def Const( + value: SubconBuildTypes, + subcon: Construct[SubconParsedType, SubconBuildTypes], +) -> _Const[SubconParsedType, t.Optional[SubconBuildTypes]]: ... + +class Computed(Construct[ParsedType, None]): func: ConstantOrContextLambda2[ParsedType] - @t.overload def __init__( - self: Computed[ParsedType, None], + self, func: ConstantOrContextLambda2[ParsedType], ) -> None: ... - @t.overload - def __init__( - self: Computed[t.Any, None], - func: ConstantOrContextLambda2[t.Any], - ) -> None: ... Index: Construct[int, t.Any] -class Rebuild(Subconstruct[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]): +class Rebuild(Subconstruct[SubconParsedType, SubconBuildTypes, SubconParsedType, None]): func: ConstantOrContextLambda[SubconBuildTypes] def __init__( - self: Rebuild[SubconParsedType, SubconBuildTypes, SubconParsedType, None], + self, subcon: Construct[SubconParsedType, SubconBuildTypes], func: ConstantOrContextLambda[SubconBuildTypes], ) -> None: ... -class Default(Subconstruct[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]): +class Default( + Subconstruct[ + SubconParsedType, + SubconBuildTypes, + SubconParsedType, + t.Optional[SubconBuildTypes], + ] +): value: ConstantOrContextLambda[SubconBuildTypes] def __init__( - self: Default[ - SubconParsedType, - SubconBuildTypes, - SubconParsedType, - t.Optional[SubconBuildTypes], - ], + self, subcon: Construct[SubconParsedType, SubconBuildTypes], value: ConstantOrContextLambda[SubconBuildTypes], ) -> None: ... -class Check(Construct[ParsedType, BuildTypes]): +class Check(Construct[None, None]): func: ConstantOrContextLambda[bool] def __init__( - self: Check[None, None], + self, func: ConstantOrContextLambda[bool], ) -> None: ... @@ -630,20 +604,15 @@ class NamedTuple( Adapter[ SubconParsedType, SubconBuildTypes, - ParsedType, - BuildTypes, + t.Tuple[t.Any, ...], + t.Union[t.Tuple[t.Any, ...], t.List[t.Any], t.Dict[str, t.Any]], ] ): tuplename: str tuplefields: str factory: Construct[SubconParsedType, SubconBuildTypes] def __init__( - self: NamedTuple[ - SubconParsedType, - SubconBuildTypes, - t.Tuple[t.Any, ...], - t.Union[t.Tuple[t.Any, ...], t.List[t.Any], t.Dict[str, t.Any]], - ], + self, tuplename: str, tuplefields: str, subcon: Construct[SubconParsedType, SubconBuildTypes], @@ -678,72 +647,63 @@ def Timestamp( K = t.TypeVar("K") V = t.TypeVar("V") -class Hex(Adapter[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]): - @t.overload - def __init__( - self: Hex[int, BuildTypes, HexDisplayedInteger, BuildTypes], - subcon: Construct[int, BuildTypes], - ) -> None: ... - @t.overload - def __init__( - self: Hex[bytes, BuildTypes, HexDisplayedBytes, BuildTypes], - subcon: Construct[bytes, BuildTypes], - ) -> None: ... - @t.overload - def __init__( - self: Hex[ - RawCopyObj[SubconParsedType], - BuildTypes, - HexDisplayedDict[str, t.Union[int, bytes, SubconParsedType]], - BuildTypes, - ], - subcon: Construct[RawCopyObj[SubconParsedType], BuildTypes], - ) -> None: ... - @t.overload - def __init__( - self: Hex[ - Container[t.Any], BuildTypes, HexDisplayedDict[str, t.Any], BuildTypes - ], - subcon: Construct[Container[t.Any], BuildTypes], - ) -> None: ... - @t.overload - def __init__( - self: Hex[ - SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes - ], - subcon: Construct[SubconParsedType, SubconBuildTypes], - ) -> None: ... +class _Hex(Adapter[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]): + pass -class HexDump(Adapter[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]): - @t.overload - def __init__( - self: HexDump[bytes, BuildTypes, HexDumpDisplayedBytes, BuildTypes], - subcon: Construct[bytes, BuildTypes], - ) -> None: ... - @t.overload - def __init__( - self: HexDump[ - RawCopyObj[SubconParsedType], - BuildTypes, - HexDumpDisplayedDict[str, t.Union[int, bytes, SubconParsedType]], - BuildTypes, - ], - subcon: Construct[RawCopyObj[SubconParsedType], BuildTypes], - ) -> None: ... - @t.overload - def __init__( - self: HexDump[ - Container[t.Any], BuildTypes, HexDumpDisplayedDict[str, t.Any], BuildTypes - ], - subcon: Construct[Container[t.Any], BuildTypes], - ) -> None: ... - @t.overload - def __init__( - self: HexDump[ - SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes - ], - subcon: Construct[SubconParsedType, SubconBuildTypes], - ) -> None: ... +@t.overload +def Hex( + subcon: Construct[int, BuildTypes], +) -> _Hex[int, BuildTypes, HexDisplayedInteger, BuildTypes]: ... +@t.overload +def Hex( + subcon: Construct[bytes, BuildTypes], +) -> _Hex[bytes, BuildTypes, HexDisplayedBytes, BuildTypes]: ... +@t.overload +def Hex( + subcon: Construct[RawCopyObj[SubconParsedType], BuildTypes], +) -> _Hex[ + RawCopyObj[SubconParsedType], + BuildTypes, + HexDisplayedDict[str, t.Union[int, bytes, SubconParsedType]], + BuildTypes, +]: ... +@t.overload +def Hex( + subcon: Construct[Container[t.Any], BuildTypes], +) -> _Hex[Container[t.Any], BuildTypes, HexDisplayedDict[str, t.Any], BuildTypes]: ... +@t.overload +def Hex( + subcon: Construct[SubconParsedType, SubconBuildTypes], +) -> _Hex[SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes]: ... + +class _HexDump(Adapter[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]): + pass + +@t.overload +def HexDump( + subcon: Construct[bytes, BuildTypes], +) -> _HexDump[bytes, BuildTypes, HexDumpDisplayedBytes, BuildTypes]: ... +@t.overload +def HexDump( + subcon: Construct[RawCopyObj[SubconParsedType], BuildTypes], +) -> _HexDump[ + RawCopyObj[SubconParsedType], + BuildTypes, + HexDumpDisplayedDict[str, t.Union[int, bytes, SubconParsedType]], + BuildTypes, +]: ... +@t.overload +def HexDump( + subcon: Construct[Container[t.Any], BuildTypes], +) -> _HexDump[ + Container[t.Any], BuildTypes, HexDumpDisplayedDict[str, t.Any], BuildTypes +]: ... +@t.overload +def HexDump( + subcon: Construct[SubconParsedType, SubconBuildTypes], +) -> _HexDump[ + SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes +]: ... # =============================================================================== # conditional @@ -762,29 +722,33 @@ class Union(Construct[Container[t.Any], t.Dict[str, t.Any]]): def __getattr__(self, name: str) -> t.Any: ... # this can maybe made better when variadic generics are available -class Select(Construct[ParsedType, BuildTypes]): +class Select(Construct[t.Any, t.Any]): subcons: t.List[Construct[t.Any, t.Any]] def __init__( - self: Select[t.Any, t.Any], + self, *subcons: Construct[t.Any, t.Any], **subconskw: Construct[t.Any, t.Any], ) -> None: ... def Optional( subcon: Construct[SubconParsedType, SubconBuildTypes] -) -> Select[t.Union[SubconParsedType, None], t.Union[SubconBuildTypes, None]]: ... +) -> Construct[t.Union[SubconParsedType, None], t.Union[SubconBuildTypes, None]]: ... ThenParsedType = t.TypeVar("ThenParsedType") ThenBuildTypes = t.TypeVar("ThenBuildTypes") ElseParsedType = t.TypeVar("ElseParsedType") ElseBuildTypes = t.TypeVar("ElseBuildTypes") -class IfThenElse(Construct[t.Union[ThenParsedType, ElseParsedType], t.Union[ThenBuildTypes, ElseBuildTypes]]): +class IfThenElse( + Construct[ + t.Union[ThenParsedType, ElseParsedType], t.Union[ThenBuildTypes, ElseBuildTypes] + ] +): condfunc: ConstantOrContextLambda[bool] thensubcon: Construct[ThenParsedType, ThenBuildTypes] elsesubcon: Construct[ElseParsedType, ElseBuildTypes] def __init__( - self: t.Self, + self, condfunc: ConstantOrContextLambda[bool], thensubcon: Construct[ThenParsedType, ThenBuildTypes], elsesubcon: Construct[ElseParsedType, ElseBuildTypes], @@ -797,29 +761,28 @@ def If( SwitchType = t.TypeVar("SwitchType") -class Switch(Construct[ParsedType, BuildTypes]): +class _Switch(Construct[ParsedType, BuildTypes]): keyfunc: ConstantOrContextLambda[t.Any] cases: t.Dict[t.Any, Construct[t.Any, t.Any]] default: Construct[t.Any, t.Any] - @t.overload - def __init__( - self: Switch[int, t.Optional[int]], - keyfunc: ConstantOrContextLambda[SwitchType], - cases: t.Dict[SwitchType, Construct[int, int]], - default: t.Optional[Construct[int, int]] = ..., - ) -> None: ... - @t.overload - def __init__( - self: Switch[t.Any, t.Any], - keyfunc: ConstantOrContextLambda[t.Any], - cases: t.Dict[t.Any, Construct[t.Any, t.Any]], - default: t.Optional[Construct[t.Any, t.Any]] = ..., - ) -> None: ... + +@t.overload +def Switch( + keyfunc: ConstantOrContextLambda[SwitchType], + cases: t.Dict[SwitchType, Construct[int, int]], + default: t.Optional[Construct[int, int]] = ..., +) -> _Switch[int, t.Optional[int]]: ... +@t.overload +def Switch( + keyfunc: ConstantOrContextLambda[t.Any], + cases: t.Dict[t.Any, Construct[t.Any, t.Any]], + default: t.Optional[Construct[t.Any, t.Any]] = ..., +) -> _Switch[t.Any, t.Any]: ... class StopIf(Construct[None, None]): condfunc: ConstantOrContextLambda[bool] def __init__( - self: t.Self, + self, condfunc: ConstantOrContextLambda[bool], ) -> None: ... @@ -836,7 +799,7 @@ class Padded( length: ConstantOrContextLambda[int] pattern: bytes def __init__( - self: t.Self, + self, length: ConstantOrContextLambda[int], subcon: Construct[SubconParsedType, SubconBuildTypes], pattern: bytes = ..., @@ -848,7 +811,7 @@ class Aligned( modulus: ConstantOrContextLambda[int] pattern: bytes def __init__( - self: t.Self, + self, modulus: ConstantOrContextLambda[int], subcon: Construct[SubconParsedType, SubconBuildTypes], pattern: bytes = ..., @@ -858,7 +821,7 @@ def AlignedStruct( modulus: ConstantOrContextLambda[int], *subcons: Construct[t.Any, t.Any], **subconskw: Construct[t.Any, t.Any], -) -> Struct[Container[t.Any], t.Optional[t.Dict[str, t.Any]]]: ... +) -> Struct: ... def BitStruct( *subcons: Construct[t.Any, t.Any], **subconskw: Construct[t.Any, t.Any] ) -> t.Union[ @@ -875,15 +838,22 @@ class Pointer( offset: ConstantOrContextLambda[int] stream: t.Optional[t.Callable[[Context], StreamType]] def __init__( - self: t.Self, + self, offset: ConstantOrContextLambda[int], subcon: Construct[SubconParsedType, SubconBuildTypes], stream: t.Optional[t.Callable[[Context], StreamType]] = ..., ) -> None: ... -class Peek(Subconstruct[SubconParsedType, SubconBuildTypes, SubconParsedType, t.Union[SubconBuildTypes, None]]): +class Peek( + Subconstruct[ + SubconParsedType, + SubconBuildTypes, + SubconParsedType, + t.Union[SubconBuildTypes, None], + ] +): def __init__( - self: t.Self, + self, subcon: Construct[SubconParsedType, SubconBuildTypes], ) -> None: ... @@ -915,14 +885,16 @@ class RawCopyObj(t.Generic[ParsedType], Container[t.Any]): offset2: int length: int -class RawCopy(Subconstruct[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]): +class RawCopy( + Subconstruct[ + SubconParsedType, + SubconBuildTypes, + RawCopyObj[SubconParsedType], + t.Optional[t.Dict[str, t.Union[SubconBuildTypes, bytes]]], + ] +): def __init__( - self: RawCopy[ - SubconParsedType, - SubconBuildTypes, - RawCopyObj[SubconParsedType], - t.Optional[t.Dict[str, t.Union[SubconBuildTypes, bytes]]], - ], + self, subcon: Construct[SubconParsedType, SubconBuildTypes], ) -> None: ... @@ -942,7 +914,7 @@ class Prefixed( lengthfield: Construct[SubconParsedType, SubconBuildTypes] includelength: t.Optional[bool] def __init__( - self: t.Self, + self, lengthfield: Construct[int, int], subcon: Construct[SubconParsedType, SubconBuildTypes], includelength: t.Optional[bool] = ..., @@ -951,19 +923,14 @@ class Prefixed( def PrefixedArray( countfield: Construct[int, int], subcon: Construct[SubconParsedType, SubconBuildTypes], -) -> Array[ - SubconParsedType, - SubconBuildTypes, - ListContainer[SubconParsedType], - t.List[SubconBuildTypes], -]: ... +) -> Array[SubconParsedType, SubconBuildTypes,]: ... class FixedSized( Subconstruct[SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes] ): length: ConstantOrContextLambda[int] def __init__( - self: t.Self, + self, length: ConstantOrContextLambda[int], subcon: Construct[SubconParsedType, SubconBuildTypes], ) -> None: ... @@ -976,7 +943,7 @@ class NullTerminated( consume: t.Optional[bool] require: t.Optional[bool] def __init__( - self: t.Self, + self, subcon: Construct[SubconParsedType, SubconBuildTypes], term: bytes = ..., include: t.Optional[bool] = ..., @@ -989,7 +956,9 @@ class NullStripped( ): pad: bytes def __init__( - self: t.Self, subcon: Construct[SubconParsedType, SubconBuildTypes], pad: bytes = ... + self, + subcon: Construct[SubconParsedType, SubconBuildTypes], + pad: bytes = ..., ) -> None: ... class RestreamData( @@ -999,7 +968,7 @@ class RestreamData( bytes, io.BytesIO, Construct[bytes, t.Any], t.Callable[[Context], bytes] ] def __init__( - self: t.Self, + self, datafunc: t.Union[ bytes, io.BytesIO, Construct[bytes, t.Any], t.Callable[[Context], bytes] ], @@ -1014,7 +983,7 @@ class Transformed( encodefunc: t.Callable[[bytes], bytes] encodeamount: t.Optional[int] def __init__( - self: t.Self, + self, subcon: Construct[SubconParsedType, SubconBuildTypes], decodefunc: t.Callable[[bytes], bytes], decodeamount: t.Optional[int], @@ -1031,7 +1000,7 @@ class Restreamed( encoderunit: int sizecomputer: t.Callable[[int], int] def __init__( - self: t.Self, + self, subcon: Construct[SubconParsedType, SubconBuildTypes], decoder: t.Callable[[bytes], bytes], decoderunit: int, @@ -1045,7 +1014,7 @@ class ProcessXor( ): padfunc: ConstantOrContextLambda2[t.Union[int, bytes]] def __init__( - self: t.Self, + self, padfunc: ConstantOrContextLambda2[t.Union[int, bytes]], subcon: Construct[SubconParsedType, SubconBuildTypes], ) -> None: ... @@ -1056,7 +1025,7 @@ class ProcessRotateLeft( amount: ConstantOrContextLambda2[int] group: ConstantOrContextLambda2[int] def __init__( - self: t.Self, + self, amount: ConstantOrContextLambda2[int], group: ConstantOrContextLambda2[int], subcon: Construct[SubconParsedType, SubconBuildTypes], @@ -1080,7 +1049,7 @@ class Compressed(Tunnel[SubconParsedType, SubconBuildTypes]): level: t.Optional[int] lib: t.Any def __init__( - self: t.Self, + self, subcon: Construct[SubconParsedType, SubconBuildTypes], encoding: str, level: t.Optional[int] = ..., @@ -1089,7 +1058,7 @@ class Compressed(Tunnel[SubconParsedType, SubconBuildTypes]): class CompressedLZ4(Tunnel[SubconParsedType, SubconBuildTypes]): lib: t.Any def __init__( - self: t.Self, + self, subcon: Construct[SubconParsedType, SubconBuildTypes], ) -> None: ... @@ -1098,7 +1067,7 @@ class Rebuffered( ): stream2: RebufferedBytesIO def __init__( - self: t.Self, + self, subcon: Construct[SubconParsedType, SubconBuildTypes], tailcutoff: t.Optional[int] = ..., ) -> None: ... @@ -1106,14 +1075,16 @@ class Rebuffered( # =============================================================================== # lazy equivalents # =============================================================================== -class Lazy(Subconstruct[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]): +class Lazy( + Subconstruct[ + SubconParsedType, + SubconBuildTypes, + t.Callable[[], SubconParsedType], + t.Union[t.Callable[[], SubconParsedType], SubconParsedType], + ] +): def __init__( - self: Lazy[ - SubconParsedType, - SubconBuildTypes, - t.Callable[[], SubconParsedType], - t.Union[t.Callable[[], SubconParsedType], SubconParsedType], - ], + self, subcon: Construct[SubconParsedType, SubconBuildTypes], ) -> None: ... @@ -1124,12 +1095,12 @@ class LazyContainer(t.Generic[ContainerType], t.Dict[str, ContainerType]): def values(self) -> t.List[ContainerType]: ... def items(self) -> t.List[t.Tuple[str, ContainerType]]: ... -class LazyStruct(Construct[ParsedType, BuildTypes]): +class LazyStruct(Construct[LazyContainer[t.Any], t.Optional[t.Dict[str, t.Any]]]): subcons: t.List[Construct[t.Any, t.Any]] _subcons: t.Dict[str, Construct[t.Any, t.Any]] _subconsindexes: t.Dict[str, int] def __init__( - self: LazyStruct[LazyContainer[t.Any], t.Optional[t.Dict[str, t.Any]]], + self, *subcons: Construct[t.Any, t.Any], **subconskw: Construct[t.Any, t.Any], ) -> None: ... @@ -1141,18 +1112,13 @@ class LazyArray( Subconstruct[ SubconParsedType, SubconBuildTypes, - ParsedType, - BuildTypes, + ListContainer[SubconParsedType], # type: ignore + t.List[SubconBuildTypes], # type: ignore ] ): count: ConstantOrContextLambda[int] def __init__( - self: LazyArray[ - SubconParsedType, - SubconBuildTypes, - ListContainer[SubconParsedType], - t.List[SubconBuildTypes], - ], + self, count: ConstantOrContextLambda[int], subcon: Construct[SubconParsedType, SubconBuildTypes], ) -> None: ... @@ -1160,7 +1126,7 @@ class LazyArray( class LazyBound(Construct[ParsedType, BuildTypes]): subconfunc: t.Callable[[], Construct[ParsedType, BuildTypes]] def __init__( - self: LazyBound[ParsedType, BuildTypes], + self, subconfunc: t.Callable[[], Construct[ParsedType, BuildTypes]], ) -> None: ... @@ -1207,22 +1173,23 @@ def Filter( ]: ... class Slicing( - Adapter[SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes] + Adapter[ + SubconParsedType, + SubconBuildTypes, + ListContainer[SubconParsedType], # type: ignore + t.List[SubconBuildTypes], # type: ignore + ] ): def __init__( - self: Slicing[ListContainer[SubconParsedType], t.List[SubconBuildTypes]], + self, subcon: t.Union[ Array[ SubconParsedType, SubconBuildTypes, - ListContainer[SubconParsedType], - t.List[SubconBuildTypes], ], GreedyRange[ SubconParsedType, SubconBuildTypes, - ListContainer[SubconParsedType], - t.List[SubconBuildTypes], ], ], count: int, @@ -1241,14 +1208,10 @@ class Indexing( Array[ SubconParsedType, SubconBuildTypes, - ListContainer[SubconParsedType], - t.List[SubconBuildTypes], ], GreedyRange[ SubconParsedType, SubconBuildTypes, - ListContainer[SubconParsedType], - t.List[SubconBuildTypes], ], ], count: int, From 6b4a52e73a039560a3c8b7ca0b3893f8e331a582 Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Tue, 18 Jul 2023 15:38:40 +0200 Subject: [PATCH 04/42] merged .py and .pyi --- tests/declarativeunittest.py | 164 ++++++++++++++++++++++++++++++---- tests/declarativeunittest.pyi | 109 ---------------------- 2 files changed, 148 insertions(+), 125 deletions(-) delete mode 100644 tests/declarativeunittest.pyi diff --git a/tests/declarativeunittest.py b/tests/declarativeunittest.py index 1d1be0c..f3c8266 100644 --- a/tests/declarativeunittest.py +++ b/tests/declarativeunittest.py @@ -1,38 +1,170 @@ +import binascii +import io +import typing as t + import pytest +from construct import * +from construct.lib import * + +import construct_typed as cst xfail = pytest.mark.xfail skip = pytest.mark.skip skipif = pytest.mark.skipif -import os, math, random, collections, itertools, io, hashlib, binascii +Buffer = t.Union[bytes, memoryview, bytearray] +ParsedType = t.TypeVar("ParsedType") +BuildTypes = t.TypeVar("BuildTypes") +ContainerType = t.TypeVar("ContainerType", bound=cst.TContainerMixin) +T = t.TypeVar("T") -from construct import * -from construct.lib import * +IdentType = t.TypeVar("IdentType") class ZeroIO(io.BufferedIOBase): - def read(self, __size=None): + def read(self, __size: t.Optional[int] = None): if __size is not None: return bytes(__size) else: return bytes(0) - def read1(self, __size=0): + def read1(self, __size: int = 0): return bytes(__size) -ident = lambda x: x -devzero = ZeroIO() +def ident(x: IdentType) -> IdentType: + return x -def raises(func, *args, **kw): +devzero: t.BinaryIO = ZeroIO() # type: ignore + + +def raises( + func: t.Callable[..., t.Any], *args: t.Any, **kw: t.Any +) -> t.Union[t.Any, Exception]: try: return func(*args, **kw) except Exception as e: return e.__class__ -def common(format, datasample, objsample, sizesample=SizeofError, **kw): +@t.overload +def common( + format: cst.TStruct[ContainerType], + datasample: Buffer, + objsample: t.Union[ContainerType, t.Dict[str, t.Any]], + sizesample: t.Union[int, t.Type[Exception]] = ..., + **kw: t.Any +) -> None: + ... + + +@t.overload +def common( + format: "Construct[ListContainer[ParsedType], t.Any]", + datasample: Buffer, + objsample: t.List[ParsedType], + sizesample: t.Union[int, t.Type[Exception]] = ..., + **kw: t.Any +) -> None: + ... + + +@t.overload +def common( + format: "Construct[Container[t.Any], t.Any]", + datasample: Buffer, + objsample: t.Dict[str, t.Any], + sizesample: t.Union[int, t.Type[Exception]] = ..., + **kw: t.Any +) -> None: + ... + + +@t.overload +def common( + format: "Construct[t.Union[EnumInteger, EnumIntegerString], t.Any]", + datasample: Buffer, + objsample: t.Union[int, str], + sizesample: t.Union[int, t.Type[Exception]] = ..., + **kw: t.Any +) -> None: + ... + + +@t.overload +def common( + format: "Construct[HexDisplayedInteger, t.Any]", + datasample: Buffer, + objsample: t.Union[HexDisplayedInteger, int], + sizesample: t.Union[int, t.Type[Exception]] = ..., + **kw: t.Any +) -> None: + ... + + +@t.overload +def common( + format: "Construct[HexDisplayedBytes, t.Any]", + datasample: Buffer, + objsample: t.Union[HexDisplayedBytes, bytes], + sizesample: t.Union[int, t.Type[Exception]] = ..., + **kw: t.Any +) -> None: + ... + + +@t.overload +def common( + format: "Construct[HexDisplayedDict[str, t.Any], t.Any]", + datasample: Buffer, + objsample: t.Dict[str, t.Any], + sizesample: t.Union[int, t.Type[Exception]] = ..., + **kw: t.Any +) -> None: + ... + + +@t.overload +def common( + format: "Construct[HexDumpDisplayedBytes, t.Any]", + datasample: Buffer, + objsample: t.Union[HexDumpDisplayedBytes, bytes], + sizesample: t.Union[int, t.Type[Exception]] = ..., + **kw: t.Any +) -> None: + ... + + +@t.overload +def common( + format: "Construct[HexDumpDisplayedDict[str, t.Any], t.Any]", + datasample: Buffer, + objsample: t.Dict[str, t.Any], + sizesample: t.Union[int, t.Type[Exception]] = ..., + **kw: t.Any +) -> None: + ... + + +@t.overload +def common( + format: "Construct[ParsedType, t.Any]", + datasample: Buffer, + objsample: ParsedType, + sizesample: t.Union[int, t.Type[Exception]] = ..., + **kw: t.Any +) -> None: + ... + + +def common( + format: "Construct[t.Any, t.Any]", + datasample: Buffer, + objsample: t.Any, + sizesample: t.Union[int, t.Type[Exception]] = SizeofError, + **kw: t.Any +) -> None: obj = format.parse(datasample, **kw) assert obj == objsample data = format.build(objsample, **kw) @@ -48,31 +180,31 @@ def common(format, datasample, objsample, sizesample=SizeofError, **kw): assert size == sizesample -def setattrs(obj, **kwargs): - """ Set multiple named values of an object """ +def setattrs(obj: T, **kwargs: t.Any) -> T: + """Set multiple named values of an object""" for name, value in kwargs.items(): setattr(obj, name, value) return obj -def commonhex(format, hexdata): +def commonhex(format: "Construct[t.Any, t.Any]", hexdata: str): commonbytes(format, binascii.unhexlify(hexdata)) -def commondumpdeprecated(format, filename): +def commondumpdeprecated(format: "Construct[t.Any, t.Any]", filename: str): filename = "tests/deprecated_gallery/blobs/" + filename with open(filename, "rb") as f: data = f.read() commonbytes(format, data) -def commondump(format, filename): +def commondump(format: "Construct[t.Any, t.Any]", filename: str): filename = "tests/gallery/blobs/" + filename with open(filename, "rb") as f: data = f.read() commonbytes(format, data) -def commonbytes(format, data): +def commonbytes(format: "Construct[t.Any, t.Any]", data: bytes): obj = format.parse(data) - data2 = format.build(obj) + format.build(obj) diff --git a/tests/declarativeunittest.pyi b/tests/declarativeunittest.pyi deleted file mode 100644 index e2f8cab..0000000 --- a/tests/declarativeunittest.pyi +++ /dev/null @@ -1,109 +0,0 @@ -import typing as t -from construct import * -from construct.lib import * -import construct_typed as cst - -Buffer = t.Union[bytes, memoryview, bytearray] -ParsedType = t.TypeVar("ParsedType") -BuildTypes = t.TypeVar("BuildTypes") -ContainerType = t.TypeVar("ContainerType", bound=cst.TContainerMixin) -T = t.TypeVar("T") - -IdentType = t.TypeVar("IdentType") - -def ident(p1: IdentType) -> IdentType: ... - -devzero: t.BinaryIO - -def raises( - func: t.Callable[..., t.Any], *args: t.Any, **kw: t.Any -) -> t.Union[t.Any, Exception]: ... -@t.overload -def common( - format: cst.TStruct[ContainerType], - datasample: Buffer, - objsample: t.Union[ContainerType, t.Dict[str, t.Any]], - sizesample: t.Union[int, t.Type[Exception]] = ..., - **kw: t.Any -) -> None: ... -@t.overload -def common( - format: Construct[ListContainer[ParsedType], t.Any], - datasample: Buffer, - objsample: t.List[ParsedType], - sizesample: t.Union[int, t.Type[Exception]] = ..., - **kw: t.Any -) -> None: ... -@t.overload -def common( - format: Construct[Container[t.Any], t.Any], - datasample: Buffer, - objsample: t.Dict[str, t.Any], - sizesample: t.Union[int, t.Type[Exception]] = ..., - **kw: t.Any -) -> None: ... -@t.overload -def common( - format: Construct[t.Union[EnumInteger, EnumIntegerString], t.Any], - datasample: Buffer, - objsample: t.Union[int, str], - sizesample: t.Union[int, t.Type[Exception]] = ..., - **kw: t.Any -) -> None: ... -@t.overload -def common( - format: Construct[HexDisplayedInteger, t.Any], - datasample: Buffer, - objsample: t.Union[HexDisplayedInteger, int], - sizesample: t.Union[int, t.Type[Exception]] = ..., - **kw: t.Any -) -> None: ... -@t.overload -def common( - format: Construct[HexDisplayedBytes, t.Any], - datasample: Buffer, - objsample: t.Union[HexDisplayedBytes, bytes], - sizesample: t.Union[int, t.Type[Exception]] = ..., - **kw: t.Any -) -> None: ... -@t.overload -def common( - format: Construct[HexDisplayedDict[str, t.Any], t.Any], - datasample: Buffer, - objsample: t.Dict[str, t.Any], - sizesample: t.Union[int, t.Type[Exception]] = ..., - **kw: t.Any -) -> None: ... -@t.overload -def common( - format: Construct[HexDumpDisplayedBytes, t.Any], - datasample: Buffer, - objsample: t.Union[HexDumpDisplayedBytes, bytes], - sizesample: t.Union[int, t.Type[Exception]] = ..., - **kw: t.Any -) -> None: ... -@t.overload -def common( - format: Construct[HexDumpDisplayedDict[str, t.Any], t.Any], - datasample: Buffer, - objsample: t.Dict[str, t.Any], - sizesample: t.Union[int, t.Type[Exception]] = ..., - **kw: t.Any -) -> None: ... -@t.overload -def common( - format: Construct[ParsedType, t.Any], - datasample: Buffer, - objsample: ParsedType, - sizesample: t.Union[int, t.Type[Exception]] = ..., - **kw: t.Any -) -> None: ... -def setattrs(obj: T, **kwargs: t.Any) -> T: ... -def commonhex(format: Construct[t.Any, t.Any], hexdata: str) -> None: ... -def commondumpdeprecated( - format: Construct[t.Any, t.Any], filename: str -) -> None: ... -def commondump(format: Construct[t.Any, t.Any], filename: str) -> None: ... -def commonbytes( - format: Construct[ParsedType, t.Any], data: ParsedType -) -> None: ... From dd1691528f85928e8887d1302079e798cf9e5c57 Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Tue, 18 Jul 2023 15:44:33 +0200 Subject: [PATCH 05/42] fixed pyright errors --- construct-stubs/expr.pyi | 6 +++--- tests/test_core.py | 19 ++++++++++--------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/construct-stubs/expr.pyi b/construct-stubs/expr.pyi index 56fae52..5708077 100644 --- a/construct-stubs/expr.pyi +++ b/construct-stubs/expr.pyi @@ -498,7 +498,7 @@ class ExprMixin(t.Generic[ReturnType], object): @t.overload def __neg__(self: ExprMixin[float]) -> BinExpr[float]: ... @t.overload - def __neg__(self) -> UniExpr[t.Any]: ... + def __neg__(self) -> BinExpr[t.Any]: ... # __pos__ ########################################################################################################## @t.overload @@ -508,7 +508,7 @@ class ExprMixin(t.Generic[ReturnType], object): @t.overload def __pos__(self: ExprMixin[float]) -> BinExpr[float]: ... @t.overload - def __pos__(self) -> UniExpr[t.Any]: ... + def __pos__(self) -> BinExpr[t.Any]: ... # __invert__ ####################################################################################################### @t.overload @@ -516,7 +516,7 @@ class ExprMixin(t.Generic[ReturnType], object): @t.overload def __invert__(self: ExprMixin[bool]) -> BinExpr[int]: ... @t.overload - def __invert__(self) -> UniExpr[t.Any]: ... + def __invert__(self) -> BinExpr[t.Any]: ... # __inv__ ########################################################################################################## def __inv__(self) -> UniExpr[t.Any]: ... diff --git a/tests/test_core.py b/tests/test_core.py index 4b1e4d0..d5bfb37 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -637,8 +637,7 @@ def test_numpy_error() -> None: numpy.load(io.BytesIO(b"")) # type: ignore def test_namedtuple() -> None: - import collections - coord = collections.namedtuple("coord", "x y z") + coord = t.NamedTuple("coord", [("x", int), ("y", int), ("z", int)]) d1 = NamedTuple("coord", "x y z", Array(3, Byte)) common(d1, b"123", coord(49,50,51), 3) d2 = NamedTuple("coord", "x y z", GreedyRange(Byte)) @@ -808,8 +807,10 @@ def test_select_buildfromnone_issue_747() -> None: assert d.build(dict()) == b"" def test_if() -> None: - common(If(True, Byte), b"\x01", 1, 1) - common(If(False, Byte), b"", None, 0) + d = If(True, Byte) + common(d, b"\x01", 1, 1) + d = If(False, Byte) + common(d, b"", None, 0) def test_ifthenelse() -> None: common(IfThenElse(True, Int8ub, Int16ub), b"\x01", 1, 1) @@ -1545,7 +1546,7 @@ def test_operators() -> None: assert d.docs == "description" d = "description" * Byte assert d.docs == "description" - """ + _ = """ description """ * \ Byte @@ -1796,11 +1797,11 @@ def test_pickling_constructs() -> None: ) data = bytes(100) - du = cloudpickle.loads(cloudpickle.dumps(d, protocol=-1)) + du = cloudpickle.loads(cloudpickle.dumps(d, protocol=-1)) # type: ignore assert du.parse(data) == d.parse(data) def test_pickling_constructs_issue_894() -> None: - import cloudpickle + import cloudpickle # type: ignore fundus_header = Struct( 'width' / Int32un, @@ -1812,7 +1813,7 @@ def test_pickling_constructs_issue_894() -> None: 'img' / Int8un, ) - cloudpickle.dumps(fundus_header) + cloudpickle.dumps(fundus_header) # type: ignore def test_exposing_members_attributes() -> None: d1 = Struct( @@ -2023,7 +2024,7 @@ def test_struct_root_topmost() -> None: assert d.parse(b"", z=2) == Container(x=1, inner=Container(inner2=Container(x=1,z=2,zz=2))) def test_parsedhook_repeatersdiscard() -> None: - outputs = [] + outputs: t.List[int] = [] def printobj1(obj: int, ctx: "Context") -> None: outputs.append(obj) d1 = GreedyRange(Byte * printobj1, discard=True) From 7f08ab2f28a1a1fb4a2d261d9aca00fe6cf5598d Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Tue, 18 Jul 2023 17:25:21 +0200 Subject: [PATCH 06/42] added intermediate variable, so that pyright v1.1.316 passes --- tests/test_core.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tests/test_core.py b/tests/test_core.py index d5bfb37..450007a 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # mypy: no-warn-unused-ignores -from .declarativeunittest import raises, common, commonhex, commondumpdeprecated, commondump, commonbytes, ident, devzero +from .declarativeunittest import raises, common, ident, devzero from construct.core import * from construct import * from construct.lib import * @@ -707,10 +707,13 @@ def test_hexdump() -> None: def test_hexdump_regression_issue_188() -> None: # Hex HexDump were not inheriting subcon flags - d = Struct(Hex(Const(b"MZ"))) + a = Hex(Const(b"MZ")) + d = Struct(a) assert d.parse(b"MZ") == Container() assert d.build(dict()) == b"MZ" - d = Struct(HexDump(Const(b"MZ"))) + + a = HexDump(Const(b"MZ")) + d = Struct(a) assert d.parse(b"MZ") == Container() assert d.build(dict()) == b"MZ" @@ -1688,9 +1691,11 @@ def test_from_issue_244() -> None: assert d.parse(b"abcd") == [Container(num=97, index=0),Container(num=98, index=1),Container(num=99, index=2),Container(num=100, index=3),] def test_from_issue_269() -> None: - d = Struct("enabled" / Byte, If(this.enabled, Padding(2))) + a = If(this.enabled, Padding(2)) + d = Struct("enabled" / Byte, a) assert d.build(dict(enabled=1)) == b"\x01\x00\x00" assert d.build(dict(enabled=0)) == b"\x00" + d = Struct("enabled" / Byte, "pad" / If(this.enabled, Padding(2))) assert d.build(dict(enabled=1)) == b"\x01\x00\x00" assert d.build(dict(enabled=0)) == b"\x00" From f75029247f3554fe7b7829fe64bef57173c9d375 Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Tue, 18 Jul 2023 17:26:03 +0200 Subject: [PATCH 07/42] added missing definitions --- construct-stubs/__init__.pyi | 4 ++++ construct-stubs/core.pyi | 13 ++++++++++++- construct-stubs/expr.pyi | 1 - construct-stubs/lib/hex.pyi | 4 +++- construct-stubs/lib/py3compat.pyi | 1 + 5 files changed, 20 insertions(+), 3 deletions(-) diff --git a/construct-stubs/__init__.pyi b/construct-stubs/__init__.pyi index 858384d..2cad48a 100644 --- a/construct-stubs/__init__.pyi +++ b/construct-stubs/__init__.pyi @@ -3,6 +3,10 @@ from construct.debug import * from construct.expr import * from construct.lib import * from construct.version import * +from construct import lib + +__author__: str +__version__: str #=============================================================================== # exposed names diff --git a/construct-stubs/core.pyi b/construct-stubs/core.pyi index a19686b..796624d 100644 --- a/construct-stubs/core.pyi +++ b/construct-stubs/core.pyi @@ -207,7 +207,16 @@ class Tunnel( def _decode(self, data: bytes, context: Context, path: PathType) -> bytes: ... def _encode(self, data: bytes, context: Context, path: PathType) -> bytes: ... -# TODO: Compiled +class Compiled(Construct[t.Any, t.Any]): + source: t.Optional[str] + defersubcon: t.Optional[Construct[t.Any, t.Any]] + parsefunc: t.Callable[[StreamType, Context], t.Any] + buildfunc: t.Callable[[t.Any, StreamType, Context], t.Any] + def __init__( + self, + parsefunc: t.Callable[[StreamType, Context], t.Any], + buildfunc: t.Callable[[t.Any, StreamType, Context], t.Any], + ) -> None: ... # =============================================================================== # bytes and bits @@ -356,6 +365,8 @@ ZigZag: Construct[int, int] # =============================================================================== # strings # =============================================================================== +possiblestringencodings: t.Dict[str, int] + class StringEncoded(Construct[str, str]): if sys.version_info >= (3, 8): ENCODING_1 = t.Literal["ascii", "utf8", "utf_8", "u8"] diff --git a/construct-stubs/expr.pyi b/construct-stubs/expr.pyi index 5708077..3d1b032 100644 --- a/construct-stubs/expr.pyi +++ b/construct-stubs/expr.pyi @@ -1,4 +1,3 @@ -import operator import typing as t from construct.core import * diff --git a/construct-stubs/lib/hex.pyi b/construct-stubs/lib/hex.pyi index afa985f..a39d918 100644 --- a/construct-stubs/lib/hex.pyi +++ b/construct-stubs/lib/hex.pyi @@ -1,6 +1,5 @@ import typing as t - class HexDisplayedInteger(int): ... class HexDisplayedBytes(bytes): ... @@ -10,3 +9,6 @@ V = t.TypeVar("V") class HexDisplayedDict(t.Dict[K, V]): ... class HexDumpDisplayedBytes(bytes): ... class HexDumpDisplayedDict(t.Dict[K, V]): ... + +def hexdump(data: bytes, linesize: int) -> str: ... +def hexundump(data: str, linesize: int) -> bytes: ... diff --git a/construct-stubs/lib/py3compat.pyi b/construct-stubs/lib/py3compat.pyi index f105096..c86f2f5 100644 --- a/construct-stubs/lib/py3compat.pyi +++ b/construct-stubs/lib/py3compat.pyi @@ -1,5 +1,6 @@ import typing as t +PY: t.Tuple[int, int] PY2: bool PY3: bool PYPY: bool From 3c81d99c12410cfc57566b8da16718472c235203 Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Tue, 18 Jul 2023 17:36:27 +0200 Subject: [PATCH 08/42] Added __new__ only where it is an absolute must have. --- construct-stubs/core.pyi | 318 ++++++++++++++++++++------------------- 1 file changed, 165 insertions(+), 153 deletions(-) diff --git a/construct-stubs/core.pyi b/construct-stubs/core.pyi index 796624d..6323b4f 100644 --- a/construct-stubs/core.pyi +++ b/construct-stubs/core.pyi @@ -246,41 +246,45 @@ def Bytewise( # =============================================================================== # integers and floats # =============================================================================== -class _FormatField(Construct[ParsedType, BuildTypes]): +class FormatField(Construct[ParsedType, BuildTypes]): fmtstr: str length: int + if sys.version_info >= (3, 8): + ENDIANITY = t.Union[t.Literal["=", "<", ">"], str] + FORMAT_INT = t.Literal["B", "H", "L", "Q", "b", "h", "l", "q"] + FORMAT_FLOAT = t.Literal["f", "d", "e"] + FORMAT_BOOL = t.Literal["?"] + @t.overload + def __new__( + cls, + endianity: str, + format: FORMAT_INT, + ) -> FormatField[int, int]: ... + @t.overload + def __new__( + cls, + endianity: str, + format: FORMAT_FLOAT, + ) -> FormatField[float, float]: ... + @t.overload + def __new__( + cls, + endianity: str, + format: FORMAT_BOOL, + ) -> FormatField[bool, bool]: ... + @t.overload + def __new__( + cls, + endianity: str, + format: str, + ) -> FormatField[t.Any, t.Any]: ... -if sys.version_info >= (3, 8): - ENDIANITY = t.Union[t.Literal["=", "<", ">"], str] - FORMAT_INT = t.Literal["B", "H", "L", "Q", "b", "h", "l", "q"] - FORMAT_FLOAT = t.Literal["f", "d", "e"] - FORMAT_BOOL = t.Literal["?"] - @t.overload - def FormatField( - endianity: str, - format: FORMAT_INT, - ) -> _FormatField[int, int]: ... - @t.overload - def FormatField( - endianity: str, - format: FORMAT_FLOAT, - ) -> _FormatField[float, float]: ... - @t.overload - def FormatField( - endianity: str, - format: FORMAT_BOOL, - ) -> _FormatField[bool, bool]: ... - @t.overload - def FormatField( - endianity: str, - format: str, - ) -> _FormatField[t.Any, t.Any]: ... - -else: - def FormatField( - endianity: str, - format: str, - ) -> _FormatField[t.Any, t.Any]: ... + else: + def __new__( + cls, + endianity: str, + format: str, + ) -> FormatField[t.Any, t.Any]: ... class BytesInteger(Construct[int, int]): length: ConstantOrContextLambda[int] @@ -308,49 +312,49 @@ Bit: BitsInteger Nibble: BitsInteger Octet: BitsInteger -Int8ub: _FormatField[int, int] -Int16ub: _FormatField[int, int] -Int32ub: _FormatField[int, int] -Int64ub: _FormatField[int, int] -Int8sb: _FormatField[int, int] -Int16sb: _FormatField[int, int] -Int32sb: _FormatField[int, int] -Int64sb: _FormatField[int, int] -Int8ul: _FormatField[int, int] -Int16ul: _FormatField[int, int] -Int32ul: _FormatField[int, int] -Int64ul: _FormatField[int, int] -Int8sl: _FormatField[int, int] -Int16sl: _FormatField[int, int] -Int32sl: _FormatField[int, int] -Int64sl: _FormatField[int, int] -Int8un: _FormatField[int, int] -Int16un: _FormatField[int, int] -Int32un: _FormatField[int, int] -Int64un: _FormatField[int, int] -Int8sn: _FormatField[int, int] -Int16sn: _FormatField[int, int] -Int32sn: _FormatField[int, int] -Int64sn: _FormatField[int, int] +Int8ub: FormatField[int, int] +Int16ub: FormatField[int, int] +Int32ub: FormatField[int, int] +Int64ub: FormatField[int, int] +Int8sb: FormatField[int, int] +Int16sb: FormatField[int, int] +Int32sb: FormatField[int, int] +Int64sb: FormatField[int, int] +Int8ul: FormatField[int, int] +Int16ul: FormatField[int, int] +Int32ul: FormatField[int, int] +Int64ul: FormatField[int, int] +Int8sl: FormatField[int, int] +Int16sl: FormatField[int, int] +Int32sl: FormatField[int, int] +Int64sl: FormatField[int, int] +Int8un: FormatField[int, int] +Int16un: FormatField[int, int] +Int32un: FormatField[int, int] +Int64un: FormatField[int, int] +Int8sn: FormatField[int, int] +Int16sn: FormatField[int, int] +Int32sn: FormatField[int, int] +Int64sn: FormatField[int, int] -Byte: _FormatField[int, int] -Short: _FormatField[int, int] -Int: _FormatField[int, int] -Long: _FormatField[int, int] +Byte: FormatField[int, int] +Short: FormatField[int, int] +Int: FormatField[int, int] +Long: FormatField[int, int] -Float16b: _FormatField[float, float] -Float16l: _FormatField[float, float] -Float16n: _FormatField[float, float] -Float32b: _FormatField[float, float] -Float32l: _FormatField[float, float] -Float32n: _FormatField[float, float] -Float64b: _FormatField[float, float] -Float64l: _FormatField[float, float] -Float64n: _FormatField[float, float] +Float16b: FormatField[float, float] +Float16l: FormatField[float, float] +Float16n: FormatField[float, float] +Float32b: FormatField[float, float] +Float32l: FormatField[float, float] +Float32n: FormatField[float, float] +Float64b: FormatField[float, float] +Float64l: FormatField[float, float] +Float64n: FormatField[float, float] -Half: _FormatField[float, float] -Single: _FormatField[float, float] -Double: _FormatField[float, float] +Half: FormatField[float, float] +Single: FormatField[float, float] +Double: FormatField[float, float] Int24ub: BytesInteger Int24ul: BytesInteger @@ -543,17 +547,19 @@ class Renamed( # =============================================================================== # miscellaneous # =============================================================================== -class _Const(Subconstruct[None, None, SubconParsedType, SubconBuildTypes]): ... - -@t.overload -def Const( - value: bytes, -) -> _Const[bytes, t.Optional[bytes]]: ... -@t.overload -def Const( - value: SubconBuildTypes, - subcon: Construct[SubconParsedType, SubconBuildTypes], -) -> _Const[SubconParsedType, t.Optional[SubconBuildTypes]]: ... +class Const(Subconstruct[None, None, SubconParsedType, SubconBuildTypes]): + value: SubconBuildTypes + @t.overload + def __new__( + cls, + value: bytes, + ) -> Const[bytes, t.Optional[bytes]]: ... + @t.overload + def __new__( + cls, + value: SubconBuildTypes, + subcon: Construct[SubconParsedType, SubconBuildTypes], + ) -> Const[SubconParsedType, t.Optional[SubconBuildTypes]]: ... class Computed(Construct[ParsedType, None]): func: ConstantOrContextLambda2[ParsedType] @@ -658,63 +664,68 @@ def Timestamp( K = t.TypeVar("K") V = t.TypeVar("V") -class _Hex(Adapter[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]): - pass +class Hex(Adapter[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]): + @t.overload + def __new__( + cls, + subcon: Construct[int, BuildTypes], + ) -> Hex[int, BuildTypes, HexDisplayedInteger, BuildTypes]: ... + @t.overload + def __new__( + cls, + subcon: Construct[bytes, BuildTypes], + ) -> Hex[bytes, BuildTypes, HexDisplayedBytes, BuildTypes]: ... + @t.overload + def __new__( + cls, + subcon: Construct[RawCopyObj[SubconParsedType], BuildTypes], + ) -> Hex[ + RawCopyObj[SubconParsedType], + BuildTypes, + HexDisplayedDict[str, t.Union[int, bytes, SubconParsedType]], + BuildTypes, + ]: ... + @t.overload + def __new__( + cls, + subcon: Construct[Container[t.Any], BuildTypes], + ) -> Hex[Container[t.Any], BuildTypes, HexDisplayedDict[str, t.Any], BuildTypes]: ... + @t.overload + def __new__( + cls, + subcon: Construct[SubconParsedType, SubconBuildTypes], + ) -> Hex[SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes]: ... -@t.overload -def Hex( - subcon: Construct[int, BuildTypes], -) -> _Hex[int, BuildTypes, HexDisplayedInteger, BuildTypes]: ... -@t.overload -def Hex( - subcon: Construct[bytes, BuildTypes], -) -> _Hex[bytes, BuildTypes, HexDisplayedBytes, BuildTypes]: ... -@t.overload -def Hex( - subcon: Construct[RawCopyObj[SubconParsedType], BuildTypes], -) -> _Hex[ - RawCopyObj[SubconParsedType], - BuildTypes, - HexDisplayedDict[str, t.Union[int, bytes, SubconParsedType]], - BuildTypes, -]: ... -@t.overload -def Hex( - subcon: Construct[Container[t.Any], BuildTypes], -) -> _Hex[Container[t.Any], BuildTypes, HexDisplayedDict[str, t.Any], BuildTypes]: ... -@t.overload -def Hex( - subcon: Construct[SubconParsedType, SubconBuildTypes], -) -> _Hex[SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes]: ... - -class _HexDump(Adapter[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]): - pass - -@t.overload -def HexDump( - subcon: Construct[bytes, BuildTypes], -) -> _HexDump[bytes, BuildTypes, HexDumpDisplayedBytes, BuildTypes]: ... -@t.overload -def HexDump( - subcon: Construct[RawCopyObj[SubconParsedType], BuildTypes], -) -> _HexDump[ - RawCopyObj[SubconParsedType], - BuildTypes, - HexDumpDisplayedDict[str, t.Union[int, bytes, SubconParsedType]], - BuildTypes, -]: ... -@t.overload -def HexDump( - subcon: Construct[Container[t.Any], BuildTypes], -) -> _HexDump[ - Container[t.Any], BuildTypes, HexDumpDisplayedDict[str, t.Any], BuildTypes -]: ... -@t.overload -def HexDump( - subcon: Construct[SubconParsedType, SubconBuildTypes], -) -> _HexDump[ - SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes -]: ... +class HexDump(Adapter[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]): + @t.overload + def __new__( + cls, + subcon: Construct[bytes, BuildTypes], + ) -> HexDump[bytes, BuildTypes, HexDumpDisplayedBytes, BuildTypes]: ... + @t.overload + def __new__( + cls, + subcon: Construct[RawCopyObj[SubconParsedType], BuildTypes], + ) -> HexDump[ + RawCopyObj[SubconParsedType], + BuildTypes, + HexDumpDisplayedDict[str, t.Union[int, bytes, SubconParsedType]], + BuildTypes, + ]: ... + @t.overload + def __new__( + cls, + subcon: Construct[Container[t.Any], BuildTypes], + ) -> HexDump[ + Container[t.Any], BuildTypes, HexDumpDisplayedDict[str, t.Any], BuildTypes + ]: ... + @t.overload + def __new__( + cls, + subcon: Construct[SubconParsedType, SubconBuildTypes], + ) -> HexDump[ + SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes + ]: ... # =============================================================================== # conditional @@ -772,23 +783,24 @@ def If( SwitchType = t.TypeVar("SwitchType") -class _Switch(Construct[ParsedType, BuildTypes]): +class Switch(Construct[ParsedType, BuildTypes]): keyfunc: ConstantOrContextLambda[t.Any] cases: t.Dict[t.Any, Construct[t.Any, t.Any]] default: Construct[t.Any, t.Any] - -@t.overload -def Switch( - keyfunc: ConstantOrContextLambda[SwitchType], - cases: t.Dict[SwitchType, Construct[int, int]], - default: t.Optional[Construct[int, int]] = ..., -) -> _Switch[int, t.Optional[int]]: ... -@t.overload -def Switch( - keyfunc: ConstantOrContextLambda[t.Any], - cases: t.Dict[t.Any, Construct[t.Any, t.Any]], - default: t.Optional[Construct[t.Any, t.Any]] = ..., -) -> _Switch[t.Any, t.Any]: ... + @t.overload + def __new__( + cls, + keyfunc: ConstantOrContextLambda[SwitchType], + cases: t.Dict[SwitchType, Construct[int, int]], + default: t.Optional[Construct[int, int]] = ..., + ) -> Switch[int, t.Optional[int]]: ... + @t.overload + def __new__( + cls, + keyfunc: ConstantOrContextLambda[t.Any], + cases: t.Dict[t.Any, Construct[t.Any, t.Any]], + default: t.Optional[Construct[t.Any, t.Any]] = ..., + ) -> Switch[t.Any, t.Any]: ... class StopIf(Construct[None, None]): condfunc: ConstantOrContextLambda[bool] From e39fc5b19d855a1c974bb02c16c07a1551a7a837 Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Tue, 18 Jul 2023 17:36:54 +0200 Subject: [PATCH 09/42] corrected version requirements.txt --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 87d1d1b..d1c8be1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -construct==2.10.67 +construct==2.10.68 pytest>=6.2.0 numpy arrow From 825783db574f506c25e86ecc490b62b51dab9561 Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Tue, 18 Jul 2023 17:37:29 +0200 Subject: [PATCH 10/42] fixed mypy issues --- construct_typed/dataclass_struct.py | 4 ++-- tests/declarativeunittest.py | 16 ++++++++-------- tests/test_core.py | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/construct_typed/dataclass_struct.py b/construct_typed/dataclass_struct.py index f79fc7e..8a4c562 100644 --- a/construct_typed/dataclass_struct.py +++ b/construct_typed/dataclass_struct.py @@ -102,10 +102,10 @@ def csfield( # Set default values in case of special sucons if isinstance(orig_subcon, cs.Const): - const_subcon: "cs.Const[t.Any, t.Any, t.Any, t.Any]" = orig_subcon + const_subcon: "cs.Const[t.Any, t.Any]" = orig_subcon default = const_subcon.value elif isinstance(orig_subcon, cs.Default): - default_subcon: "cs.Default[t.Any, t.Any, t.Any, t.Any]" = orig_subcon + default_subcon: "cs.Default[t.Any, t.Any]" = orig_subcon if callable(default_subcon.value): default = None # context lambda is only defined at parsing/building else: diff --git a/tests/declarativeunittest.py b/tests/declarativeunittest.py index f3c8266..ed7fb59 100644 --- a/tests/declarativeunittest.py +++ b/tests/declarativeunittest.py @@ -22,13 +22,13 @@ IdentType = t.TypeVar("IdentType") class ZeroIO(io.BufferedIOBase): - def read(self, __size: t.Optional[int] = None): + def read(self, __size: t.Optional[int] = None) -> bytes: if __size is not None: return bytes(__size) else: return bytes(0) - def read1(self, __size: int = 0): + def read1(self, __size: int = 0) -> bytes: return bytes(__size) @@ -176,8 +176,8 @@ def common( size = format.sizeof(**kw) assert size == sizesample else: - size = raises(format.sizeof, **kw) - assert size == sizesample + size_ex = raises(format.sizeof, **kw) + assert size_ex == sizesample def setattrs(obj: T, **kwargs: t.Any) -> T: @@ -187,24 +187,24 @@ def setattrs(obj: T, **kwargs: t.Any) -> T: return obj -def commonhex(format: "Construct[t.Any, t.Any]", hexdata: str): +def commonhex(format: "Construct[t.Any, t.Any]", hexdata: str) -> None: commonbytes(format, binascii.unhexlify(hexdata)) -def commondumpdeprecated(format: "Construct[t.Any, t.Any]", filename: str): +def commondumpdeprecated(format: "Construct[t.Any, t.Any]", filename: str) -> None: filename = "tests/deprecated_gallery/blobs/" + filename with open(filename, "rb") as f: data = f.read() commonbytes(format, data) -def commondump(format: "Construct[t.Any, t.Any]", filename: str): +def commondump(format: "Construct[t.Any, t.Any]", filename: str) -> None: filename = "tests/gallery/blobs/" + filename with open(filename, "rb") as f: data = f.read() commonbytes(format, data) -def commonbytes(format: "Construct[t.Any, t.Any]", data: bytes): +def commonbytes(format: "Construct[t.Any, t.Any]", data: bytes) -> None: obj = format.parse(data) format.build(obj) diff --git a/tests/test_core.py b/tests/test_core.py index 450007a..6cfd8ba 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -712,8 +712,8 @@ def test_hexdump_regression_issue_188() -> None: assert d.parse(b"MZ") == Container() assert d.build(dict()) == b"MZ" - a = HexDump(Const(b"MZ")) - d = Struct(a) + b = HexDump(Const(b"MZ")) + d = Struct(b) assert d.parse(b"MZ") == Container() assert d.build(dict()) == b"MZ" From d9026772a0f9d95a8896a78b5c28359ecc624667 Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Tue, 18 Jul 2023 17:39:10 +0200 Subject: [PATCH 11/42] fixed further mypy issues --- tests/test_core.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/test_core.py b/tests/test_core.py index 6cfd8ba..0531715 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -420,11 +420,11 @@ def test_struct_proper_context() -> None: "x"/Byte, "inner"/Struct( "y"/Byte, - "a"/Computed(this._.x+1), - "b"/Computed(this.y+2), + "a"/Computed[int](this._.x+1), + "b"/Computed[int](this.y+2), ), - "c"/Computed(this.x+3), - "d"/Computed(this.inner.y+4), + "c"/Computed[int](this.x+3), + "d"/Computed[int](this.inner.y+4), ) assert d.parse(b"\x01\x0f") == Container(x=1, inner=Container(y=15, a=2, b=17), c=4, d=19) @@ -511,7 +511,7 @@ def test_const() -> None: def test_computed() -> None: common(Computed(255), b"", 255, 0) - common(Computed(lambda ctx: 255), b"", 255, 0) + common(Computed[int](lambda ctx: 255), b"", 255, 0) assert Computed(255).build(None) == b"" assert Struct(Computed(255)).build({}) == b"" assert raises(Computed(this.missing).parse, b"") == KeyError From ede1a72c70585ad4e6114388456cc23a9389075d Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Tue, 18 Jul 2023 17:42:57 +0200 Subject: [PATCH 12/42] added ignores, because 'Computed' is not subscriptable at runtime --- tests/test_core.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/test_core.py b/tests/test_core.py index 0531715..b31cd6b 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -420,11 +420,11 @@ def test_struct_proper_context() -> None: "x"/Byte, "inner"/Struct( "y"/Byte, - "a"/Computed[int](this._.x+1), - "b"/Computed[int](this.y+2), + "a"/Computed(this._.x+1), # type: ignore + "b"/Computed(this.y+2), # type: ignore ), - "c"/Computed[int](this.x+3), - "d"/Computed[int](this.inner.y+4), + "c"/Computed(this.x+3), # type: ignore + "d"/Computed(this.inner.y+4), # type: ignore ) assert d.parse(b"\x01\x0f") == Container(x=1, inner=Container(y=15, a=2, b=17), c=4, d=19) @@ -511,7 +511,7 @@ def test_const() -> None: def test_computed() -> None: common(Computed(255), b"", 255, 0) - common(Computed[int](lambda ctx: 255), b"", 255, 0) + common(Computed(lambda ctx: 255), b"", 255, 0) # type: ignore assert Computed(255).build(None) == b"" assert Struct(Computed(255)).build({}) == b"" assert raises(Computed(this.missing).parse, b"") == KeyError From 86f27dc1fbbade2c7469e9d49a95eec7e8886320 Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Mon, 24 Jul 2023 09:40:50 +0200 Subject: [PATCH 13/42] use method-scoped TypeVars for __new__ (see here https://github.com/microsoft/pyright/issues/5404#issuecomment-1645764913) --- construct-stubs/core.pyi | 66 ++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 37 deletions(-) diff --git a/construct-stubs/core.pyi b/construct-stubs/core.pyi index 6323b4f..d138539 100644 --- a/construct-stubs/core.pyi +++ b/construct-stubs/core.pyi @@ -256,32 +256,32 @@ class FormatField(Construct[ParsedType, BuildTypes]): FORMAT_BOOL = t.Literal["?"] @t.overload def __new__( - cls, + cls: "type[FormatField[int, int]]", endianity: str, format: FORMAT_INT, ) -> FormatField[int, int]: ... @t.overload def __new__( - cls, + cls: "type[FormatField[float, float]]", endianity: str, format: FORMAT_FLOAT, ) -> FormatField[float, float]: ... @t.overload def __new__( - cls, + cls: "type[FormatField[bool, bool]]", endianity: str, format: FORMAT_BOOL, ) -> FormatField[bool, bool]: ... @t.overload def __new__( - cls, + cls: "type[FormatField[t.Any, t.Any]]", endianity: str, format: str, ) -> FormatField[t.Any, t.Any]: ... else: def __new__( - cls, + cls: "type[FormatField[t.Any, t.Any]]", endianity: str, format: str, ) -> FormatField[t.Any, t.Any]: ... @@ -547,16 +547,16 @@ class Renamed( # =============================================================================== # miscellaneous # =============================================================================== -class Const(Subconstruct[None, None, SubconParsedType, SubconBuildTypes]): - value: SubconBuildTypes +class Const(Subconstruct[t.Any, t.Any, ParsedType, BuildTypes]): + value: BuildTypes @t.overload def __new__( - cls, + cls: "type[Const[bytes, t.Optional[bytes]]]", value: bytes, ) -> Const[bytes, t.Optional[bytes]]: ... @t.overload def __new__( - cls, + cls: "type[Const[SubconParsedType, t.Optional[SubconBuildTypes]]]", value: SubconBuildTypes, subcon: Construct[SubconParsedType, SubconBuildTypes], ) -> Const[SubconParsedType, t.Optional[SubconBuildTypes]]: ... @@ -664,68 +664,60 @@ def Timestamp( K = t.TypeVar("K") V = t.TypeVar("V") -class Hex(Adapter[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]): +class Hex(Adapter[t.Any, t.Any, ParsedType, BuildTypes]): @t.overload def __new__( - cls, + cls: "type[Hex[HexDisplayedInteger, BuildTypes]]", subcon: Construct[int, BuildTypes], - ) -> Hex[int, BuildTypes, HexDisplayedInteger, BuildTypes]: ... + ) -> Hex[HexDisplayedInteger, BuildTypes]: ... @t.overload def __new__( - cls, + cls: "type[Hex[HexDisplayedBytes, BuildTypes]]", subcon: Construct[bytes, BuildTypes], - ) -> Hex[bytes, BuildTypes, HexDisplayedBytes, BuildTypes]: ... + ) -> Hex[HexDisplayedBytes, BuildTypes]: ... @t.overload def __new__( - cls, + cls: "type[Hex[HexDisplayedDict[str, t.Union[int, bytes, SubconParsedType]], BuildTypes,]]", subcon: Construct[RawCopyObj[SubconParsedType], BuildTypes], ) -> Hex[ - RawCopyObj[SubconParsedType], - BuildTypes, HexDisplayedDict[str, t.Union[int, bytes, SubconParsedType]], BuildTypes, ]: ... @t.overload def __new__( - cls, + cls: "type[Hex[HexDisplayedDict[str, t.Any], BuildTypes]]", subcon: Construct[Container[t.Any], BuildTypes], - ) -> Hex[Container[t.Any], BuildTypes, HexDisplayedDict[str, t.Any], BuildTypes]: ... + ) -> Hex[HexDisplayedDict[str, t.Any], BuildTypes]: ... @t.overload def __new__( - cls, + cls: "type[Hex[SubconParsedType, SubconBuildTypes]]", subcon: Construct[SubconParsedType, SubconBuildTypes], - ) -> Hex[SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes]: ... + ) -> Hex[SubconParsedType, SubconBuildTypes]: ... -class HexDump(Adapter[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]): +class HexDump(Adapter[t.Any, t.Any, ParsedType, BuildTypes]): @t.overload def __new__( - cls, + cls: "type[HexDump[HexDumpDisplayedBytes, BuildTypes]]", subcon: Construct[bytes, BuildTypes], - ) -> HexDump[bytes, BuildTypes, HexDumpDisplayedBytes, BuildTypes]: ... + ) -> HexDump[HexDumpDisplayedBytes, BuildTypes]: ... @t.overload def __new__( - cls, + cls: "type[HexDump[HexDumpDisplayedDict[str, t.Union[int, bytes, SubconParsedType]],BuildTypes,]]", subcon: Construct[RawCopyObj[SubconParsedType], BuildTypes], ) -> HexDump[ - RawCopyObj[SubconParsedType], - BuildTypes, HexDumpDisplayedDict[str, t.Union[int, bytes, SubconParsedType]], BuildTypes, ]: ... @t.overload def __new__( - cls, + cls: "type[HexDump[HexDumpDisplayedDict[str, t.Any], BuildTypes]]", subcon: Construct[Container[t.Any], BuildTypes], - ) -> HexDump[ - Container[t.Any], BuildTypes, HexDumpDisplayedDict[str, t.Any], BuildTypes - ]: ... + ) -> HexDump[HexDumpDisplayedDict[str, t.Any], BuildTypes]: ... @t.overload def __new__( - cls, + cls: "type[HexDump[SubconParsedType, SubconBuildTypes]]", subcon: Construct[SubconParsedType, SubconBuildTypes], - ) -> HexDump[ - SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes - ]: ... + ) -> HexDump[SubconParsedType, SubconBuildTypes]: ... # =============================================================================== # conditional @@ -789,14 +781,14 @@ class Switch(Construct[ParsedType, BuildTypes]): default: Construct[t.Any, t.Any] @t.overload def __new__( - cls, + cls: "type[Switch[int, t.Optional[int]]]", keyfunc: ConstantOrContextLambda[SwitchType], cases: t.Dict[SwitchType, Construct[int, int]], default: t.Optional[Construct[int, int]] = ..., ) -> Switch[int, t.Optional[int]]: ... @t.overload def __new__( - cls, + cls: "type[Switch[t.Any, t.Any]]", keyfunc: ConstantOrContextLambda[t.Any], cases: t.Dict[t.Any, Construct[t.Any, t.Any]], default: t.Optional[Construct[t.Any, t.Any]] = ..., From 26f7fd82dc05a4774e9a575f41a1bfb37ed2a815 Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Mon, 24 Jul 2023 10:14:33 +0200 Subject: [PATCH 14/42] removed unnessesary comment --- construct-stubs/core.pyi | 4 ---- 1 file changed, 4 deletions(-) diff --git a/construct-stubs/core.pyi b/construct-stubs/core.pyi index d138539..aa1c4c7 100644 --- a/construct-stubs/core.pyi +++ b/construct-stubs/core.pyi @@ -25,10 +25,6 @@ from construct.lib import ( # - Higher Kinded Types: https://github.com/python/typing/issues/548 # - Higher Kinded Types: https://sobolevn.me/2020/10/higher-kinded-types-in-python -# unfortunalty the static type checkers "pyright" and "mypy" are slight different. pyright is not fully analysing the type hint of the -# self type in the __init__ (eg. self: Construct[int, int] is not working). but pyright would support such type hints of the return type -# of __new__. indeed mypy doens not support the type inference for the method __new__, but fully supports the annotation of self in __init__... - StreamType = t.IO[bytes] FilenameType = t.Union[str, bytes, os.PathLike[str], os.PathLike[bytes]] PathType = str From 86fddbe2ace94e3d12e3455709aa06cbbc4ee6ed Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Mon, 24 Jul 2023 10:14:52 +0200 Subject: [PATCH 15/42] simplified "IfThenElse" --- construct-stubs/core.pyi | 26 +++++++++++++++----------- tests/test_typed.py | 9 +++++++++ 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/construct-stubs/core.pyi b/construct-stubs/core.pyi index aa1c4c7..23d9c43 100644 --- a/construct-stubs/core.pyi +++ b/construct-stubs/core.pyi @@ -749,25 +749,29 @@ ThenBuildTypes = t.TypeVar("ThenBuildTypes") ElseParsedType = t.TypeVar("ElseParsedType") ElseBuildTypes = t.TypeVar("ElseBuildTypes") -class IfThenElse( - Construct[ - t.Union[ThenParsedType, ElseParsedType], t.Union[ThenBuildTypes, ElseBuildTypes] - ] -): +class IfThenElse(Construct[ParsedType, BuildTypes]): condfunc: ConstantOrContextLambda[bool] - thensubcon: Construct[ThenParsedType, ThenBuildTypes] - elsesubcon: Construct[ElseParsedType, ElseBuildTypes] - def __init__( - self, + thensubcon: Construct[t.Any, t.Any] + elsesubcon: Construct[t.Any, t.Any] + @t.overload + def __new__( + cls: "type[IfThenElse[t.Union[ThenParsedType, ElseParsedType], t.Union[ThenBuildTypes, ElseBuildTypes]]]", condfunc: ConstantOrContextLambda[bool], thensubcon: Construct[ThenParsedType, ThenBuildTypes], elsesubcon: Construct[ElseParsedType, ElseBuildTypes], - ) -> None: ... + ) -> "IfThenElse[t.Union[ThenParsedType, ElseParsedType], t.Union[ThenBuildTypes, ElseBuildTypes]]": ... + @t.overload + def __new__( + cls: "type[IfThenElse[t.Any, t.Any]]", + condfunc: ConstantOrContextLambda[bool], + thensubcon: Construct[t.Any, t.Any], + elsesubcon: Construct[t.Any, t.Any], + ) -> "IfThenElse[t.Any, t.Any]": ... def If( condfunc: ConstantOrContextLambda[bool], subcon: Construct[ThenParsedType, ThenBuildTypes], -) -> IfThenElse[ThenParsedType, None, ThenBuildTypes, None]: ... +) -> IfThenElse[t.Optional[ThenParsedType], t.Optional[ThenBuildTypes]]: ... SwitchType = t.TypeVar("SwitchType") diff --git a/tests/test_typed.py b/tests/test_typed.py index 7d726a3..b85058a 100644 --- a/tests/test_typed.py +++ b/tests/test_typed.py @@ -72,6 +72,15 @@ def test_dataclass_str_repr() -> None: == "Image: \n signature = b'BMP' (total 3)\n width = 3\n height = 2" ) +def test_dataclass_ifthenelse() -> None: + @dataclasses.dataclass + class IfThenElseTest(DataclassMixin): + test_if: t.Optional[int] = csfield(cs.If(False, cs.Int8ub)) + test_ifthenelse: t.Optional[int] = csfield(cs.IfThenElse(True, cs.Int8ub, cs.Pass)) + + a = IfThenElseTest(test_if=None, test_ifthenelse=None) + assert a.test_if == None + assert a.test_ifthenelse == None def test_dataclass_struct() -> None: @dataclasses.dataclass From c6bded59f4a53a8b220707bbddf6b2055dd7dffa Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Mon, 24 Jul 2023 10:56:37 +0200 Subject: [PATCH 16/42] fixes #25 --- construct-stubs/core.pyi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/construct-stubs/core.pyi b/construct-stubs/core.pyi index 23d9c43..34aaf79 100644 --- a/construct-stubs/core.pyi +++ b/construct-stubs/core.pyi @@ -105,10 +105,10 @@ class Construct(t.Generic[ParsedType, BuildTypes]): def build(self, obj: BuildTypes, **contextkw: ContextKWType) -> bytes: ... def build_stream( self, obj: BuildTypes, stream: StreamType, **contextkw: ContextKWType - ) -> bytes: ... + ) -> None: ... def build_file( self, obj: BuildTypes, filename: FilenameType, **contextkw: ContextKWType - ) -> bytes: ... + ) -> None: ... def sizeof(self, **contextkw: ContextKWType) -> int: ... def compile( self, filename: FilenameType = ... From c04a90575d5e68097ed455f918c01e89f1b3d744 Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Mon, 24 Jul 2023 09:58:17 +0200 Subject: [PATCH 17/42] use PEP688 buffer protocol for "parse" Method (fixes #24) --- construct-stubs/core.pyi | 8 ++++++-- setup.py | 5 ++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/construct-stubs/core.pyi b/construct-stubs/core.pyi index 34aaf79..4a28191 100644 --- a/construct-stubs/core.pyi +++ b/construct-stubs/core.pyi @@ -17,6 +17,7 @@ from construct.lib import ( ListType, RebufferedBytesIO, ) +from typing_extensions import Buffer # unfortunately, there are a few duplications with "typing", e.g. Union and Optional, which is why the t. prefix must be used everywhere @@ -25,6 +26,7 @@ from construct.lib import ( # - Higher Kinded Types: https://github.com/python/typing/issues/548 # - Higher Kinded Types: https://sobolevn.me/2020/10/higher-kinded-types-in-python +ReadableBuffer: t.TypeAlias = Buffer StreamType = t.IO[bytes] FilenameType = t.Union[str, bytes, os.PathLike[str], os.PathLike[bytes]] PathType = str @@ -95,7 +97,7 @@ class Construct(t.Generic[ParsedType, BuildTypes]): docs: str flagbuildnone: bool parsed: t.Optional[t.Callable[[ParsedType, Context], None]] - def parse(self, data: bytes, **contextkw: ContextKWType) -> ParsedType: ... + def parse(self, data: ReadableBuffer, **contextkw: ContextKWType) -> ParsedType: ... def parse_stream( self, stream: StreamType, **contextkw: ContextKWType ) -> ParsedType: ... @@ -113,7 +115,9 @@ class Construct(t.Generic[ParsedType, BuildTypes]): def compile( self, filename: FilenameType = ... ) -> Construct[ParsedType, BuildTypes]: ... - def benchmark(self, sampledata: bytes, filename: FilenameType = ...) -> str: ... + def benchmark( + self, sampledata: ReadableBuffer, filename: FilenameType = ... + ) -> str: ... def export_ksy( self, schemaname: str = ..., filename: FilenameType = ... ) -> str: ... diff --git a/setup.py b/setup.py index 54dd52d..aa7b612 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,10 @@ setup( url="https://github.com/timrid/construct-typing", author="Tim Riddermann", python_requires=">=3.7", - install_requires=["construct==2.10.68"], + install_requires=[ + "construct==2.10.68", + "typing_extensions>=4.6.0" + ], keywords=[ "construct", "kaitai", From af1a93c630e5c977699c02c56f34f6ed16ca321a Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Mon, 24 Jul 2023 11:02:39 +0200 Subject: [PATCH 18/42] incremented version to 0.6.0 --- construct_typed/version.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/construct_typed/version.py b/construct_typed/version.py index 740da2f..f097ab1 100644 --- a/construct_typed/version.py +++ b/construct_typed/version.py @@ -1,2 +1,2 @@ -version = (0, 5, 6) -version_string = "0.5.6" +version = (0, 6, 0) +version_string = "0.6.0" From 74593404b1edf6e2d4a7ee2684f13366c3c5f282 Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Mon, 24 Jul 2023 11:55:05 +0200 Subject: [PATCH 19/42] fixed missmatch between stub and runtime type for `Array` --- construct_typed/generic_wrapper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/construct_typed/generic_wrapper.py b/construct_typed/generic_wrapper.py index f570f70..742c267 100644 --- a/construct_typed/generic_wrapper.py +++ b/construct_typed/generic_wrapper.py @@ -39,7 +39,7 @@ else: pass class Array( - t.Generic[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes], + t.Generic[SubconParsedType, SubconBuildTypes], cs.Array, ): pass From af98d2004d0f151e1f4e1e741fe98d5ade1cd9fb Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Mon, 24 Jul 2023 11:56:08 +0200 Subject: [PATCH 20/42] incremented version to 0.6.1 --- construct_typed/version.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/construct_typed/version.py b/construct_typed/version.py index f097ab1..721c684 100644 --- a/construct_typed/version.py +++ b/construct_typed/version.py @@ -1,2 +1,2 @@ -version = (0, 6, 0) -version_string = "0.6.0" +version = (0, 6, 1) +version_string = "0.6.1" From c405d09d5f9b696aee80fe88032e05d92b780798 Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Thu, 3 Aug 2023 09:21:30 +0200 Subject: [PATCH 21/42] fixed error message from `EnumBase` and `FlagsEnumBase` that occures since pyright v1.1.320 --- construct_typed/tenum.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/construct_typed/tenum.py b/construct_typed/tenum.py index a71fb7f..b602f23 100644 --- a/construct_typed/tenum.py +++ b/construct_typed/tenum.py @@ -1,6 +1,8 @@ import enum import typing as t +from typing_extensions import Self + from .generic_wrapper import * @@ -45,7 +47,7 @@ class EnumBase(enum.IntEnum): 'This is the running state.' """ - def __new__(cls, val: t.Union[EnumValue, int]) -> "EnumBase": + def __new__(cls, val: t.Union[EnumValue, int]) -> "Self": if isinstance(val, EnumValue): obj = int.__new__(cls, val.value) obj._value_ = val.value @@ -158,7 +160,7 @@ class FlagsEnumBase(enum.IntFlag): 'This is option two.' """ - def __new__(cls, val: t.Union[EnumValue, int]) -> "FlagsEnumBase": + def __new__(cls, val: t.Union[EnumValue, int]) -> "Self": if isinstance(val, EnumValue): obj = int.__new__(cls, val.value) obj._value_ = val.value From c7e3fc705770afea6c39c17c0265e5481a21ee1b Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Thu, 3 Aug 2023 09:22:33 +0200 Subject: [PATCH 22/42] removed unnessasary `__new__` methods in `DataclassStruct`, `TEnum` and `TFlagsEnum` --- construct_typed/dataclass_struct.py | 9 --------- construct_typed/tenum.py | 16 ---------------- 2 files changed, 25 deletions(-) diff --git a/construct_typed/dataclass_struct.py b/construct_typed/dataclass_struct.py index 8a4c562..f276c99 100644 --- a/construct_typed/dataclass_struct.py +++ b/construct_typed/dataclass_struct.py @@ -153,15 +153,6 @@ class DataclassStruct(Adapter[t.Any, t.Any, DataclassType, DataclassType]): """ subcon: "cs.Struct" - if t.TYPE_CHECKING: - - def __new__( - cls, - dc_type: t.Type[DataclassType], - reverse: bool = False, - ) -> "DataclassStruct[DataclassType]": - ... - def __init__( self, dc_type: t.Type[DataclassType], diff --git a/construct_typed/tenum.py b/construct_typed/tenum.py index b602f23..4ae6c03 100644 --- a/construct_typed/tenum.py +++ b/construct_typed/tenum.py @@ -91,14 +91,6 @@ class TEnum(Adapter[int, int, EnumType, EnumType]): """ Typed enum. """ - - if t.TYPE_CHECKING: - - def __new__( - cls, subcon: Construct[int, int], enum_type: t.Type[EnumType] - ) -> "TEnum[EnumType]": - ... - def __init__(self, subcon: Construct[int, int], enum_type: t.Type[EnumType]): if not issubclass(enum_type, EnumBase): raise TypeError( @@ -195,14 +187,6 @@ class TFlagsEnum(Adapter[int, int, FlagsEnumType, FlagsEnumType]): """ Typed enum. """ - - if t.TYPE_CHECKING: - - def __new__( - cls, subcon: Construct[int, int], enum_type: t.Type[FlagsEnumType] - ) -> "TFlagsEnum[FlagsEnumType]": - ... - def __init__(self, subcon: Construct[int, int], enum_type: t.Type[FlagsEnumType]): if not issubclass(enum_type, FlagsEnumBase): raise TypeError( From 2ffa785ce60800d58523c394603bcd1bb409fde1 Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Thu, 3 Aug 2023 09:27:59 +0200 Subject: [PATCH 23/42] incremented version to 0.6.2 --- construct_typed/version.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/construct_typed/version.py b/construct_typed/version.py index 721c684..b1bde74 100644 --- a/construct_typed/version.py +++ b/construct_typed/version.py @@ -1,2 +1,2 @@ -version = (0, 6, 1) -version_string = "0.6.1" +version = (0, 6, 2) +version_string = "0.6.2" From 9957b0e6f127132ef8341c1d69733d183a80303b Mon Sep 17 00:00:00 2001 From: Prilkop Date: Mon, 17 Jun 2024 15:46:04 +0300 Subject: [PATCH 24/42] added internal Construct methods, used when inheriting the class --- construct-stubs/core.pyi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/construct-stubs/core.pyi b/construct-stubs/core.pyi index 4a28191..70c7876 100644 --- a/construct-stubs/core.pyi +++ b/construct-stubs/core.pyi @@ -138,6 +138,10 @@ class Construct(t.Generic[ParsedType, BuildTypes]): def __getitem__( self, count: t.Union[int, t.Callable[[Context], int]] ) -> Array[ParsedType, BuildTypes,]: ... + def _parse(self, stream: StreamType, context: Context, path: PathType) -> ParsedType: ... + def _parsereport(self, stream: StreamType, context: Context, path: PathType) -> ParsedType: ... + def _build(self, obj: BuildTypes, stream: StreamType, context: Context, path: PathType) -> int: ... + def _sizeof(self, context: Context, path: PathType) -> int: ... @t.type_check_only class Context(Container[t.Any]): From 647c273bff48d439fa405dfab9fa19217760dd5c Mon Sep 17 00:00:00 2001 From: Tim Rid <6593626+timrid@users.noreply.github.com> Date: Sun, 12 Jan 2025 11:52:00 +0100 Subject: [PATCH 25/42] Added Python 3.12 and 3.13 to the CI --- .github/workflows/main.yml | 4 ++-- setup.py | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3bdc963..1424f0e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,6 +1,6 @@ name: CI -on: [push, pull_request] +on: [push, pull_request, workflow_dispatch] jobs: build: @@ -8,7 +8,7 @@ jobs: strategy: matrix: os: ['ubuntu-latest', 'windows-latest'] - python-version: [ '3.7', '3.8', '3.9', '3.10', '3.11' ] + python-version: [ '3.7', '3.8', '3.9', '3.10', '3.11', '3.12', '3.13' ] runs-on: ${{ matrix.os }} name: OS ${{ matrix.os }}, Python ${{ matrix.python-version }} diff --git a/setup.py b/setup.py index aa7b612..0d25363 100644 --- a/setup.py +++ b/setup.py @@ -63,6 +63,8 @@ setup( "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Programming Language :: Python :: Implementation :: CPython", "Typing :: Typed", ], From bbeb5b185f442e319ae4678a126007b9bd4465db Mon Sep 17 00:00:00 2001 From: Tim Rid <6593626+timrid@users.noreply.github.com> Date: Sun, 12 Jan 2025 11:58:33 +0100 Subject: [PATCH 26/42] removed Python Versions with EOL (3.7, 3.8) --- .github/workflows/main.yml | 2 +- setup.py | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1424f0e..46d379a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -8,7 +8,7 @@ jobs: strategy: matrix: os: ['ubuntu-latest', 'windows-latest'] - python-version: [ '3.7', '3.8', '3.9', '3.10', '3.11', '3.12', '3.13' ] + python-version: [ '3.9', '3.10', '3.11', '3.12', '3.13' ] runs-on: ${{ matrix.os }} name: OS ${{ matrix.os }}, Python ${{ matrix.python-version }} diff --git a/setup.py b/setup.py index 0d25363..cf5ca66 100644 --- a/setup.py +++ b/setup.py @@ -58,8 +58,6 @@ setup( "Topic :: Software Development :: Build Tools", "Topic :: Software Development :: Code Generators", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", From 457857389adc8d1bb78aff29cad40a3e21c3d975 Mon Sep 17 00:00:00 2001 From: Tim Rid <6593626+timrid@users.noreply.github.com> Date: Sun, 12 Jan 2025 12:22:45 +0100 Subject: [PATCH 27/42] According to PEP688 (https://peps.python.org/pep-0688/#removal-of-the-bytes-special-case) `bytes` has not any special meaning any more. So `bytearray` is not included in `bytes` any more and we have to declare it explicitly. `collections.abc.Buffer` cant be used, because `memoryview` is not supported by `construct` --- construct-stubs/core.pyi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/construct-stubs/core.pyi b/construct-stubs/core.pyi index 4a28191..88173c2 100644 --- a/construct-stubs/core.pyi +++ b/construct-stubs/core.pyi @@ -221,14 +221,14 @@ class Compiled(Construct[t.Any, t.Any]): # =============================================================================== # bytes and bits # =============================================================================== -class Bytes(Construct[bytes, t.Union[bytes, int]]): +class Bytes(Construct[bytes, t.Union[bytes, bytearray, int]]): length: ConstantOrContextLambda[int] def __init__( self, length: ConstantOrContextLambda[int], ) -> None: ... -GreedyBytes: Construct[bytes, bytes] +GreedyBytes: Construct[bytes, t.Union[bytes, bytearray]] def Bitwise( subcon: Construct[SubconParsedType, SubconBuildTypes] From a2a6be536f737ede3164a6bbf00509152d671ef2 Mon Sep 17 00:00:00 2001 From: Tim Rid <6593626+timrid@users.noreply.github.com> Date: Sun, 12 Jan 2025 12:33:51 +0100 Subject: [PATCH 28/42] satisfy pyright 1.1.391 --- construct-stubs/core.pyi | 8 ++++---- construct-stubs/expr.pyi | 4 ++-- construct-stubs/lib/containers.pyi | 2 +- construct_typed/dataclass_struct.py | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/construct-stubs/core.pyi b/construct-stubs/core.pyi index 88173c2..36863e6 100644 --- a/construct-stubs/core.pyi +++ b/construct-stubs/core.pyi @@ -169,7 +169,7 @@ class Subconstruct( subcon: Construct[SubconParsedType, SubconBuildTypes], ) -> None: ... @t.overload - def __init__( + def __init__( # type: ignore self, *args: t.Any, **kwargs: t.Any, @@ -1110,9 +1110,9 @@ class Lazy( 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]: ... - def values(self) -> t.List[ContainerType]: ... - def items(self) -> t.List[t.Tuple[str, ContainerType]]: ... + def keys(self) -> t.Iterator[str]: ... # type: ignore + def values(self) -> t.List[ContainerType]: ... # type: ignore + def items(self) -> t.List[t.Tuple[str, ContainerType]]: ... # type: ignore class LazyStruct(Construct[LazyContainer[t.Any], t.Optional[t.Dict[str, t.Any]]]): subcons: t.List[Construct[t.Any, t.Any]] diff --git a/construct-stubs/expr.pyi b/construct-stubs/expr.pyi index 3d1b032..a7c1a1a 100644 --- a/construct-stubs/expr.pyi +++ b/construct-stubs/expr.pyi @@ -469,7 +469,7 @@ class ExprMixin(t.Generic[ReturnType], object): @t.overload def __eq__(self: ExprMixin[float], other: ConstOrCallable[float]) -> BinExpr[bool]: ... @t.overload - def __eq__(self, other: t.Any) -> BinExpr[t.Any]: ... + def __eq__(self, other: ConstOrCallable[t.Any]) -> BinExpr[t.Any]: ... # type: ignore # __ne__ ########################################################################################################### @t.overload @@ -487,7 +487,7 @@ class ExprMixin(t.Generic[ReturnType], object): @t.overload def __ne__(self: ExprMixin[float], other: ConstOrCallable[float]) -> BinExpr[bool]: ... @t.overload - def __ne__(self, other: t.Any) -> BinExpr[t.Any]: ... + def __ne__(self, other: t.Any) -> BinExpr[t.Any]: ... # type: ignore # __neg__ ########################################################################################################## @t.overload diff --git a/construct-stubs/lib/containers.pyi b/construct-stubs/lib/containers.pyi index a50033a..37efc75 100644 --- a/construct-stubs/lib/containers.pyi +++ b/construct-stubs/lib/containers.pyi @@ -19,7 +19,7 @@ def recursion_lock( class Container(t.Generic[ContainerType], t.Dict[str, ContainerType]): def __getattr__(self, name: str) -> ContainerType: ... - def update( + def update( # type: ignore self, seqordict: t.Union[t.Dict[str, ContainerType], t.Tuple[str, ContainerType]], ) -> None: ... diff --git a/construct_typed/dataclass_struct.py b/construct_typed/dataclass_struct.py index f276c99..e6ca2e8 100644 --- a/construct_typed/dataclass_struct.py +++ b/construct_typed/dataclass_struct.py @@ -152,13 +152,13 @@ class DataclassStruct(Adapter[t.Any, t.Any, DataclassType, DataclassType]): Image(width=1, height=2, pixels=b'12') """ - subcon: "cs.Struct" + subcon: "cs.Struct" # type: ignore def __init__( self, dc_type: t.Type[DataclassType], reverse: bool = False, ) -> None: - if not issubclass(dc_type, DataclassMixin): + if not issubclass(dc_type, DataclassMixin): # type: ignore raise TypeError(f"'{repr(dc_type)}' has to be a '{repr(DataclassMixin)}'") if not dataclasses.is_dataclass(dc_type): raise TypeError(f"'{repr(dc_type)}' has to be a 'dataclasses.dataclass'") From f01246ae823fa1a2490e4a992d5d2bb9a1ba3c90 Mon Sep 17 00:00:00 2001 From: Tim Rid <6593626+timrid@users.noreply.github.com> Date: Sun, 12 Jan 2025 12:43:04 +0100 Subject: [PATCH 29/42] Since Python 3.13 the compiler now strips common leading whitespace from every line in a docstring. So this have to be fixed in the pytests. --- tests/test_typed.py | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/tests/test_typed.py b/tests/test_typed.py index b85058a..df8cc84 100644 --- a/tests/test_typed.py +++ b/tests/test_typed.py @@ -2,9 +2,11 @@ # pyright: strict import dataclasses import enum +import textwrap import typing as t import construct as cs + import construct_typed as cst from construct_typed import DataclassBitStruct, DataclassMixin, DataclassStruct, csfield @@ -72,16 +74,20 @@ def test_dataclass_str_repr() -> None: == "Image: \n signature = b'BMP' (total 3)\n width = 3\n height = 2" ) + def test_dataclass_ifthenelse() -> None: @dataclasses.dataclass class IfThenElseTest(DataclassMixin): test_if: t.Optional[int] = csfield(cs.If(False, cs.Int8ub)) - test_ifthenelse: t.Optional[int] = csfield(cs.IfThenElse(True, cs.Int8ub, cs.Pass)) + test_ifthenelse: t.Optional[int] = csfield( + cs.IfThenElse(True, cs.Int8ub, cs.Pass) + ) a = IfThenElseTest(test_if=None, test_ifthenelse=None) assert a.test_if == None assert a.test_ifthenelse == None + def test_dataclass_struct() -> None: @dataclasses.dataclass class Image(DataclassMixin): @@ -395,9 +401,10 @@ def test_tenum_no_enumbase() -> None: def test_tenum_asdict() -> None: # see: https://github.com/timrid/construct-typing/issues/21 - import construct_typed as cst import dataclasses + import construct_typed as cst + class TestEnum(cst.EnumBase): one = 1 two = 2 @@ -436,9 +443,9 @@ def test_tenum_docstring() -> None: Value_NoDoc = cst.EnumValue(2) Value_NoDoc2 = 3 - assert ( - TestEnum.__doc__ - == """ + assert TestEnum.__doc__ is not None + assert textwrap.dedent(TestEnum.__doc__) == textwrap.dedent( + """ This is an test enum. """ ) @@ -508,9 +515,10 @@ def test_tenum_flags() -> None: def test_tenum_flags_asdict() -> None: - import construct_typed as cst import dataclasses + import construct_typed as cst + class TestEnum(cst.FlagsEnumBase): one = 1 two = 2 @@ -549,9 +557,9 @@ def test_tenum_flags_docstring() -> None: Value_NoDoc = cst.EnumValue(2) Value_NoDoc2 = 4 - assert ( - TestEnum.__doc__ - == """ + assert TestEnum.__doc__ is not None + assert textwrap.dedent(TestEnum.__doc__) == textwrap.dedent( + """ This is an test flags enum. """ ) From a222fe769537828b5b2a37f0c7ba5098c49cfb2b Mon Sep 17 00:00:00 2001 From: Tim Rid <6593626+timrid@users.noreply.github.com> Date: Sun, 12 Jan 2025 13:01:00 +0100 Subject: [PATCH 30/42] print pyright version in CI --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 46d379a..daadc0d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -35,6 +35,7 @@ jobs: - name: Install pyright run: | npm install -g pyright + pyright --version # Install this package - name: Install this package From 04e1bc0c612428d324c6897fcf46d47b9797ffd8 Mon Sep 17 00:00:00 2001 From: Tim Rid <6593626+timrid@users.noreply.github.com> Date: Sun, 12 Jan 2025 15:35:54 +0100 Subject: [PATCH 31/42] updated to construct==2.10.70 --- construct-stubs/core.pyi | 81 +++++++++++++++++----- requirements.txt | 5 +- setup.py | 2 +- tests/test_core.py | 142 +++++++++++++++++++++++++++++++++++++-- 4 files changed, 205 insertions(+), 25 deletions(-) diff --git a/construct-stubs/core.pyi b/construct-stubs/core.pyi index 78609a4..ef6e20e 100644 --- a/construct-stubs/core.pyi +++ b/construct-stubs/core.pyi @@ -17,6 +17,9 @@ from construct.lib import ( ListType, RebufferedBytesIO, ) +from cryptography.hazmat.primitives.ciphers import Cipher +from cryptography.hazmat.primitives.ciphers.aead import AESCCM, AESGCM, ChaCha20Poly1305 +from cryptography.hazmat.primitives.ciphers.modes import Mode from typing_extensions import Buffer # unfortunately, there are a few duplications with "typing", e.g. Union and Optional, which is why the t. prefix must be used everywhere @@ -67,6 +70,7 @@ class RawCopyError(ConstructError): ... class RotationError(ConstructError): ... class ChecksumError(ConstructError): ... class CancelParsing(ConstructError): ... +class CipherError(ConstructError): ... # =============================================================================== # used internally @@ -86,6 +90,17 @@ def stream_size(stream: StreamType) -> int: ... def stream_iseof(stream: StreamType) -> bool: ... def evaluate(param: ConstantOrContextLambda2[T], context: Context) -> T: ... +class BytesIOWithOffsets(io.BytesIO): + @staticmethod + def from_reading( + stream: StreamType, length: int, path: PathType + ) -> BytesIOWithOffsets: ... + def __init__( + self, contents: bytes, parent_stream: StreamType, offset: int + ) -> None: ... + def tell(self) -> int: ... + def seek(self, offset: int, whence: int = ...) -> int: ... + # =============================================================================== # abstract constructs # =============================================================================== @@ -135,12 +150,19 @@ class Construct(t.Generic[ParsedType, BuildTypes]): ) -> Renamed[ParsedType, BuildTypes]: ... def __add__(self, other: Construct[t.Any, t.Any]) -> Struct: ... def __rshift__(self, other: Construct[t.Any, t.Any]) -> Sequence: ... - def __getitem__( - self, count: t.Union[int, t.Callable[[Context], int]] - ) -> Array[ParsedType, BuildTypes,]: ... - def _parse(self, stream: StreamType, context: Context, path: PathType) -> ParsedType: ... - def _parsereport(self, stream: StreamType, context: Context, path: PathType) -> ParsedType: ... - def _build(self, obj: BuildTypes, stream: StreamType, context: Context, path: PathType) -> int: ... + def __getitem__(self, count: t.Union[int, t.Callable[[Context], int]]) -> Array[ + ParsedType, + BuildTypes, + ]: ... + def _parse( + self, stream: StreamType, context: Context, path: PathType + ) -> ParsedType: ... + def _parsereport( + self, stream: StreamType, context: Context, path: PathType + ) -> ParsedType: ... + def _build( + self, obj: BuildTypes, stream: StreamType, context: Context, path: PathType + ) -> int: ... def _sizeof(self, context: Context, path: PathType) -> int: ... @t.type_check_only @@ -234,15 +256,11 @@ class Bytes(Construct[bytes, t.Union[bytes, bytearray, int]]): GreedyBytes: Construct[bytes, t.Union[bytes, bytearray]] -def Bitwise( - subcon: Construct[SubconParsedType, SubconBuildTypes] -) -> t.Union[ +def Bitwise(subcon: Construct[SubconParsedType, SubconBuildTypes]) -> t.Union[ Transformed[SubconParsedType, SubconBuildTypes], Restreamed[SubconParsedType, SubconBuildTypes], ]: ... -def Bytewise( - subcon: Construct[SubconParsedType, SubconBuildTypes] -) -> t.Union[ +def Bytewise(subcon: Construct[SubconParsedType, SubconBuildTypes]) -> t.Union[ Transformed[SubconParsedType, SubconBuildTypes], Restreamed[SubconParsedType, SubconBuildTypes], ]: ... @@ -880,6 +898,16 @@ class Peek( subcon: Construct[SubconParsedType, SubconBuildTypes], ) -> None: ... +class OffsettedEnd( + Subconstruct[SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes] +): + endoffset: ConstantOrContextLambda[int] + def __init__( + self, + endoffset: ConstantOrContextLambda[int], + subcon: Construct[SubconParsedType, SubconBuildTypes], + ) -> None: ... + class Seek(Construct[int, None]): at: ConstantOrContextLambda[int] if sys.version_info >= (3, 8): @@ -924,9 +952,7 @@ class RawCopy( def ByteSwapped( subcon: Construct[SubconParsedType, SubconBuildTypes] ) -> Transformed[SubconParsedType, SubconBuildTypes]: ... -def BitsSwapped( - subcon: Construct[SubconParsedType, SubconBuildTypes] -) -> t.Union[ +def BitsSwapped(subcon: Construct[SubconParsedType, SubconBuildTypes]) -> t.Union[ Transformed[SubconParsedType, SubconBuildTypes], Restreamed[SubconParsedType, SubconBuildTypes], ]: ... @@ -946,7 +972,10 @@ class Prefixed( def PrefixedArray( countfield: Construct[int, int], subcon: Construct[SubconParsedType, SubconBuildTypes], -) -> Array[SubconParsedType, SubconBuildTypes,]: ... +) -> Array[ + SubconParsedType, + SubconBuildTypes, +]: ... class FixedSized( Subconstruct[SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes] @@ -1095,6 +1124,26 @@ class Rebuffered( tailcutoff: t.Optional[int] = ..., ) -> None: ... +class EncryptedSym(Tunnel[SubconParsedType, SubconBuildTypes]): + cipher: ConstantOrContextLambda2[Cipher[Mode]] + def __init__( + self, + subcon: Construct[SubconParsedType, SubconBuildTypes], + cipher: ConstantOrContextLambda2[Cipher[Mode]], + ) -> None: ... + +class EncryptedSymAead(Tunnel[SubconParsedType, SubconBuildTypes]): + cipher: ConstantOrContextLambda2[t.Union[AESGCM, AESCCM, ChaCha20Poly1305]] + nonce: ConstantOrContextLambda2[bytes] + associated_data: ConstantOrContextLambda2[bytes] + def __init__( + self, + subcon: Construct[SubconParsedType, SubconBuildTypes], + cipher: ConstantOrContextLambda2[t.Union[AESGCM, AESCCM, ChaCha20Poly1305]], + nonce: ConstantOrContextLambda2[bytes], + associated_data: ConstantOrContextLambda2[bytes] = ..., + ) -> None: ... + # =============================================================================== # lazy equivalents # =============================================================================== diff --git a/requirements.txt b/requirements.txt index d1c8be1..a50644c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -construct==2.10.68 +construct==2.10.70 pytest>=6.2.0 numpy arrow @@ -7,4 +7,5 @@ cloudpickle lz4 black isort -mypy \ No newline at end of file +mypy +cryptography diff --git a/setup.py b/setup.py index cf5ca66..00a4b6d 100644 --- a/setup.py +++ b/setup.py @@ -22,7 +22,7 @@ setup( author="Tim Riddermann", python_requires=">=3.7", install_requires=[ - "construct==2.10.68", + "construct==2.10.70", "typing_extensions>=4.6.0" ], keywords=[ diff --git a/tests/test_core.py b/tests/test_core.py index b31cd6b..e697f36 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -150,18 +150,30 @@ def test_formatfield_bool_issue_901() -> None: assert d.build(False) == b"\x00" assert d.sizeof() == 1 -def test_bytesinteger() -> None: +def test_bytesinteger(): + d = BytesInteger(0) + assert raises(d.parse, b"") == IntegerError + assert raises(d.build, 0) == IntegerError d = BytesInteger(4, signed=True, swapped=False) common(d, b"\x01\x02\x03\x04", 0x01020304, 4) common(d, b"\xff\xff\xff\xff", -1, 4) d = BytesInteger(4, signed=False, swapped=this.swapped) common(d, b"\x01\x02\x03\x04", 0x01020304, 4, swapped=False) common(d, b"\x04\x03\x02\x01", 0x01020304, 4, swapped=True) + assert raises(BytesInteger(-1).parse, b"") == IntegerError + assert raises(BytesInteger(-1).build, 0) == IntegerError + assert raises(BytesInteger(8).build, None) == IntegerError + assert raises(BytesInteger(8, signed=False).build, -1) == IntegerError + assert raises(BytesInteger(8, True).build, -2**64) == IntegerError + assert raises(BytesInteger(8, True).build, 2**64) == IntegerError + assert raises(BytesInteger(8, False).build, -2**64) == IntegerError + assert raises(BytesInteger(8, False).build, 2**64) == IntegerError assert raises(BytesInteger(this.missing).sizeof) == SizeofError - assert raises(BytesInteger(4, signed=False).build, -1) == IntegerError - common(BytesInteger(0), b"", 0, 0) -def test_bitsinteger() -> None: +def test_bitsinteger(): + d = BitsInteger(0) + assert raises(d.parse, b"") == IntegerError + assert raises(d.build, 0) == IntegerError d = BitsInteger(8) common(d, b"\x01\x01\x01\x01\x01\x01\x01\x01", 255, 8) d = BitsInteger(8, signed=True) @@ -171,9 +183,17 @@ def test_bitsinteger() -> None: d = BitsInteger(16, swapped=this.swapped) common(d, b"\x01\x01\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00", 0xff00, 16, swapped=False) common(d, b"\x00\x00\x00\x00\x00\x00\x00\x00\x01\x01\x01\x01\x01\x01\x01\x01", 0xff00, 16, swapped=True) - assert raises(BitsInteger(this.missing).sizeof) == SizeofError + assert raises(BitsInteger(-1).parse, b"") == IntegerError + assert raises(BitsInteger(-1).build, 0) == IntegerError + assert raises(BitsInteger(5, swapped=True).parse, bytes(5)) == IntegerError + assert raises(BitsInteger(5, swapped=True).build, 0) == IntegerError + assert raises(BitsInteger(8).build, None) == IntegerError assert raises(BitsInteger(8, signed=False).build, -1) == IntegerError - common(BitsInteger(0), b"", 0, 0) + assert raises(BitsInteger(8, True).build, -2**64) == IntegerError + assert raises(BitsInteger(8, True).build, 2**64) == IntegerError + assert raises(BitsInteger(8, False).build, -2**64) == IntegerError + assert raises(BitsInteger(8, False).build, 2**64) == IntegerError + assert raises(BitsInteger(this.missing).sizeof) == SizeofError def test_varint() -> None: d = VarInt @@ -926,6 +946,17 @@ def test_peek() -> None: assert d4.build(Container(a=0x01, b=0x0102)) == b"" assert d4.sizeof() == 0 +def test_offsettedend(): + d = Struct( + "header" / Bytes(2), + "data" / OffsettedEnd(-2, GreedyBytes), + "footer" / Bytes(2), + ) + common(d, b"\x01\x02\x03\x04\x05\x06\x07", Container(header=b'\x01\x02', data=b'\x03\x04\x05', footer=b'\x06\x07')) + + d = OffsettedEnd(0, Byte) + assert raises(d.sizeof) == SizeofError + def test_seek() -> None: d = Seek(5) assert d.parse(b"") == 5 @@ -1334,6 +1365,105 @@ def test_compressed_prefixed() -> None: assert st.parse(st.build(Container(one=zeros,two=zeros))) == Container(one=zeros,two=zeros) assert raises(d.sizeof) == SizeofError +@pytest.mark.xfail(ONWINDOWS and PYPY, reason="no wheel for 'cryptography' is currently available for pypy on windows") +def test_encryptedsym(): + from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes + key128 = b"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + key256 = b"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + iv = b"\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + nonce = iv + + # AES 128/256 bit - ECB + d = EncryptedSym(GreedyBytes, lambda ctx: Cipher(algorithms.AES(ctx.key), modes.ECB())) + common(d, b"\xf4\x0f\x54\xb7\x6a\x7a\xf1\xdb\x92\x73\x14\xde\x2f\xa0\x3e\x2d", b'Secret Message..', key=key128, iv=iv) + common(d, b"\x82\x6b\x01\x82\x90\x02\xa1\x9e\x35\x0a\xe2\xc3\xee\x1a\x42\xf5", b'Secret Message..', key=key256, iv=iv) + + # AES 128/256 bit - CBC + d = EncryptedSym(GreedyBytes, lambda ctx: Cipher(algorithms.AES(ctx.key), modes.CBC(ctx.iv))) + common(d, b"\xba\x79\xc2\x62\x22\x08\x29\xb9\xfb\xd3\x90\xc4\x04\xb7\x55\x87", b'Secret Message..', key=key128, iv=iv) + common(d, b"\x60\xc2\x45\x0d\x7e\x41\xd4\xf8\x85\xd4\x8a\x64\xd1\x45\x49\xe3", b'Secret Message..', key=key256, iv=iv) + + # AES 128/256 bit - CTR + d = EncryptedSym(GreedyBytes, lambda ctx: Cipher(algorithms.AES(ctx.key), modes.CTR(ctx.nonce))) + common(d, b"\x80\x78\xb6\x0c\x07\xf5\x0c\x90\xce\xa2\xbf\xcb\x5b\x22\xb9\xb5", b'Secret Message..', key=key128, nonce=nonce) + common(d, b"\x6a\xae\x7b\x86\x1a\xa6\xe0\x6a\x49\x02\x02\x1b\xf2\x3c\xd8\x0d", b'Secret Message..', key=key256, nonce=nonce) + + assert raises(EncryptedSym(GreedyBytes, "AES").build, b"") == CipherError # type: ignore + assert raises(EncryptedSym(GreedyBytes, "AES").parse, b"") == CipherError # type: ignore + +@pytest.mark.xfail(ONWINDOWS and PYPY, reason="no wheel for 'cryptography' is currently available for pypy on windows") +def test_encryptedsym_cbc_example(): + from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes + d = Struct( + "iv" / Default(Bytes(16), os.urandom(16)), + "enc_data" / EncryptedSym( + Aligned(16, + Struct( + "width" / Int16ul, + "height" / Int16ul + ) + ), + lambda ctx: Cipher(algorithms.AES(ctx._.key), modes.CBC(ctx.iv)) + ) + ) + key128 = b"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + byts = d.build({"enc_data": {"width": 5, "height": 4}}, key=key128) + obj = d.parse(byts, key=key128) + assert obj.enc_data == Container(width=5, height=4) + +@pytest.mark.xfail(ONWINDOWS and PYPY, reason="no wheel for 'cryptography' is currently available for pypy on windows") +def test_encryptedsymaead(): + from cryptography.hazmat.primitives.ciphers import aead + key128 = b"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + key256 = b"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + nonce = b"\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + + # AES 128/256 bit - GCM + d = Struct( + "associated_data" / Bytes(21), + "data" / EncryptedSymAead( + GreedyBytes, + lambda ctx: aead.AESGCM(ctx._.key), + this._.nonce, + this.associated_data + ) + ) + common( + d, + b"This is authenticated\xb6\xd3\x64\x0c\x7a\x31\xaa\x16\xa3\x58\xec\x17\x39\x99\x2e\xf8\x4e\x41\x17\x76\x3f\xd1\x06\x47\x04\x9f\x42\x1c\xf4\xa9\xfd\x99\x9c\xe9", + Container(associated_data=b"This is authenticated", data=b"The secret message"), + key=key128, + nonce=nonce + ) + common( + d, + b"This is authenticated\xde\xb4\x41\x79\xc8\x7f\xea\x8d\x0e\x41\xf6\x44\x2f\x93\x21\xe6\x37\xd1\xd3\x29\xa4\x97\xc3\xb5\xf4\x81\x72\xa1\x7f\x3b\x9b\x53\x24\xe4", + Container(associated_data=b"This is authenticated", data=b"The secret message"), + key=key256, + nonce=nonce + ) + assert raises(EncryptedSymAead(GreedyBytes, "AESGCM", bytes(16)).build, b"") == CipherError # type: ignore + assert raises(EncryptedSymAead(GreedyBytes, "AESGCM", bytes(16)).parse, b"") == CipherError # type: ignore + +@pytest.mark.xfail(ONWINDOWS and PYPY, reason="no wheel for 'cryptography' is currently available for pypy on windows") +def test_encryptedsymaead_gcm_example(): + from cryptography.hazmat.primitives.ciphers import aead + d = Struct( + "nonce" / Default(Bytes(16), os.urandom(16)), + "associated_data" / Bytes(21), + "enc_data" / EncryptedSymAead( + GreedyBytes, + lambda ctx: aead.AESGCM(ctx._.key), + this.nonce, + this.associated_data + ) + ) + key128 = b"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + byts = d.build({"associated_data": b"This is authenticated", "enc_data": b"The secret message"}, key=key128) + obj = d.parse(byts, key=key128) + assert obj.enc_data == b"The secret message" + assert obj.associated_data == b"This is authenticated" + def test_rebuffered() -> None: data = b"0" * 1000 assert Rebuffered(Array(1000,Byte)).parse_stream(io.BytesIO(data)) == [48]*1000 From a9f4b448010848136c7ee42541114932da21349d Mon Sep 17 00:00:00 2001 From: Tim Rid <6593626+timrid@users.noreply.github.com> Date: Sun, 12 Jan 2025 15:39:57 +0100 Subject: [PATCH 32/42] fixed mypy errors --- tests/test_core.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/test_core.py b/tests/test_core.py index e697f36..602a899 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -150,7 +150,7 @@ def test_formatfield_bool_issue_901() -> None: assert d.build(False) == b"\x00" assert d.sizeof() == 1 -def test_bytesinteger(): +def test_bytesinteger() -> None: d = BytesInteger(0) assert raises(d.parse, b"") == IntegerError assert raises(d.build, 0) == IntegerError @@ -170,7 +170,7 @@ def test_bytesinteger(): assert raises(BytesInteger(8, False).build, 2**64) == IntegerError assert raises(BytesInteger(this.missing).sizeof) == SizeofError -def test_bitsinteger(): +def test_bitsinteger() -> None: d = BitsInteger(0) assert raises(d.parse, b"") == IntegerError assert raises(d.build, 0) == IntegerError @@ -946,16 +946,16 @@ def test_peek() -> None: assert d4.build(Container(a=0x01, b=0x0102)) == b"" assert d4.sizeof() == 0 -def test_offsettedend(): - d = Struct( +def test_offsettedend() -> None: + d1 = Struct( "header" / Bytes(2), "data" / OffsettedEnd(-2, GreedyBytes), "footer" / Bytes(2), ) - common(d, b"\x01\x02\x03\x04\x05\x06\x07", Container(header=b'\x01\x02', data=b'\x03\x04\x05', footer=b'\x06\x07')) + common(d1, b"\x01\x02\x03\x04\x05\x06\x07", Container(header=b'\x01\x02', data=b'\x03\x04\x05', footer=b'\x06\x07')) - d = OffsettedEnd(0, Byte) - assert raises(d.sizeof) == SizeofError + d2 = OffsettedEnd(0, Byte) + assert raises(d2.sizeof) == SizeofError def test_seek() -> None: d = Seek(5) @@ -1366,7 +1366,7 @@ def test_compressed_prefixed() -> None: assert raises(d.sizeof) == SizeofError @pytest.mark.xfail(ONWINDOWS and PYPY, reason="no wheel for 'cryptography' is currently available for pypy on windows") -def test_encryptedsym(): +def test_encryptedsym() -> None: from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes key128 = b"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" key256 = b"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" @@ -1392,7 +1392,7 @@ def test_encryptedsym(): assert raises(EncryptedSym(GreedyBytes, "AES").parse, b"") == CipherError # type: ignore @pytest.mark.xfail(ONWINDOWS and PYPY, reason="no wheel for 'cryptography' is currently available for pypy on windows") -def test_encryptedsym_cbc_example(): +def test_encryptedsym_cbc_example() -> None: from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes d = Struct( "iv" / Default(Bytes(16), os.urandom(16)), @@ -1412,7 +1412,7 @@ def test_encryptedsym_cbc_example(): assert obj.enc_data == Container(width=5, height=4) @pytest.mark.xfail(ONWINDOWS and PYPY, reason="no wheel for 'cryptography' is currently available for pypy on windows") -def test_encryptedsymaead(): +def test_encryptedsymaead() -> None: from cryptography.hazmat.primitives.ciphers import aead key128 = b"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" key256 = b"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" @@ -1446,7 +1446,7 @@ def test_encryptedsymaead(): assert raises(EncryptedSymAead(GreedyBytes, "AESGCM", bytes(16)).parse, b"") == CipherError # type: ignore @pytest.mark.xfail(ONWINDOWS and PYPY, reason="no wheel for 'cryptography' is currently available for pypy on windows") -def test_encryptedsymaead_gcm_example(): +def test_encryptedsymaead_gcm_example() -> None: from cryptography.hazmat.primitives.ciphers import aead d = Struct( "nonce" / Default(Bytes(16), os.urandom(16)), From c5ffc142bef32fbd45b867f23e57977c6f2dfc9c Mon Sep 17 00:00:00 2001 From: Olivier Morelle Date: Sun, 26 Oct 2025 20:40:54 +0100 Subject: [PATCH 33/42] fix(core.pyi): replaces typing.TypeAlias by typing_extensions.TypeAlias for compatibility with python3.9 --- construct-stubs/core.pyi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/construct-stubs/core.pyi b/construct-stubs/core.pyi index ef6e20e..456ab4a 100644 --- a/construct-stubs/core.pyi +++ b/construct-stubs/core.pyi @@ -20,7 +20,7 @@ from construct.lib import ( from cryptography.hazmat.primitives.ciphers import Cipher from cryptography.hazmat.primitives.ciphers.aead import AESCCM, AESGCM, ChaCha20Poly1305 from cryptography.hazmat.primitives.ciphers.modes import Mode -from typing_extensions import Buffer +from typing_extensions import Buffer, TypeAlias # unfortunately, there are a few duplications with "typing", e.g. Union and Optional, which is why the t. prefix must be used everywhere @@ -29,7 +29,7 @@ from typing_extensions import Buffer # - Higher Kinded Types: https://github.com/python/typing/issues/548 # - Higher Kinded Types: https://sobolevn.me/2020/10/higher-kinded-types-in-python -ReadableBuffer: t.TypeAlias = Buffer +ReadableBuffer: TypeAlias = Buffer StreamType = t.IO[bytes] FilenameType = t.Union[str, bytes, os.PathLike[str], os.PathLike[bytes]] PathType = str From a3287676891c02838ff845336e735e54ece262fa Mon Sep 17 00:00:00 2001 From: Tim Rid <6593626+timrid@users.noreply.github.com> Date: Mon, 27 Oct 2025 19:33:50 +0100 Subject: [PATCH 34/42] replaced setup.py with pyproject.toml --- .github/workflows/python-publish.yml | 4 +- mypy.ini | 3 -- pyproject.toml | 76 ++++++++++++++++++++++++++++ requirements.txt | 3 ++ setup.py | 69 ------------------------- 5 files changed, 81 insertions(+), 74 deletions(-) delete mode 100644 mypy.ini create mode 100644 pyproject.toml delete mode 100644 setup.py diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 4e1ef42..05cfb95 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -21,11 +21,11 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install setuptools wheel twine + pip install setuptools wheel build twine - name: Build and publish env: TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} run: | - python setup.py sdist bdist_wheel + python -m build --wheel --sdist twine upload dist/* diff --git a/mypy.ini b/mypy.ini deleted file mode 100644 index 3412486..0000000 --- a/mypy.ini +++ /dev/null @@ -1,3 +0,0 @@ -[mypy] -strict = True -warn_unused_ignores = False \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..8a2689b --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,76 @@ + +[build-system] +requires = ["setuptools >= 75.8.0"] +build-backend = "setuptools.build_meta" + +[project] +name="construct-typing" +dynamic = ["version"] +license = { file = "LICENSE" } +description="Extension for the python package 'construct' that adds typing features" +readme = "README.md" +authors=[{ name = "Tim Riddermann" }] +requires-python = ">=3.9" +dependencies = [ + "construct==2.10.70", + "typing_extensions>=4.6.0" +] +keywords = [ + "construct", + "kaitai", + "declarative", + "data structure", + "struct", + "binary", + "symmetric", + "parser", + "builder", + "parsing", + "building", + "pack", + "unpack", + "packer", + "unpacker", + "bitstring", + "bytestring", + "annotation", + "type hint", + "typing", + "typed", + "bitstruct", + "PEP 561", +] +classifiers = [ + "Development Status :: 3 - Alpha", + "License :: OSI Approved :: MIT License", + "Intended Audience :: Developers", + "Topic :: Software Development :: Libraries :: Python Modules", + "Topic :: Software Development :: Build Tools", + "Topic :: Software Development :: Code Generators", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: Implementation :: CPython", + "Typing :: Typed", +] + +[project.urls] +"Homepage" = "https://github.com/timrid/construct-typing" +"Bug Reports" = "https://github.com/timrid/construct-typing/issues" + +[tool.setuptools] +packages=[ + "construct-stubs", + "construct-stubs.lib", + "construct_typed" +] + +[tool.setuptools.dynamic] +version = {attr = "construct_typed.version.version_string"} + +[tool.mypy] +strict = true +warn_unused_ignores = false \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index a50644c..2514c06 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,3 +9,6 @@ black isort mypy cryptography +build +setuptools +wheel diff --git a/setup.py b/setup.py deleted file mode 100644 index 00a4b6d..0000000 --- a/setup.py +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env python -from setuptools import setup - -version_string = "?.?.?" -exec(open("./construct_typed/version.py").read()) - -setup( - name="construct-typing", - version=version_string, - packages=["construct-stubs", "construct_typed"], - package_data={ - "construct-stubs": ["*.pyi", "lib/*.pyi"], - "construct_typed": ["py.typed"], - }, - license="MIT", - license_files=("LICENSE",), - description="Extension for the python package 'construct' that adds typing features", - long_description=open("README.md").read(), - long_description_content_type="text/markdown", - platforms=["POSIX", "Windows"], - url="https://github.com/timrid/construct-typing", - author="Tim Riddermann", - python_requires=">=3.7", - install_requires=[ - "construct==2.10.70", - "typing_extensions>=4.6.0" - ], - keywords=[ - "construct", - "kaitai", - "declarative", - "data structure", - "struct", - "binary", - "symmetric", - "parser", - "builder", - "parsing", - "building", - "pack", - "unpack", - "packer", - "unpacker", - "bitstring", - "bytestring", - "annotation", - "type hint", - "typing", - "typed", - "bitstruct", - "PEP 561", - ], - classifiers=[ - "Development Status :: 3 - Alpha", - "License :: OSI Approved :: MIT License", - "Intended Audience :: Developers", - "Topic :: Software Development :: Libraries :: Python Modules", - "Topic :: Software Development :: Build Tools", - "Topic :: Software Development :: Code Generators", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - "Programming Language :: Python :: 3.13", - "Programming Language :: Python :: Implementation :: CPython", - "Typing :: Typed", - ], -) From 071038405cc1d14420513f1393a5c2a33693a0e2 Mon Sep 17 00:00:00 2001 From: timrid <6593626+timrid@users.noreply.github.com> Date: Mon, 27 Oct 2025 19:52:19 +0100 Subject: [PATCH 35/42] added trusted publishing infos --- .github/workflows/main.yml | 27 +++++++++++++++++++ .github/workflows/python-publish.yml | 39 ++++++++++++++-------------- 2 files changed, 47 insertions(+), 19 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index daadc0d..44dc00c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -62,3 +62,30 @@ jobs: - name: Run pyright run: | pyright + + create_wheel_and_sdist: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.13' + architecture: x64 + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install wheel build + + - name: Build wheel and sdist + run: | + python -m build + + - name: Upload wheel and sdist as artifact + uses: actions/upload-artifact@v4 + with: + name: Package-Distributions-construct-typing + path: dist/ \ No newline at end of file diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 05cfb95..6cdb1dd 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -1,6 +1,3 @@ -# This workflows will upload a Python Package using Twine when a release is created -# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries - name: Upload Python Package on: @@ -8,24 +5,28 @@ on: types: [created] jobs: - deploy: + create_wheel_and_sdist: + name: create_wheel_and_sdist + uses: ./.github/workflows/main.yml + with: + attest-package: "true" + deploy: + depends-on: create_wheel_and_sdist runs-on: ubuntu-latest + + environment: pypi + permissions: + id-token: write. # IMPORTANT: this permission is mandatory for Trusted Publishing steps: - - uses: actions/checkout@v2 - - name: Set up Python - uses: actions/setup-python@v2 + - uses: actions/checkout@v3 + + - name: Download artifacts + uses: actions/download-artifact@v4 with: - python-version: '3.x' - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install setuptools wheel build twine - - name: Build and publish - env: - TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} - TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} - run: | - python -m build --wheel --sdist - twine upload dist/* + name: Package-Distributions-construct-typing + path: ./dist + + - name: Publish package distributions to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 From fddd438ac8f6fcc724f1c06d2f007ee5a4a20c53 Mon Sep 17 00:00:00 2001 From: timrid <6593626+timrid@users.noreply.github.com> Date: Mon, 27 Oct 2025 20:05:12 +0100 Subject: [PATCH 36/42] fix publish workflow --- .github/workflows/main.yml | 6 +++++- .github/workflows/python-publish.yml | 6 ++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 44dc00c..e09f947 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,6 +1,10 @@ name: CI -on: [push, pull_request, workflow_dispatch] +on: + push: + pull_request: + workflow_dispatch: + workflow_call: jobs: build: diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 6cdb1dd..ea14263 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -8,16 +8,14 @@ jobs: create_wheel_and_sdist: name: create_wheel_and_sdist uses: ./.github/workflows/main.yml - with: - attest-package: "true" deploy: - depends-on: create_wheel_and_sdist + needs: [ create_wheel_and_sdist ] runs-on: ubuntu-latest environment: pypi permissions: - id-token: write. # IMPORTANT: this permission is mandatory for Trusted Publishing + id-token: write # IMPORTANT: this permission is mandatory for Trusted Publishing steps: - uses: actions/checkout@v3 From f3b7bc342ee6ecc1aee4d072972cdfd626666a81 Mon Sep 17 00:00:00 2001 From: timrid <6593626+timrid@users.noreply.github.com> Date: Mon, 27 Oct 2025 20:18:53 +0100 Subject: [PATCH 37/42] incremented version to 0.7.0 --- construct_typed/version.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/construct_typed/version.py b/construct_typed/version.py index b1bde74..04fbf4c 100644 --- a/construct_typed/version.py +++ b/construct_typed/version.py @@ -1,2 +1,2 @@ -version = (0, 6, 2) -version_string = "0.6.2" +version = (0, 7, 0) +version_string = "0.7.0" From 0c93e4d551079227d560dc71515998d8653711c0 Mon Sep 17 00:00:00 2001 From: wrapper Date: Tue, 7 Apr 2026 18:48:27 +0700 Subject: [PATCH 38/42] mod --- .gitignore | 3 ++ README.md | 8 ++++ construct-stubs/core.pyi | 27 +++++++++----- construct_typed/__init__.py | 12 +++++- construct_typed/dataclass_struct.py | 57 +++++++++++++++++++---------- construct_typed/generic_wrapper.py | 11 +++++- construct_typed/tenum.py | 45 +++++++++++------------ construct_typed/version.py | 2 +- 8 files changed, 110 insertions(+), 55 deletions(-) diff --git a/.gitignore b/.gitignore index b3d4398..1d9e0fe 100644 --- a/.gitignore +++ b/.gitignore @@ -129,3 +129,6 @@ dmypy.json example_737 example_888 example_ksy.ksy + +# Test stuff +devtest/ \ No newline at end of file diff --git a/README.md b/README.md index b11989c..d95463b 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,11 @@ +## Modified version of "construct-typing" module used in my projects. +This modification features: +- **[EnhancedDataclassMixin](https://github.com/waszil/construct-typing/commit/479b51344bfd95149596a75ee574ac2e63c032df)** +- **ConstantOrContextLambda2 type** +- **Typing for Subconstruct** +- **Type hint for Computed** + +The original README.md file was described down below: # construct-typing [![PyPI](https://img.shields.io/pypi/v/construct-typing)](https://pypi.org/project/construct-typing/) ![PyPI - Implementation](https://img.shields.io/pypi/implementation/construct-typing) diff --git a/construct-stubs/core.pyi b/construct-stubs/core.pyi index 456ab4a..59f482e 100644 --- a/construct-stubs/core.pyi +++ b/construct-stubs/core.pyi @@ -800,6 +800,8 @@ def If( ) -> IfThenElse[t.Optional[ThenParsedType], t.Optional[ThenBuildTypes]]: ... SwitchType = t.TypeVar("SwitchType") +SwitchParsedType = t.TypeVar("SwitchParsedType") +SwitchBuildTypes = t.TypeVar("SwitchBuildTypes") class Switch(Construct[ParsedType, BuildTypes]): keyfunc: ConstantOrContextLambda[t.Any] @@ -807,18 +809,25 @@ class Switch(Construct[ParsedType, BuildTypes]): default: Construct[t.Any, t.Any] @t.overload def __new__( - cls: "type[Switch[int, t.Optional[int]]]", + cls: "type[Switch[SwitchParsedType | None, SwitchBuildTypes | None]]", keyfunc: ConstantOrContextLambda[SwitchType], - cases: t.Dict[SwitchType, Construct[int, int]], - default: t.Optional[Construct[int, int]] = ..., - ) -> Switch[int, t.Optional[int]]: ... + cases: dict[t.Any, Construct[SwitchParsedType, SwitchBuildTypes]], + default: None = ..., + ) -> Switch[SwitchParsedType | None, SwitchBuildTypes | None]: ... @t.overload def __new__( - cls: "type[Switch[t.Any, t.Any]]", - keyfunc: ConstantOrContextLambda[t.Any], - cases: t.Dict[t.Any, Construct[t.Any, t.Any]], - default: t.Optional[Construct[t.Any, t.Any]] = ..., - ) -> Switch[t.Any, t.Any]: ... + cls: "type[Switch[SwitchParsedType, SwitchBuildTypes]]", + keyfunc: ConstantOrContextLambda[SwitchType], + cases: dict[t.Any, Construct[SwitchParsedType, SwitchBuildTypes]], + default: Construct[SwitchParsedType, SwitchBuildTypes], + ) -> Switch[SwitchParsedType, SwitchBuildTypes]: ... + # @t.overload + # def __new__( + # cls: "type[Switch[t.Any, t.Any]]", + # keyfunc: ConstantOrContextLambda[t.Any], + # cases: t.Dict[t.Any, Construct[t.Any, t.Any]], + # default: t.Optional[Construct[t.Any, t.Any]] = ..., + # ) -> Switch[t.Any, t.Any]: ... class StopIf(Construct[None, None]): condfunc: ConstantOrContextLambda[bool] diff --git a/construct_typed/__init__.py b/construct_typed/__init__.py index 9ea0ccf..f594f2b 100644 --- a/construct_typed/__init__.py +++ b/construct_typed/__init__.py @@ -9,15 +9,19 @@ from .dataclass_struct import ( TStructField, csfield, sfield, + EnhancedDataclassMixin ) from .generic_wrapper import ( Adapter, ConstantOrContextLambda, + ConstantOrContextLambda2, Construct, Context, ListContainer, PathType, - Array + Array, + Subconstruct, + Computed, ) from .tenum import EnumBase, EnumValue, FlagsEnumBase, TEnum, TFlagsEnum @@ -32,6 +36,7 @@ __all__ = [ "TStructField", "csfield", "sfield", + "EnhancedDataclassMixin", "EnumBase", "EnumValue", "FlagsEnumBase", @@ -39,9 +44,12 @@ __all__ = [ "TFlagsEnum", "Adapter", "ConstantOrContextLambda", + "ConstantOrContextLambda2", "Construct", "Context", "ListContainer", "PathType", - "Array" + "Array", + "Subconstruct", + "Computed" ] diff --git a/construct_typed/dataclass_struct.py b/construct_typed/dataclass_struct.py index e6ca2e8..e626085 100644 --- a/construct_typed/dataclass_struct.py +++ b/construct_typed/dataclass_struct.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- # pyright: strict +# pyright: reportIncompatibleVariableOverride=false, reportAny=false import dataclasses import textwrap import typing as t @@ -11,6 +12,7 @@ from construct.lib.containers import ( recursion_lock, ) from construct.lib.py3compat import bytestringtype, reprstring, unicodestringtype +from typing_extensions import override from .generic_wrapper import Adapter, Construct, Context, ParsedType, PathType @@ -27,7 +29,7 @@ class DataclassMixin: methods exists and every name can be used. """ - __dataclass_fields__: "t.ClassVar[t.Dict[str, dataclasses.Field[t.Any]]]" + __dataclass_fields__: "t.ClassVar[dict[str, dataclasses.Field[t.Any]]]" def __getitem__(self, key: str) -> t.Any: return getattr(self, key) @@ -77,8 +79,8 @@ class DataclassMixin: def csfield( subcon: Construct[ParsedType, t.Any], - doc: t.Optional[str] = None, - parsed: t.Optional[t.Callable[[t.Any, Context], None]] = None, + doc: str | None = None, + parsed: t.Callable[[t.Any, Context], None] | None = None, ) -> ParsedType: """ Helper method for "DataclassStruct" and "DataclassBitStruct" to create the dataclass fields. @@ -155,15 +157,11 @@ class DataclassStruct(Adapter[t.Any, t.Any, DataclassType, DataclassType]): subcon: "cs.Struct" # type: ignore def __init__( self, - dc_type: t.Type[DataclassType], + dc_type: type[DataclassType], reverse: bool = False, ) -> None: - if not issubclass(dc_type, DataclassMixin): # type: ignore - raise TypeError(f"'{repr(dc_type)}' has to be a '{repr(DataclassMixin)}'") - if not dataclasses.is_dataclass(dc_type): - raise TypeError(f"'{repr(dc_type)}' has to be a 'dataclasses.dataclass'") - self.dc_type = dc_type - self.reverse = reverse + self.dc_type: type[DataclassType] = dc_type + self.reverse: bool = reverse # get all fields from the dataclass fields = dataclasses.fields(self.dc_type) @@ -171,7 +169,7 @@ class DataclassStruct(Adapter[t.Any, t.Any, DataclassType, DataclassType]): fields = tuple(reversed(fields)) # extract the construct formats from the struct_type - subcon_fields = {} + subcon_fields: dict[str, t.Any] = {} for field in fields: subcon_fields[field.name] = field.metadata["subcon"] @@ -181,6 +179,7 @@ class DataclassStruct(Adapter[t.Any, t.Any, DataclassType, DataclassType]): def __getattr__(self, name: str) -> t.Any: return getattr(self.subcon, name) + @override def _decode( self, obj: "cs.Container[t.Any]", context: Context, path: PathType ) -> DataclassType: @@ -205,9 +204,10 @@ class DataclassStruct(Adapter[t.Any, t.Any, DataclassType, DataclassType]): return dc # type: ignore + @override def _encode( self, obj: DataclassType, context: Context, path: PathType - ) -> t.Dict[str, t.Any]: + ) -> dict[str, t.Any]: if not isinstance(obj, self.dc_type): raise TypeError(f"'{repr(obj)}' has to be of type {repr(self.dc_type)}") @@ -215,20 +215,16 @@ class DataclassStruct(Adapter[t.Any, t.Any, DataclassType, DataclassType]): fields = dataclasses.fields(self.dc_type) # extract all fields from the container, that are used for create the dataclass object - ret_dict: t.Dict[str, t.Any] = {} + ret_dict: dict[str, t.Any] = {} for field in fields: value = getattr(obj, field.name) ret_dict[field.name] = value return ret_dict - def DataclassBitStruct( - dc_type: t.Type[DataclassType], reverse: bool = False -) -> t.Union[ - "cs.Transformed[DataclassType, DataclassType]", - "cs.Restreamed[DataclassType, DataclassType]", -]: + dc_type: type[DataclassType], reverse: bool = False +) -> "cs.Transformed[DataclassType, DataclassType] | cs.Restreamed[DataclassType, DataclassType]": r""" Makes a DataclassStruct inside a Bitwise. @@ -255,6 +251,29 @@ def DataclassBitStruct( """ return cs.Bitwise(DataclassStruct(dc_type, reverse)) +class EnhancedDataclassMixin(DataclassMixin): + @classmethod + def format(cls): + return DataclassStruct(cls) + + @classmethod + def build(cls, obj: t.Self, **kw: dict[str, t.Any]): + return cls.format().build(obj, **kw) + + @classmethod + def parse(cls, data: bytes | bytearray, **kw: dict[str, t.Any]): + return cls.format().parse(data, **kw) + + @classmethod + def parse_file(cls, file: str, **kw: dict[str, t.Any]): + return cls.format().parse_file(file, **kw) + + @classmethod + def parse_stream(cls, stream: t.IO[bytes], **kw: dict[str, t.Any]): + return cls.format().parse_stream(stream, **kw) + + def build_self(self) -> bytes: + return self.build(self) # support legacy names TStruct = DataclassStruct diff --git a/construct_typed/generic_wrapper.py b/construct_typed/generic_wrapper.py index 742c267..cd4788b 100644 --- a/construct_typed/generic_wrapper.py +++ b/construct_typed/generic_wrapper.py @@ -12,12 +12,14 @@ if t.TYPE_CHECKING: # while type checking, the original classes are already generics, because they are defined like this in the stubs. from construct import Adapter as Adapter from construct import ConstantOrContextLambda as ConstantOrContextLambda + from construct import ConstantOrContextLambda2 as ConstantOrContextLambda2 from construct import Construct as Construct from construct import Context as Context from construct import ListContainer as ListContainer from construct import PathType as PathType from construct import Array as Array - + from construct import Subconstruct as Subconstruct + from construct import Computed as Computed else: import construct as cs @@ -44,5 +46,12 @@ else: ): pass + class Subconstruct(t.Generic[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes], cs.Subconstruct): + pass + + class Computed(t.Generic[ParsedType], cs.Computed): + pass + ConstantOrContextLambda = t.Union[ValueType, t.Callable[[Context], t.Any]] + ConstantOrContextLambda2 = t.Union[ValueType, t.Callable[[Context], ValueType]] PathType = str diff --git a/construct_typed/tenum.py b/construct_typed/tenum.py index 4ae6c03..4417c6b 100644 --- a/construct_typed/tenum.py +++ b/construct_typed/tenum.py @@ -1,9 +1,10 @@ +# pyright: reportAny=false import enum import typing as t -from typing_extensions import Self +from typing_extensions import Self, override -from .generic_wrapper import * +from .generic_wrapper import Construct, Adapter, Context, PathType # ## TEnum ############################################################################################################ @@ -12,8 +13,8 @@ class EnumValue: This is a helper class for adding documentation to an enum value. """ - def __init__(self, value: int, doc: t.Optional[str] = None) -> None: - self.value = value + def __init__(self, value: int, doc: str | None = None) -> None: + self.value: int = value self.__doc__ = doc if doc else "" @@ -47,7 +48,7 @@ class EnumBase(enum.IntEnum): 'This is the running state.' """ - def __new__(cls, val: t.Union[EnumValue, int]) -> "Self": + def __new__(cls, val: EnumValue | int) -> "Self": if isinstance(val, EnumValue): obj = int.__new__(cls, val.value) obj._value_ = val.value @@ -62,7 +63,8 @@ class EnumBase(enum.IntEnum): # not found in the enum, a new pseudo member is created. # The idea is taken from: https://stackoverflow.com/a/57179436 @classmethod - def _missing_(cls, value: t.Any) -> t.Optional[enum.Enum]: + @override + def _missing_(cls, value: t.Any) -> enum.Enum | None: if isinstance(value, int): pseudo_member = cls._value2member_map_.get(value, None) if pseudo_member is None: @@ -76,7 +78,8 @@ class EnumBase(enum.IntEnum): return pseudo_member return None # will raise the ValueError in Enum.__new__ - def __reduce_ex__(self, proto: t.Any) -> t.Tuple[t.Any, ...]: + @override + def __reduce_ex__(self, proto: t.Any) -> tuple[t.Any, ...]: """ Pickle enums by value instead of name (restores pre-3.11 behavior). See https://github.com/python/cpython/pull/26658 for why this exists. @@ -91,21 +94,18 @@ class TEnum(Adapter[int, int, EnumType, EnumType]): """ Typed enum. """ - def __init__(self, subcon: Construct[int, int], enum_type: t.Type[EnumType]): - if not issubclass(enum_type, EnumBase): - raise TypeError( - "'{}' has to be a '{}'".format(repr(enum_type), repr(EnumBase)) - ) - + def __init__(self, subcon: Construct[int, int], enum_type: type[EnumType]): # save enum type - self.enum_type = t.cast(t.Type[EnumType], enum_type) # type: ignore + self.enum_type: type[EnumType] = enum_type # init adatper super(TEnum, self).__init__(subcon) # type: ignore + @override def _decode(self, obj: int, context: Context, path: PathType) -> EnumType: return self.enum_type(obj) + @override def _encode( self, obj: EnumType, @@ -152,7 +152,7 @@ class FlagsEnumBase(enum.IntFlag): 'This is option two.' """ - def __new__(cls, val: t.Union[EnumValue, int]) -> "Self": + def __new__(cls, val: EnumValue | int) -> "Self": if isinstance(val, EnumValue): obj = int.__new__(cls, val.value) obj._value_ = val.value @@ -164,6 +164,7 @@ class FlagsEnumBase(enum.IntFlag): return obj @classmethod + @override def _missing_(cls, value: t.Any) -> t.Any: """ Returns member (possibly creating it) if one can be found for value. @@ -172,7 +173,8 @@ class FlagsEnumBase(enum.IntFlag): new_member.__doc__ = "missing value" return new_member - def __reduce_ex__(self, proto: t.Any) -> t.Tuple[t.Any, ...]: + @override + def __reduce_ex__(self, proto: t.Any) -> tuple[t.Any, ...]: """ Pickle enums by value instead of name (restores pre-3.11 behavior). See https://github.com/python/cpython/pull/26658 for why this exists. @@ -187,21 +189,18 @@ class TFlagsEnum(Adapter[int, int, FlagsEnumType, FlagsEnumType]): """ Typed enum. """ - def __init__(self, subcon: Construct[int, int], enum_type: t.Type[FlagsEnumType]): - if not issubclass(enum_type, FlagsEnumBase): - raise TypeError( - "'{}' has to be a '{}'".format(repr(enum_type), repr(FlagsEnumBase)) - ) - + def __init__(self, subcon: Construct[int, int], enum_type: type[FlagsEnumType]): # save enum type - self.enum_type = t.cast(t.Type[FlagsEnumType], enum_type) # type: ignore + self.enum_type: type[FlagsEnumType] = enum_type # init adatper super(TFlagsEnum, self).__init__(subcon) # type: ignore + @override def _decode(self, obj: int, context: Context, path: PathType) -> FlagsEnumType: return self.enum_type(obj) + @override def _encode( self, obj: FlagsEnumType, diff --git a/construct_typed/version.py b/construct_typed/version.py index 04fbf4c..38a2845 100644 --- a/construct_typed/version.py +++ b/construct_typed/version.py @@ -1,2 +1,2 @@ version = (0, 7, 0) -version_string = "0.7.0" +version_string = "0.7.0+wrapper" From 2f078b340bbb510d647ce69bec5b5ce13e181df8 Mon Sep 17 00:00:00 2001 From: wrapper Date: Tue, 7 Apr 2026 19:02:24 +0700 Subject: [PATCH 39/42] more switch fixes --- README.md | 1 + construct-stubs/core.pyi | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d95463b..73d2f1d 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ This modification features: - **ConstantOrContextLambda2 type** - **Typing for Subconstruct** - **Type hint for Computed** +- **Switch typing fixes** The original README.md file was described down below: # construct-typing diff --git a/construct-stubs/core.pyi b/construct-stubs/core.pyi index 59f482e..3792b96 100644 --- a/construct-stubs/core.pyi +++ b/construct-stubs/core.pyi @@ -802,6 +802,8 @@ def If( SwitchType = t.TypeVar("SwitchType") SwitchParsedType = t.TypeVar("SwitchParsedType") SwitchBuildTypes = t.TypeVar("SwitchBuildTypes") +SwitchDefaultParsedType = t.TypeVar("SwitchDefaultParsedType") +SwitchDefaultBuildTypes = t.TypeVar("SwitchDefaultBuildTypes") class Switch(Construct[ParsedType, BuildTypes]): keyfunc: ConstantOrContextLambda[t.Any] @@ -816,11 +818,11 @@ class Switch(Construct[ParsedType, BuildTypes]): ) -> Switch[SwitchParsedType | None, SwitchBuildTypes | None]: ... @t.overload def __new__( - cls: "type[Switch[SwitchParsedType, SwitchBuildTypes]]", + cls: "type[Switch[SwitchParsedType | SwitchDefaultParsedType, SwitchBuildTypes | SwitchDefaultBuildTypes]]", keyfunc: ConstantOrContextLambda[SwitchType], cases: dict[t.Any, Construct[SwitchParsedType, SwitchBuildTypes]], - default: Construct[SwitchParsedType, SwitchBuildTypes], - ) -> Switch[SwitchParsedType, SwitchBuildTypes]: ... + default: Construct[SwitchDefaultParsedType, SwitchDefaultBuildTypes], + ) -> Switch[SwitchParsedType | SwitchDefaultParsedType, SwitchBuildTypes | SwitchDefaultBuildTypes]: ... # @t.overload # def __new__( # cls: "type[Switch[t.Any, t.Any]]", From c1896ab8dcb96bab8900269a8b706ed0e94591b2 Mon Sep 17 00:00:00 2001 From: wrapper Date: Tue, 7 Apr 2026 19:25:45 +0700 Subject: [PATCH 40/42] Construct Error class does not return --- construct-stubs/core.pyi | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/construct-stubs/core.pyi b/construct-stubs/core.pyi index 3792b96..4bee6b5 100644 --- a/construct-stubs/core.pyi +++ b/construct-stubs/core.pyi @@ -622,7 +622,7 @@ class Check(Construct[None, None]): func: ConstantOrContextLambda[bool], ) -> None: ... -Error: Construct[None, None] +Error: Construct[t.NoReturn, t.NoReturn] class FocusedSeq(Construct[t.Any, t.Any]): subcons: t.List[Construct[t.Any, t.Any]] @@ -817,6 +817,13 @@ class Switch(Construct[ParsedType, BuildTypes]): default: None = ..., ) -> Switch[SwitchParsedType | None, SwitchBuildTypes | None]: ... @t.overload + def __new__( + cls: "type[Switch[SwitchParsedType, SwitchBuildTypes]]", + keyfunc: ConstantOrContextLambda[SwitchType], + cases: dict[t.Any, Construct[SwitchParsedType, SwitchBuildTypes]], + default: Construct[t.NoReturn, t.NoReturn], + ) -> Switch[SwitchParsedType, SwitchBuildTypes]: ... + @t.overload def __new__( cls: "type[Switch[SwitchParsedType | SwitchDefaultParsedType, SwitchBuildTypes | SwitchDefaultBuildTypes]]", keyfunc: ConstantOrContextLambda[SwitchType], From 0a4628935b6d279649114cfc1c632a90a785907a Mon Sep 17 00:00:00 2001 From: wrapper Date: Tue, 7 Apr 2026 20:19:38 +0700 Subject: [PATCH 41/42] add --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 73d2f1d..c4bac18 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ## Modified version of "construct-typing" module used in my projects. This modification features: -- **[EnhancedDataclassMixin](https://github.com/waszil/construct-typing/commit/479b51344bfd95149596a75ee574ac2e63c032df)** +- **[EnhancedDataclassMixin](https://github.com/waszil/construct-typing/commit/479b51344bfd95149596a75ee574ac2e63c032df) with additional features** - **ConstantOrContextLambda2 type** - **Typing for Subconstruct** - **Type hint for Computed** From 486c553d6576ee38200f4b32df387c00e9d05db7 Mon Sep 17 00:00:00 2001 From: wrapper Date: Tue, 7 Apr 2026 23:28:33 +0700 Subject: [PATCH 42/42] fallback switch --- construct-stubs/core.pyi | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/construct-stubs/core.pyi b/construct-stubs/core.pyi index 4bee6b5..7ed1af6 100644 --- a/construct-stubs/core.pyi +++ b/construct-stubs/core.pyi @@ -830,13 +830,13 @@ class Switch(Construct[ParsedType, BuildTypes]): cases: dict[t.Any, Construct[SwitchParsedType, SwitchBuildTypes]], default: Construct[SwitchDefaultParsedType, SwitchDefaultBuildTypes], ) -> Switch[SwitchParsedType | SwitchDefaultParsedType, SwitchBuildTypes | SwitchDefaultBuildTypes]: ... - # @t.overload - # def __new__( - # cls: "type[Switch[t.Any, t.Any]]", - # keyfunc: ConstantOrContextLambda[t.Any], - # cases: t.Dict[t.Any, Construct[t.Any, t.Any]], - # default: t.Optional[Construct[t.Any, t.Any]] = ..., - # ) -> Switch[t.Any, t.Any]: ... + @t.overload + def __new__( + cls: "type[Switch[t.Any, t.Any]]", + keyfunc: ConstantOrContextLambda[SwitchType], + cases: dict[t.Any, Construct[t.Any, t.Any]], + default: Construct[t.Any, t.Any] | None = ..., + ) -> Switch[t.Any, t.Any]: ... class StopIf(Construct[None, None]): condfunc: ConstantOrContextLambda[bool]