From 0979257dd7f6eeb941d751d4d1a57910e4da8ba2 Mon Sep 17 00:00:00 2001 From: Parnassius Date: Fri, 7 Jan 2022 12:07:46 +0100 Subject: [PATCH 01/84] Use `os.PathLike` for file names --- construct-stubs/core.pyi | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/construct-stubs/core.pyi b/construct-stubs/core.pyi index 73a1f88..a5603ac 100644 --- a/construct-stubs/core.pyi +++ b/construct-stubs/core.pyi @@ -1,5 +1,6 @@ import enum import io +import os import sys import typing as t @@ -25,6 +26,7 @@ from construct.lib import ( # - Higher Kinded Types: https://sobolevn.me/2020/10/higher-kinded-types-in-python StreamType = t.BinaryIO +FilenameType = t.Union[str, bytes, os.PathLike[str], os.PathLike[bytes]] PathType = str ContextKWType = t.Any @@ -97,18 +99,24 @@ class Construct(t.Generic[ParsedType, BuildTypes]): def parse_stream( self, stream: StreamType, **contextkw: ContextKWType ) -> ParsedType: ... - def parse_file(self, filename: str, **contextkw: ContextKWType) -> ParsedType: ... + def parse_file( + self, filename: FilenameType, **contextkw: ContextKWType + ) -> ParsedType: ... def build(self, obj: BuildTypes, **contextkw: ContextKWType) -> bytes: ... def build_stream( self, obj: BuildTypes, stream: StreamType, **contextkw: ContextKWType ) -> bytes: ... def build_file( - self, obj: BuildTypes, filename: str, **contextkw: ContextKWType + self, obj: BuildTypes, filename: FilenameType, **contextkw: ContextKWType ) -> bytes: ... def sizeof(self, **contextkw: ContextKWType) -> int: ... - def compile(self, filename: str = ...) -> Construct[ParsedType, BuildTypes]: ... - def benchmark(self, sampledata: bytes, filename: str = ...) -> str: ... - def export_ksy(self, schemaname: str = ..., filename: str = ...) -> str: ... + def compile( + self, filename: FilenameType = ... + ) -> Construct[ParsedType, BuildTypes]: ... + def benchmark(self, sampledata: bytes, filename: FilenameType = ...) -> str: ... + def export_ksy( + self, schemaname: str = ..., filename: FilenameType = ... + ) -> str: ... def __rtruediv__( self, name: t.Optional[t.AnyStr] ) -> Renamed[ParsedType, BuildTypes]: ... From 930fd9928c70692f6688d8ea090d518aec4cc1cf Mon Sep 17 00:00:00 2001 From: Tim Rid <6593626+timrid@users.noreply.github.com> Date: Sun, 9 Jan 2022 12:30:57 +0100 Subject: [PATCH 02/84] added mypy.ini: no error on unused ignores. mypy and pyright are slightly different, so pyright needs some ignores that mypy does not nee. --- mypy.ini | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 mypy.ini diff --git a/mypy.ini b/mypy.ini new file mode 100644 index 0000000..3412486 --- /dev/null +++ b/mypy.ini @@ -0,0 +1,3 @@ +[mypy] +strict = True +warn_unused_ignores = False \ No newline at end of file From e91bd27589a3aafe573afb258e9f69a6f0dbb95c Mon Sep 17 00:00:00 2001 From: timrid <6593626+timrid@users.noreply.github.com> Date: Sun, 9 Jan 2022 12:51:34 +0100 Subject: [PATCH 03/84] use settings from mypy.ini and also test the `construct_typed` folder --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 805dcca..4a3e3db 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -55,7 +55,7 @@ jobs: # Run mypy - name: Run mypy run: | - mypy --strict tests/ + mypy tests construct_typed # Run pyright - name: Run pyright From 29d2608c37998168b7dc96d286b6f12ef5750c1d Mon Sep 17 00:00:00 2001 From: Tim Rid <6593626+timrid@users.noreply.github.com> Date: Sun, 13 Feb 2022 01:06:45 +0100 Subject: [PATCH 04/84] fixed BuildTypes of cs.Const --- construct-stubs/core.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/construct-stubs/core.pyi b/construct-stubs/core.pyi index a5603ac..010f471 100644 --- a/construct-stubs/core.pyi +++ b/construct-stubs/core.pyi @@ -526,7 +526,7 @@ class Const(Subconstruct[SubconParsedType, SubconBuildTypes, ParsedType, BuildTy def __new__( cls, value: bytes, - ) -> Const[None, None, bytes, Bytes[bytes, int]]: ... + ) -> Const[None, None, bytes, t.Optional[bytes]]: ... @t.overload def __new__( cls, From 5533a7923e3abed7c8b6f4f06b1e77bf39726ca8 Mon Sep 17 00:00:00 2001 From: Tim Rid <6593626+timrid@users.noreply.github.com> Date: Sun, 13 Feb 2022 01:10:20 +0100 Subject: [PATCH 05/84] fixed "potential security vulnerabilities" from github --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 0836710..2d70b89 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ construct==2.10.67 pytest>=6.2.0 -numpy==1.20.* +numpy==1.21.* arrow ruamel.yaml cloudpickle From 834d244eda588323f28f45f17bc1f276b058088b Mon Sep 17 00:00:00 2001 From: Tim Rid <6593626+timrid@users.noreply.github.com> Date: Sun, 13 Feb 2022 01:14:01 +0100 Subject: [PATCH 06/84] ignore mypy error "Call to untyped function "load" in typed context" --- tests/test_core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_core.py b/tests/test_core.py index 96b9b91..6f65772 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -634,7 +634,7 @@ def test_numpy() -> None: @pytest.mark.xfail(reason="docs stated that it throws StreamError, not true at all") def test_numpy_error() -> None: import numpy, io - numpy.load(io.BytesIO(b"")) + numpy.load(io.BytesIO(b"")) # type: ignore def test_namedtuple() -> None: import collections From 47fd2838f7e059951f253675297fa27de16f88b2 Mon Sep 17 00:00:00 2001 From: Tim Rid <6593626+timrid@users.noreply.github.com> Date: Sun, 23 Oct 2022 22:12:49 +0200 Subject: [PATCH 07/84] changed requirements for Python 3.11 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 2d70b89..2c2ee3f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ construct==2.10.67 pytest>=6.2.0 -numpy==1.21.* +numpy==1.23.* arrow ruamel.yaml cloudpickle From 19fd0bf7f354c414c03b066265c30006e8af4518 Mon Sep 17 00:00:00 2001 From: Tim Rid <6593626+timrid@users.noreply.github.com> Date: Sun, 23 Oct 2022 22:12:55 +0200 Subject: [PATCH 08/84] Fixed Error in Python 3.11: "_sunder_ names, such as '_create_pseudo_member_', are reserved for future Enum use" --- construct_typed/tenum.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/construct_typed/tenum.py b/construct_typed/tenum.py index 7c93e33..e66c11e 100644 --- a/construct_typed/tenum.py +++ b/construct_typed/tenum.py @@ -18,11 +18,11 @@ class EnumBase(enum.IntEnum): @classmethod def _missing_(cls, value: t.Any) -> t.Optional["EnumBase"]: if isinstance(value, int): - return cls._create_pseudo_member_(value) + return cls._create_pseudo_member(value) return None # will raise the ValueError in Enum.__new__ @classmethod - def _create_pseudo_member_(cls, value: int) -> "EnumBase": + def _create_pseudo_member(cls, value: int) -> "EnumBase": pseudo_member = cls._value2member_map_.get(value, None) # type: ignore if pseudo_member is None: new_member = int.__new__(cls, value) From 18597a05db90f70e9b4c5d31a6bb4e954dce713a Mon Sep 17 00:00:00 2001 From: Tim Rid <6593626+timrid@users.noreply.github.com> Date: Sun, 23 Oct 2022 22:19:07 +0200 Subject: [PATCH 09/84] changed requirements to use the latest numpy, because numpy 1.23.* is not supporting Python 3.7. --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 2c2ee3f..87d1d1b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ construct==2.10.67 pytest>=6.2.0 -numpy==1.23.* +numpy arrow ruamel.yaml cloudpickle From 94896208b985fda53cc0fc2d1c634e91423bf850 Mon Sep 17 00:00:00 2001 From: Tim Rid <6593626+timrid@users.noreply.github.com> Date: Sun, 23 Oct 2022 22:24:08 +0200 Subject: [PATCH 10/84] fixed mypy error: `error: Returning Any from function declared to return "int"` --- tests/test_core.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_core.py b/tests/test_core.py index 6f65772..759dbe8 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -1213,7 +1213,7 @@ def test_checksum() -> None: def test_checksum_nonbytes_issue_323() -> None: d = Struct( "vals" / Byte[2], - "checksum" / Checksum(Byte, lambda vals: sum(vals) & 0xFF, this.vals), + "checksum" / Checksum(Byte, lambda vals: int(sum(vals)) & 0xFF, this.vals), ) assert d.parse(b"\x00\x00\x00") == Container(vals=[0, 0], checksum=0) assert raises(d.parse, b"\x00\x00\x01") == ChecksumError @@ -1704,7 +1704,7 @@ def test_from_issue_324() -> None: )), "checksum" / Checksum( Byte, - lambda data: sum(data) & 0xFF, + lambda data: int(sum(data)) & 0xFF, this.vals.data ), ) From a03190d816121a7e92f58cbd7a98b65f9277e19e Mon Sep 17 00:00:00 2001 From: Tim Rid <6593626+timrid@users.noreply.github.com> Date: Sun, 23 Oct 2022 22:48:42 +0200 Subject: [PATCH 11/84] fixed some pyright/pylance issues --- construct-stubs/core.pyi | 19 ++++++++++++------- construct-stubs/expr.pyi | 2 +- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/construct-stubs/core.pyi b/construct-stubs/core.pyi index 010f471..324f010 100644 --- a/construct-stubs/core.pyi +++ b/construct-stubs/core.pyi @@ -482,8 +482,8 @@ class RepeatUntil( Subconstruct[ SubconParsedType, SubconBuildTypes, - ListContainer[SubconParsedType], - t.List[SubconBuildTypes], + ParsedType, + BuildTypes, ] ): predicate: t.Union[ @@ -491,8 +491,8 @@ class RepeatUntil( t.Callable[[SubconParsedType, ListContainer[SubconParsedType], Context], bool], ] discard: bool - def __init__( - self, + def __new__( + cls, predicate: t.Union[ bool, t.Callable[ @@ -501,7 +501,12 @@ class RepeatUntil( ], subcon: Construct[SubconParsedType, SubconBuildTypes], discard: bool = ..., - ) -> None: ... + ) -> RepeatUntil[ + SubconParsedType, + SubconBuildTypes, + ListContainer[SubconParsedType], + t.List[SubconBuildTypes], + ]: ... # =============================================================================== # specials @@ -994,7 +999,7 @@ class Restreamed( ) -> None: ... class ProcessXor( - Subconstruct[SubconParsedType, SubconBuildTypes, SubconParsedType, SubconParsedType] + Subconstruct[SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes] ): padfunc: ConstantOrContextLambda2[t.Union[int, bytes]] def __new__( @@ -1004,7 +1009,7 @@ class ProcessXor( ) -> ProcessXor[SubconParsedType, SubconBuildTypes]: ... class ProcessRotateLeft( - Subconstruct[SubconParsedType, SubconBuildTypes, SubconParsedType, SubconParsedType] + Subconstruct[SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes] ): amount: ConstantOrContextLambda2[int] group: ConstantOrContextLambda2[int] diff --git a/construct-stubs/expr.pyi b/construct-stubs/expr.pyi index 8450a44..56fae52 100644 --- a/construct-stubs/expr.pyi +++ b/construct-stubs/expr.pyi @@ -543,7 +543,7 @@ class Path2(ExprMixin[ReturnType]): class FuncPath(ExprMixin[ReturnType]): - def __init__(self, func: t.Callable[[t.Any], t.Any], operand: t.Optional[t.Any] = ...) -> None: ... + def __init__(self, func: t.Callable[[t.Any], ReturnType], operand: t.Optional[t.Any] = ...) -> None: ... def __call__(self, operand: t.Any, *args: t.Any) -> ReturnType: ... From aeff7c6b7cc02813ac43038933230ac2e6cada56 Mon Sep 17 00:00:00 2001 From: Tim Rid <6593626+timrid@users.noreply.github.com> Date: Sun, 23 Oct 2022 23:03:40 +0200 Subject: [PATCH 12/84] remove github actions deprecation warnings. --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4a3e3db..48d1816 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -16,7 +16,7 @@ jobs: steps: # Checks out a copy of your repository on the machine - name: Checkout code - uses: actions/checkout@v1 + uses: actions/checkout@v3 # Setup python - name: Setup python From 2b780ae7b969182f190fd6311cd024bc7914c044 Mon Sep 17 00:00:00 2001 From: Tim Rid <6593626+timrid@users.noreply.github.com> Date: Sun, 23 Oct 2022 23:49:58 +0200 Subject: [PATCH 13/84] changed `Adapter` `__new__` to `__init__` to fix #13. But this change on `Adapter` also reqires to change other `Adapter` subclasses. --- construct-stubs/core.pyi | 79 +++++++++++++++++++++++++++++++--------- 1 file changed, 61 insertions(+), 18 deletions(-) diff --git a/construct-stubs/core.pyi b/construct-stubs/core.pyi index 324f010..22fc43d 100644 --- a/construct-stubs/core.pyi +++ b/construct-stubs/core.pyi @@ -182,9 +182,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: ... def _decode( self, obj: SubconBuildTypes, context: Context, path: PathType ) -> ParsedType: ... @@ -391,6 +391,12 @@ class Enum(Adapter[int, int, ParsedType, BuildTypes]): *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, + subcon: Construct[int, int], + *merge: t.Union[t.Type[enum.IntEnum], t.Type[enum.IntFlag]], + **mapping: int + ) -> None: ... def __getattr__(self, name: str) -> EnumIntegerString: ... class BitwisableString(str): @@ -405,6 +411,12 @@ class FlagsEnum(Adapter[int, int, ParsedType, BuildTypes]): *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, + subcon: Construct[int, int], + *merge: t.Union[t.Type[enum.IntEnum], t.Type[enum.IntFlag]], + **flags: int + ) -> None: ... def __getattr__(self, name: str) -> BitwisableString: ... class Mapping(Adapter[SubconParsedType, SubconBuildTypes, t.Any, t.Any]): @@ -415,6 +427,11 @@ class Mapping(Adapter[SubconParsedType, SubconBuildTypes, t.Any, t.Any]): subcon: Construct[SubconParsedType, SubconBuildTypes], mapping: t.Dict[t.Any, t.Any], ) -> Mapping[t.Any, t.Any]: ... + def __init__( + self, + subcon: Construct[SubconParsedType, SubconBuildTypes], + mapping: t.Dict[t.Any, t.Any], + ) -> None: ... # =============================================================================== # structures and sequences @@ -492,7 +509,7 @@ class RepeatUntil( ] discard: bool def __new__( - cls, + cls, predicate: t.Union[ bool, t.Callable[ @@ -615,6 +632,12 @@ class NamedTuple( t.Tuple[t.Any, ...], t.Union[t.Tuple[t.Any, ...], t.List[t.Any], t.Dict[str, t.Any]], ]: ... + def __init__( + self, + tuplename: str, + tuplefields: str, + subcon: Construct[SubconParsedType, SubconBuildTypes], + ) -> None: ... if sys.version_info >= (3, 8): MSDOS = t.Literal["msdos"] @@ -1121,30 +1144,28 @@ class LazyBound(Construct[ParsedType, BuildTypes]): # adapters and validators # =============================================================================== class ExprAdapter(Adapter[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]): - def __new__( - cls, + def __init__( + self, subcon: Construct[SubconParsedType, SubconBuildTypes], decoder: t.Callable[[SubconParsedType, Context], ParsedType], encoder: t.Callable[[BuildTypes, Context], SubconBuildTypes], - ) -> ExprAdapter[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]: ... + ) -> None: ... class ExprSymmetricAdapter( ExprAdapter[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes] ): - def __new__( - cls, + def __init__( + self, subcon: Construct[SubconParsedType, SubconBuildTypes], encoder: t.Callable[[BuildTypes, Context], SubconBuildTypes], - ) -> ExprSymmetricAdapter[ - SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes - ]: ... + ) -> None: ... class ExprValidator(Validator[SubconParsedType, SubconBuildTypes]): - def __new__( - cls, + def __init__( + self, subcon: Construct[SubconParsedType, SubconBuildTypes], validator: t.Callable[[SubconParsedType, Context], bool], - ) -> ExprValidator[SubconParsedType, SubconBuildTypes]: ... + ) -> None: ... def OneOf( subcon: Construct[SubconParsedType, SubconBuildTypes], @@ -1186,12 +1207,34 @@ class Slicing( step: int = ..., empty: t.Optional[SubconParsedType] = ..., ) -> Slicing[ListContainer[SubconParsedType], t.List[SubconBuildTypes]]: ... + def __init__( + self, + 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] = ..., + ) -> None: ... class Indexing( Adapter[SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes] ): - def __new__( - cls, + def __init__( + self, subcon: t.Union[ Array[ SubconParsedType, @@ -1209,4 +1252,4 @@ class Indexing( count: int, index: int, empty: t.Optional[SubconParsedType] = ..., - ) -> Indexing[SubconParsedType, SubconBuildTypes]: ... + ) -> None: ... From e10938f30838a13f27cae3c0ff5865ee4606b847 Mon Sep 17 00:00:00 2001 From: Tim Rid <6593626+timrid@users.noreply.github.com> Date: Mon, 24 Oct 2022 00:07:57 +0200 Subject: [PATCH 14/84] Added type hint to self type, for mypy support. --- construct-stubs/core.pyi | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/construct-stubs/core.pyi b/construct-stubs/core.pyi index 22fc43d..7e6dfd1 100644 --- a/construct-stubs/core.pyi +++ b/construct-stubs/core.pyi @@ -25,6 +25,11 @@ 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.BinaryIO FilenameType = t.Union[str, bytes, os.PathLike[str], os.PathLike[bytes]] PathType = str @@ -392,7 +397,7 @@ class Enum(Adapter[int, int, ParsedType, BuildTypes]): **mapping: int ) -> Enum[t.Union[EnumInteger, EnumIntegerString], t.Union[int, str]]: ... def __init__( - self, + self: Enum[t.Union[EnumInteger, EnumIntegerString], t.Union[int, str]], subcon: Construct[int, int], *merge: t.Union[t.Type[enum.IntEnum], t.Type[enum.IntFlag]], **mapping: int @@ -412,7 +417,7 @@ class FlagsEnum(Adapter[int, int, ParsedType, BuildTypes]): **flags: int ) -> FlagsEnum[Container[bool], t.Union[int, str, t.Dict[str, bool]]]: ... def __init__( - self, + self: FlagsEnum[Container[bool], t.Union[int, str, t.Dict[str, bool]]], subcon: Construct[int, int], *merge: t.Union[t.Type[enum.IntEnum], t.Type[enum.IntFlag]], **flags: int @@ -428,7 +433,7 @@ class Mapping(Adapter[SubconParsedType, SubconBuildTypes, t.Any, t.Any]): mapping: t.Dict[t.Any, t.Any], ) -> Mapping[t.Any, t.Any]: ... def __init__( - self, + self: Mapping[t.Any, t.Any], subcon: Construct[SubconParsedType, SubconBuildTypes], mapping: t.Dict[t.Any, t.Any], ) -> None: ... @@ -633,7 +638,12 @@ class NamedTuple( t.Union[t.Tuple[t.Any, ...], t.List[t.Any], t.Dict[str, t.Any]], ]: ... def __init__( - self, + self: NamedTuple[ + SubconParsedType, + SubconBuildTypes, + t.Tuple[t.Any, ...], + t.Union[t.Tuple[t.Any, ...], t.List[t.Any], t.Dict[str, t.Any]], + ], tuplename: str, tuplefields: str, subcon: Construct[SubconParsedType, SubconBuildTypes], @@ -1208,7 +1218,7 @@ class Slicing( empty: t.Optional[SubconParsedType] = ..., ) -> Slicing[ListContainer[SubconParsedType], t.List[SubconBuildTypes]]: ... def __init__( - self, + self: Slicing[ListContainer[SubconParsedType], t.List[SubconBuildTypes]], subcon: t.Union[ Array[ SubconParsedType, From 92b3555c508d32eaaf81ebd40cab5d8385f78094 Mon Sep 17 00:00:00 2001 From: Tim Rid <6593626+timrid@users.noreply.github.com> Date: Tue, 25 Oct 2022 19:26:37 +0200 Subject: [PATCH 15/84] removed `_create_pseudo_member` completely and integrated it into `_missing_` --- construct_typed/tenum.py | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/construct_typed/tenum.py b/construct_typed/tenum.py index e66c11e..6855f3d 100644 --- a/construct_typed/tenum.py +++ b/construct_typed/tenum.py @@ -12,27 +12,23 @@ class EnumBase(enum.IntEnum): This class extends the standard `enum.IntEnum`, so that missing values are automatically generated. """ - # Extend the enum type with __missing__ method. So if a enum value + # Extend the enum type with _missing_ method. So if a enum value # 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["EnumBase"]: + def _missing_(cls, value: t.Any) -> t.Optional[enum.Enum]: if isinstance(value, int): - return cls._create_pseudo_member(value) + pseudo_member = cls._value2member_map_.get(value, None) + if pseudo_member is None: + new_member = int.__new__(cls, value) + # I expect a name attribute to hold a string, hence str(value) + # However, new_member._name_ = value works, too + new_member._name_ = str(value) + new_member._value_ = value + pseudo_member = cls._value2member_map_.setdefault(value, new_member) + return pseudo_member return None # will raise the ValueError in Enum.__new__ - @classmethod - def _create_pseudo_member(cls, value: int) -> "EnumBase": - pseudo_member = cls._value2member_map_.get(value, None) # type: ignore - if pseudo_member is None: - new_member = int.__new__(cls, value) - # I expect a name attribute to hold a string, hence str(value) - # However, new_member._name_ = value works, too - new_member._name_ = str(value) - new_member._value_ = value - pseudo_member = cls._value2member_map_.setdefault(value, new_member) # type: ignore - return pseudo_member # type: ignore - EnumType = t.TypeVar("EnumType", bound=EnumBase) From ce871936d9e885c84f2f507c723fc5a7e99c9096 Mon Sep 17 00:00:00 2001 From: Tim Rid <6593626+timrid@users.noreply.github.com> Date: Tue, 25 Oct 2022 20:49:07 +0200 Subject: [PATCH 16/84] Added Python 3.10 and 3.11 to the Test-Matrix and removed github warning "Node.js 12 actions are deprecated." --- .github/workflows/main.yml | 8 ++++---- setup.py | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 48d1816..3bdc963 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' ] + python-version: [ '3.7', '3.8', '3.9', '3.10', '3.11' ] runs-on: ${{ matrix.os }} name: OS ${{ matrix.os }}, Python ${{ matrix.python-version }} @@ -20,16 +20,16 @@ jobs: # Setup python - name: Setup python - uses: actions/setup-python@v1 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} architecture: x64 # Setup node.js (for pyright) - name: Setup node.js (for pyright) - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: - node-version: '14' + node-version: 16 # Install pyright - name: Install pyright diff --git a/setup.py b/setup.py index 6cdeb7a..ca87762 100644 --- a/setup.py +++ b/setup.py @@ -58,6 +58,8 @@ setup( "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", "Programming Language :: Python :: Implementation :: CPython", "Typing :: Typed", ], From 25883cb7c8eae9f8ddfd241b84504d859e59710e Mon Sep 17 00:00:00 2001 From: Tim Rid <6593626+timrid@users.noreply.github.com> Date: Mon, 31 Oct 2022 09:54:15 +0100 Subject: [PATCH 17/84] Updated settings.json --- .vscode/settings.json | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 76bdfe9..75b5040 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,24 +1,26 @@ { - "python.pythonPath": "python", + // static analysis "python.languageServer": "Pylance", - // "python.testing.unittestEnabled": false, - // "python.testing.nosetestsEnabled": false, - // "python.testing.pytestEnabled": true, - "pythonTestExplorer.testFramework": "pytest", - "python.formatting.provider": "black", - "python.sortImports.path": "isort", - "python.sortImports.args": [ - "--profile=black", - ], - // "[python]": { - // "editor.codeActionsOnSave": { - // "source.organizeImports": true - // } - // } "python.analysis.typeCheckingMode": "strict", "python.analysis.autoImportCompletions": false, "python.analysis.diagnosticSeverityOverrides": { "reportPrivateUsage": "information", "reportUntypedNamedTuple": "information", }, + + // formating + "python.formatting.provider": "black", + + // sorting + "python.sortImports.path": "isort", + "python.sortImports.args": [ + "--profile=black", + ], + + // tests + "python.testing.pytestArgs": [ + "tests" + ], + "python.testing.unittestEnabled": false, + "python.testing.pytestEnabled": true, } \ No newline at end of file From f3051a1116d0f3767ff27dc9e6a036e637c92fe2 Mon Sep 17 00:00:00 2001 From: Tim Rid <6593626+timrid@users.noreply.github.com> Date: Mon, 31 Oct 2022 09:54:50 +0100 Subject: [PATCH 18/84] upgrade requirement to construct==2.10.68 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index ca87762..54dd52d 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ setup( url="https://github.com/timrid/construct-typing", author="Tim Riddermann", python_requires=">=3.7", - install_requires=["construct==2.10.67"], + install_requires=["construct==2.10.68"], keywords=[ "construct", "kaitai", From ceb4b67ff8a1a3800b06c6468798c0c72b4f9edf Mon Sep 17 00:00:00 2001 From: Tim Rid <6593626+timrid@users.noreply.github.com> Date: Mon, 31 Oct 2022 10:06:15 +0100 Subject: [PATCH 19/84] incremented version to 0.5.3 --- 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 1a555cf..ce77de7 100644 --- a/construct_typed/version.py +++ b/construct_typed/version.py @@ -1,2 +1,2 @@ -version = (0, 5, 2) -version_string = "0.5.2" \ No newline at end of file +version = (0, 5, 3) +version_string = "0.5.3" \ No newline at end of file From 349c8e5dd214c4e1bbdf027a3bf995d7b483dde3 Mon Sep 17 00:00:00 2001 From: Tim Rid <6593626+timrid@users.noreply.github.com> Date: Fri, 23 Dec 2022 20:37:05 +0100 Subject: [PATCH 20/84] Updated IfThenElse so that it represents the real implementation --- construct-stubs/core.pyi | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/construct-stubs/core.pyi b/construct-stubs/core.pyi index 7e6dfd1..32b4b77 100644 --- a/construct-stubs/core.pyi +++ b/construct-stubs/core.pyi @@ -767,23 +767,23 @@ ThenBuildTypes = t.TypeVar("ThenBuildTypes") ElseParsedType = t.TypeVar("ElseParsedType") ElseBuildTypes = t.TypeVar("ElseBuildTypes") -# This does not represent the original code, but it is the only solution that works good with pyright -class _IfThenElse(Construct[ParsedType, BuildTypes]): +class IfThenElse(Construct[ParsedType, BuildTypes]): condfunc: ConstantOrContextLambda[bool] thensubcon: Construct[ParsedType, BuildTypes] elsesubcon: Construct[ParsedType, BuildTypes] + def __new__( + cls, + condfunc: ConstantOrContextLambda[bool], + thensubcon: Construct[ThenParsedType, ThenBuildTypes], + elsesubcon: Construct[ElseParsedType, ElseBuildTypes], + ) -> IfThenElse[ + t.Union[ThenParsedType, ElseParsedType], t.Union[ThenBuildTypes, ElseBuildTypes] + ]: ... -def IfThenElse( - condfunc: ConstantOrContextLambda[bool], - thensubcon: Construct[ThenParsedType, ThenBuildTypes], - elsesubcon: Construct[ElseParsedType, ElseBuildTypes], -) -> _IfThenElse[ - t.Union[ThenParsedType, ElseParsedType], t.Union[ThenBuildTypes, ElseBuildTypes] -]: ... def If( condfunc: ConstantOrContextLambda[bool], subcon: Construct[ThenParsedType, ThenBuildTypes], -) -> _IfThenElse[t.Union[ThenParsedType, None], t.Union[ThenBuildTypes, None]]: ... +) -> IfThenElse[t.Union[ThenParsedType, None], t.Union[ThenBuildTypes, None]]: ... SwitchType = t.TypeVar("SwitchType") From b7e92c3c7d7fa3c41cc5043c1c2cc915f0686b9a Mon Sep 17 00:00:00 2001 From: Tim Rid <6593626+timrid@users.noreply.github.com> Date: Fri, 23 Dec 2022 20:37:38 +0100 Subject: [PATCH 21/84] removed mypy error 'Unused "type: ignore" comment' --- tests/test_core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_core.py b/tests/test_core.py index 759dbe8..95e5e59 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- - +# mypy: no-warn-unused-ignores from .declarativeunittest import raises, common, commonhex, commondumpdeprecated, commondump, commonbytes, ident, devzero from construct.core import * from construct import * From 916349f876c23e191973eb17bbb969e478858ed7 Mon Sep 17 00:00:00 2001 From: Tim Rid <6593626+timrid@users.noreply.github.com> Date: Sat, 24 Dec 2022 12:00:23 +0100 Subject: [PATCH 22/84] enhanced `EnumBase` and `FlagsEnumBase` to support induvidual documentation for each enum value via `EnumValue` --- construct_typed/__init__.py | 3 +- construct_typed/tenum.py | 91 ++++++++++++++++++++++++++++++++++++- tests/test_typed.py | 72 +++++++++++++++++++++++++++++ 3 files changed, 163 insertions(+), 3 deletions(-) diff --git a/construct_typed/__init__.py b/construct_typed/__init__.py index 00d5093..e052ee5 100644 --- a/construct_typed/__init__.py +++ b/construct_typed/__init__.py @@ -18,7 +18,7 @@ from .generic_wrapper import ( ListContainer, PathType, ) -from .tenum import EnumBase, FlagsEnumBase, TEnum, TFlagsEnum +from .tenum import EnumBase, EnumValue, FlagsEnumBase, TEnum, TFlagsEnum __all__ = [ "DataclassBitStruct", @@ -32,6 +32,7 @@ __all__ = [ "csfield", "sfield", "EnumBase", + "EnumValue", "FlagsEnumBase", "TEnum", "TFlagsEnum", diff --git a/construct_typed/tenum.py b/construct_typed/tenum.py index 6855f3d..3ead0dd 100644 --- a/construct_typed/tenum.py +++ b/construct_typed/tenum.py @@ -5,13 +5,55 @@ from .generic_wrapper import * # ## TEnum ############################################################################################################ +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 + self.__doc__ = doc if doc else "" + + def __int__(self) -> int: + return self.value + + class EnumBase(enum.IntEnum): """ Base class for an Enum used in `construct_typed.TEnum`. - This class extends the standard `enum.IntEnum`, so that missing values are automatically generated. + This class extends the standard `enum.IntEnum` by. + - missing values are automatically generated + - possibility to add documentation for each enum value (see `EnumValue`) + + Example:: + + >>> class State(EnumBase): + ... Idle = 1 + ... Running = EnumValue(2, "This is the running state.") + + >>> State(1) + + + >>> State["Idle"] + + + >>> State.Idle + + + >>> State(3) # missing value + + + >>> State.Running.__doc__ # documentation + 'This is the running state.' """ + def __init__(self, val: t.Union[EnumValue, int]): + if isinstance(val, EnumValue): + self.__doc__ = val.__doc__ + else: + self.__doc__ = "" + # Extend the enum type with _missing_ method. So if a enum value # not found in the enum, a new pseudo member is created. # The idea is taken from: https://stackoverflow.com/a/57179436 @@ -25,6 +67,7 @@ class EnumBase(enum.IntEnum): # However, new_member._name_ = value works, too new_member._name_ = str(value) new_member._value_ = value + new_member.__doc__ = "missing value" pseudo_member = cls._value2member_map_.setdefault(value, new_member) return pseudo_member return None # will raise the ValueError in Enum.__new__ @@ -75,7 +118,51 @@ class TEnum(Adapter[int, int, EnumType, EnumType]): # ## TFlagsEnum ####################################################################################################### class FlagsEnumBase(enum.IntFlag): - pass + """ + Base class for an Enum used in `construct_typed.TFlagsEnum`. + + This class extends the standard `enum.IntFlag` by. + - possibility to add documentation for each enum value (see `EnumValue`) + + Example:: + + >>> class Option(FlagsEnumBase): + ... OptOne = 1 + ... OptTwo = EnumValue(2, "This is option two.") + + >>> Option(1) + + + >>> Option["OptOne"] + + + >>> Option.OptOne + + + >>> Option(3) + + + >>> Option(4) + + + >>> Option.OptTwo.__doc__ # documentation + 'This is option two.' + """ + + def __init__(self, val: t.Union[EnumValue, int]): + if isinstance(val, EnumValue): + self.__doc__ = val.__doc__ + else: + self.__doc__ = "" + + @classmethod + def _missing_(cls, value: t.Any) -> t.Any: + """ + Returns member (possibly creating it) if one can be found for value. + """ + new_member = super()._missing_(value) + new_member.__doc__ = "missing value" + return new_member FlagsEnumType = t.TypeVar("FlagsEnumType", bound=FlagsEnumBase) diff --git a/tests/test_typed.py b/tests/test_typed.py index d74e025..756b0f6 100644 --- a/tests/test_typed.py +++ b/tests/test_typed.py @@ -384,6 +384,42 @@ def test_tenum_no_enumbase() -> None: assert raises(lambda: cst.TEnum(cs.Byte, cls)) == TypeError +def test_tenum_docstring() -> None: + class TestEnum(cst.EnumBase): + """ + This is an test enum. + """ + + Value_WithDoc = cst.EnumValue(0, doc="an enum with a documentation") + Value_WithMultilineDoc = cst.EnumValue( + 1, + """ + An enum with a multiline documentation... + ...next line... + """, + ) + Value_NoDoc = cst.EnumValue(2) + Value_NoDoc2 = 3 + + assert ( + TestEnum.__doc__ + == """ + This is an test enum. + """ + ) + assert TestEnum.Value_WithDoc.__doc__ == "an enum with a documentation" + assert ( + TestEnum.Value_WithMultilineDoc.__doc__ + == """ + An enum with a multiline documentation... + ...next line... + """ + ) + assert TestEnum.Value_NoDoc.__doc__ == "" + assert TestEnum.Value_NoDoc2.__doc__ == "" + assert TestEnum(5).__doc__ == "missing value" + + def test_dataclass_struct_wrong_enumbase() -> None: class E1(cst.EnumBase): a = 1 @@ -434,3 +470,39 @@ def test_tenum_flags() -> None: assert d.build(TestEnum(255)) == b"\xff" assert d.build(TestEnum.eight) == b"\x08" assert raises(d.build, 2) == TypeError + + +def test_tenum_flags_docstring() -> None: + class TestEnum(cst.FlagsEnumBase): + """ + This is an test flags enum. + """ + + Value_WithDoc = cst.EnumValue(0, doc="an enum with a documentation") + Value_WithMultilineDoc = cst.EnumValue( + 1, + """ + An enum with a multiline documentation... + ...next line... + """, + ) + Value_NoDoc = cst.EnumValue(2) + Value_NoDoc2 = 4 + + assert ( + TestEnum.__doc__ + == """ + This is an test flags enum. + """ + ) + assert TestEnum.Value_WithDoc.__doc__ == "an enum with a documentation" + assert ( + TestEnum.Value_WithMultilineDoc.__doc__ + == """ + An enum with a multiline documentation... + ...next line... + """ + ) + assert TestEnum.Value_NoDoc.__doc__ == "" + assert TestEnum.Value_NoDoc2.__doc__ == "" + assert TestEnum(8).__doc__ == "missing value" From ed5d0fe826a229a31fc70ad9fa587accd1c91291 Mon Sep 17 00:00:00 2001 From: Tim Rid <6593626+timrid@users.noreply.github.com> Date: Sat, 24 Dec 2022 12:20:03 +0100 Subject: [PATCH 23/84] incremented version to 0.5.4 --- 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 ce77de7..e9cf6fc 100644 --- a/construct_typed/version.py +++ b/construct_typed/version.py @@ -1,2 +1,2 @@ -version = (0, 5, 3) -version_string = "0.5.3" \ No newline at end of file +version = (0, 5, 4) +version_string = "0.5.4" \ No newline at end of file From 31a10dcc88e2a757107edf9530120bb7e2864a71 Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Fri, 6 Jan 2023 10:32:19 +0100 Subject: [PATCH 24/84] added type hints for `Struct._subcons`, `Sequence._subcons`, `FocusedSeq._subcons`, `Union._subcons`, `LazyStruct._subcons`, `LazyStruct._subconsindexes` --- construct-stubs/core.pyi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/construct-stubs/core.pyi b/construct-stubs/core.pyi index 32b4b77..0ff8888 100644 --- a/construct-stubs/core.pyi +++ b/construct-stubs/core.pyi @@ -444,6 +444,7 @@ class Mapping(Adapter[SubconParsedType, SubconBuildTypes, t.Any, t.Any]): # this can maybe made better when variadic generics are available class Struct(Construct[ParsedType, BuildTypes]): 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]]]: ... @@ -452,6 +453,7 @@ class Struct(Construct[ParsedType, BuildTypes]): # this can maybe made better when variadic generics are available class Sequence(Construct[ParsedType, BuildTypes]): 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]]]: ... @@ -603,6 +605,7 @@ Error: Construct[None, None] class FocusedSeq(Construct[t.Any, t.Any]): subcons: t.List[Construct[t.Any, t.Any]] + _subcons: t.Dict[str, Construct[t.Any, t.Any]] def __init__( self, parsebuildfrom: ConstantOrContextLambda[str], @@ -743,6 +746,7 @@ class HexDump(Adapter[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes class Union(Construct[Container[t.Any], t.Dict[str, t.Any]]): parsefrom: t.Optional[ConstantOrContextLambda[t.Union[int, str]]] subcons: t.List[Construct[t.Any, t.Any]] + _subcons: t.Dict[str, Construct[t.Any, t.Any]] def __init__( self, parsefrom: t.Optional[ConstantOrContextLambda[t.Union[int, str]]], @@ -1117,6 +1121,8 @@ class LazyContainer(t.Generic[ContainerType], t.Dict[str, ContainerType]): 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, Construct[t.Any, t.Any]] 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]]]: ... From 747bfaebd132d025001f914a82012d7cdcee5099 Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Fri, 6 Jan 2023 10:32:44 +0100 Subject: [PATCH 25/84] added generic wrapper for cs.Array --- construct_typed/generic_wrapper.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/construct_typed/generic_wrapper.py b/construct_typed/generic_wrapper.py index aa4af4c..99d8026 100644 --- a/construct_typed/generic_wrapper.py +++ b/construct_typed/generic_wrapper.py @@ -37,5 +37,11 @@ else: class Context: pass + class Array( + t.Generic[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes], + cs.Array, + ): + pass + ConstantOrContextLambda = t.Union[ValueType, t.Callable[[Context], t.Any]] PathType = str From f98532a382fba26b1aa41b22da83ea52f6d06fba Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Fri, 6 Jan 2023 10:35:07 +0100 Subject: [PATCH 26/84] fixed _subconsindexes --- construct-stubs/core.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/construct-stubs/core.pyi b/construct-stubs/core.pyi index 0ff8888..bf280c0 100644 --- a/construct-stubs/core.pyi +++ b/construct-stubs/core.pyi @@ -1122,7 +1122,7 @@ class LazyContainer(t.Generic[ContainerType], t.Dict[str, ContainerType]): 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, 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]]]: ... From b5add648ed3aedbcd09330594b79c16315466a06 Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Fri, 6 Jan 2023 10:45:55 +0100 Subject: [PATCH 27/84] fixed pyright 1.1.287 error --- tests/test_core.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/tests/test_core.py b/tests/test_core.py index 95e5e59..a50b7c2 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -1033,13 +1033,14 @@ def test_prefixed() -> None: common(d5, b"\x0a"+bytes(10), u"\x00"*10, SizeofError) def test_prefixedarray() -> None: - common(PrefixedArray(Byte,Byte), b"\x02\x0a\x0b", [10,11], SizeofError) - assert PrefixedArray(Byte, Byte).parse(b"\x03\x01\x02\x03") == [1,2,3] - assert PrefixedArray(Byte, Byte).parse(b"\x00") == [] - assert PrefixedArray(Byte, Byte).build([1,2,3]) == b"\x03\x01\x02\x03" - assert raises(PrefixedArray(Byte, Byte).parse, b"") == StreamError - assert raises(PrefixedArray(Byte, Byte).parse, b"\x03\x01") == StreamError - assert raises(PrefixedArray(Byte, Byte).sizeof) == SizeofError + d = PrefixedArray(Byte, Byte) + common(d, b"\x02\x0a\x0b", [10,11], SizeofError) + assert d.parse(b"\x03\x01\x02\x03") == [1,2,3] + assert d.parse(b"\x00") == [] + assert d.build([1,2,3]) == b"\x03\x01\x02\x03" + assert raises(d.parse, b"") == StreamError + assert raises(d.parse, b"\x03\x01") == StreamError + assert raises(d.sizeof) == SizeofError def test_fixedsized() -> None: d1 = FixedSized(10, Byte) From 7f6577af470221c8a65bdf5a0e45006705f75de4 Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Fri, 6 Jan 2023 12:00:42 +0100 Subject: [PATCH 28/84] added `__init__` methods for all that currently only defined an `__new__` method --- construct-stubs/core.pyi | 378 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 353 insertions(+), 25 deletions(-) diff --git a/construct-stubs/core.pyi b/construct-stubs/core.pyi index bf280c0..d62f962 100644 --- a/construct-stubs/core.pyi +++ b/construct-stubs/core.pyi @@ -183,6 +183,19 @@ class Subconstruct( def __new__( cls, *args: t.Any, **kwargs: t.Any ) -> Subconstruct[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]: ... + @t.overload + def __init__( + self: Subconstruct[ + SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes + ], + subcon: Construct[SubconParsedType, SubconBuildTypes], + ) -> None: ... + @t.overload + def __init__( + self: Subconstruct[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes], + *args: t.Any, + **kwargs: t.Any, + ) -> None: ... class Adapter( Subconstruct[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes], @@ -224,8 +237,13 @@ class Tunnel( class Bytes(Construct[ParsedType, BuildTypes]): length: ConstantOrContextLambda[int] def __new__( - cls, length: ConstantOrContextLambda[int] + cls, + length: ConstantOrContextLambda[int], ) -> Bytes[bytes, t.Union[bytes, int]]: ... + def __init__( + self: Bytes[bytes, t.Union[bytes, int]], + length: ConstantOrContextLambda[int], + ) -> None: ... GreedyBytes: Construct[bytes, bytes] @@ -255,20 +273,63 @@ class FormatField(Construct[ParsedType, BuildTypes]): FORMAT_BOOL = t.Literal["?"] @t.overload def __new__( - cls, endianity: str, format: FORMAT_INT + cls, + endianity: str, + format: FORMAT_INT, ) -> FormatField[int, int]: ... @t.overload def __new__( - cls, endianity: str, format: FORMAT_FLOAT + cls, + endianity: str, + format: FORMAT_FLOAT, ) -> FormatField[float, float]: ... @t.overload def __new__( - cls, endianity: str, format: FORMAT_BOOL + cls, + endianity: str, + format: FORMAT_BOOL, ) -> FormatField[bool, bool]: ... @t.overload - def __new__(cls, endianity: str, format: str) -> FormatField[t.Any, t.Any]: ... + def __new__( + cls, + endianity: str, + format: str, + ) -> FormatField[t.Any, t.Any]: ... + @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 __new__(cls, endianity: str, format: str) -> FormatField[t.Any, t.Any]: ... + def __new__( + cls, + endianity: str, + format: str, + ) -> FormatField[t.Any, t.Any]: ... + def __init__( + self: FormatField[t.Any, t.Any], + endianity: str, + format: str, + ) -> None: ... class BytesInteger(Construct[ParsedType, BuildTypes]): length: ConstantOrContextLambda[int] @@ -280,6 +341,12 @@ class BytesInteger(Construct[ParsedType, BuildTypes]): signed: bool = ..., swapped: ConstantOrContextLambda[bool] = ..., ) -> BytesInteger[int, int]: ... + def __init__( + self: BytesInteger[int, int], + length: ConstantOrContextLambda[int], + signed: bool = ..., + swapped: ConstantOrContextLambda[bool] = ..., + ) -> None: ... class BitsInteger(Construct[ParsedType, BuildTypes]): length: ConstantOrContextLambda[int] @@ -291,6 +358,12 @@ class BitsInteger(Construct[ParsedType, BuildTypes]): signed: bool = ..., swapped: ConstantOrContextLambda[bool] = ..., ) -> BitsInteger[int, int]: ... + def __init__( + self: BitsInteger[int, int], + length: ConstantOrContextLambda[int], + signed: bool = ..., + swapped: ConstantOrContextLambda[bool] = ..., + ) -> None: ... Bit: BitsInteger[int, int] Nibble: BitsInteger[int, int] @@ -363,8 +436,15 @@ class StringEncoded(Construct[ParsedType, BuildTypes]): ENCODING = str encoding: ENCODING def __new__( - cls, subcon: Construct[ParsedType, BuildTypes], encoding: ENCODING + cls, + subcon: Construct[ParsedType, BuildTypes], + encoding: ENCODING, ) -> StringEncoded[str, str]: ... + def __init__( + self: StringEncoded[str, str], + subcon: Construct[ParsedType, BuildTypes], + encoding: ENCODING, + ) -> None: ... def PaddedString( length: ConstantOrContextLambda[int], encoding: StringEncoded.ENCODING @@ -394,13 +474,13 @@ class Enum(Adapter[int, int, ParsedType, BuildTypes]): cls, subcon: Construct[int, int], *merge: t.Union[t.Type[enum.IntEnum], t.Type[enum.IntFlag]], - **mapping: int + **mapping: int, ) -> Enum[t.Union[EnumInteger, EnumIntegerString], t.Union[int, str]]: ... def __init__( self: Enum[t.Union[EnumInteger, EnumIntegerString], t.Union[int, str]], subcon: Construct[int, int], *merge: t.Union[t.Type[enum.IntEnum], t.Type[enum.IntFlag]], - **mapping: int + **mapping: int, ) -> None: ... def __getattr__(self, name: str) -> EnumIntegerString: ... @@ -414,13 +494,13 @@ class FlagsEnum(Adapter[int, int, ParsedType, BuildTypes]): cls, subcon: Construct[int, int], *merge: t.Union[t.Type[enum.IntEnum], t.Type[enum.IntFlag]], - **flags: int + **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]]], subcon: Construct[int, int], *merge: t.Union[t.Type[enum.IntEnum], t.Type[enum.IntFlag]], - **flags: int + **flags: int, ) -> None: ... def __getattr__(self, name: str) -> BitwisableString: ... @@ -446,8 +526,15 @@ class Struct(Construct[ParsedType, BuildTypes]): 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] + 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]]], + *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 @@ -455,8 +542,15 @@ class Sequence(Construct[ParsedType, BuildTypes]): 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] + 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]]], + *subcons: Construct[t.Any, t.Any], + **subconskw: Construct[t.Any, t.Any], + ) -> None: ... def __getattr__(self, name: str) -> t.Any: ... # =============================================================================== @@ -483,6 +577,17 @@ class Array( ListContainer[SubconParsedType], t.List[SubconBuildTypes], ]: ... + def __init__( + self: Array[ + SubconParsedType, + SubconBuildTypes, + ListContainer[SubconParsedType], + t.List[SubconBuildTypes], + ], + count: ConstantOrContextLambda[int], + subcon: Construct[SubconParsedType, SubconBuildTypes], + discard: bool = ..., + ) -> None: ... class GreedyRange( Subconstruct[ @@ -494,13 +599,25 @@ class GreedyRange( ): discard: bool def __new__( - cls, subcon: Construct[SubconParsedType, SubconBuildTypes], discard: bool = ... + cls, + subcon: Construct[SubconParsedType, SubconBuildTypes], + discard: bool = ..., ) -> GreedyRange[ SubconParsedType, SubconBuildTypes, ListContainer[SubconParsedType], t.List[SubconBuildTypes], ]: ... + def __init__( + self: GreedyRange[ + SubconParsedType, + SubconBuildTypes, + ListContainer[SubconParsedType], + t.List[SubconBuildTypes], + ], + subcon: Construct[SubconParsedType, SubconBuildTypes], + discard: bool = ..., + ) -> None: ... class RepeatUntil( Subconstruct[ @@ -531,6 +648,22 @@ class RepeatUntil( ListContainer[SubconParsedType], t.List[SubconBuildTypes], ]: ... + def __init__( + self: RepeatUntil[ + SubconParsedType, + SubconBuildTypes, + ListContainer[SubconParsedType], + t.List[SubconBuildTypes], + ], + predicate: t.Union[ + bool, + t.Callable[ + [SubconParsedType, ListContainer[SubconParsedType], Context], bool + ], + ], + subcon: Construct[SubconParsedType, SubconBuildTypes], + discard: bool = ..., + ) -> None: ... # =============================================================================== # specials @@ -567,12 +700,24 @@ class Computed(Construct[ParsedType, BuildTypes]): func: ConstantOrContextLambda2[ParsedType] @t.overload def __new__( - cls, func: ConstantOrContextLambda2[ParsedType] + cls, + func: ConstantOrContextLambda2[ParsedType], ) -> Computed[ParsedType, None]: ... @t.overload def __new__( - cls, func: ConstantOrContextLambda2[t.Any] + cls, + func: ConstantOrContextLambda2[t.Any], ) -> Computed[t.Any, None]: ... + @t.overload + def __init__( + self: Computed[ParsedType, None], + func: ConstantOrContextLambda2[ParsedType], + ) -> None: ... + @t.overload + def __init__( + self: Computed[t.Any, None], + func: ConstantOrContextLambda2[t.Any], + ) -> None: ... Index: Construct[int, t.Any] @@ -583,6 +728,11 @@ class Rebuild(Subconstruct[SubconParsedType, SubconBuildTypes, ParsedType, Build subcon: Construct[SubconParsedType, SubconBuildTypes], func: ConstantOrContextLambda[SubconBuildTypes], ) -> Rebuild[SubconParsedType, SubconBuildTypes, SubconParsedType, None]: ... + def __init__( + self: Rebuild[SubconParsedType, SubconBuildTypes, SubconParsedType, None], + subcon: Construct[SubconParsedType, SubconBuildTypes], + func: ConstantOrContextLambda[SubconBuildTypes], + ) -> None: ... class Default(Subconstruct[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]): value: ConstantOrContextLambda[SubconBuildTypes] @@ -596,10 +746,27 @@ class Default(Subconstruct[SubconParsedType, SubconBuildTypes, ParsedType, Build SubconParsedType, t.Optional[SubconBuildTypes], ]: ... + def __init__( + self: Default[ + SubconParsedType, + SubconBuildTypes, + SubconParsedType, + t.Optional[SubconBuildTypes], + ], + subcon: Construct[SubconParsedType, SubconBuildTypes], + value: ConstantOrContextLambda[SubconBuildTypes], + ) -> None: ... class Check(Construct[ParsedType, BuildTypes]): func: ConstantOrContextLambda[bool] - def __new__(cls, func: ConstantOrContextLambda[bool]) -> Check[None, None]: ... + def __new__( + cls, + func: ConstantOrContextLambda[bool], + ) -> Check[None, None]: ... + def __init__( + self: Check[None, None], + func: ConstantOrContextLambda[bool], + ) -> None: ... Error: Construct[None, None] @@ -610,7 +777,7 @@ class FocusedSeq(Construct[t.Any, t.Any]): self, parsebuildfrom: ConstantOrContextLambda[str], *subcons: Construct[t.Any, t.Any], - **subconskw: Construct[t.Any, t.Any] + **subconskw: Construct[t.Any, t.Any], ) -> None: ... def __getattr__(self, name: str) -> t.Any: ... @@ -711,6 +878,40 @@ class Hex(Adapter[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]): ) -> Hex[ SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes ]: ... + @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 HexDump(Adapter[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]): @t.overload @@ -738,6 +939,35 @@ class HexDump(Adapter[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes ) -> HexDump[ SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes ]: ... + @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: ... # =============================================================================== # conditional @@ -751,7 +981,7 @@ class Union(Construct[Container[t.Any], t.Dict[str, t.Any]]): self, parsefrom: t.Optional[ConstantOrContextLambda[t.Union[int, str]]], *subcons: Construct[t.Any, t.Any], - **subconskw: Construct[t.Any, t.Any] + **subconskw: Construct[t.Any, t.Any], ) -> None: ... def __getattr__(self, name: str) -> t.Any: ... @@ -759,8 +989,15 @@ class Union(Construct[Container[t.Any], t.Dict[str, t.Any]]): 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] + 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], + **subconskw: Construct[t.Any, t.Any], + ) -> None: ... def Optional( subcon: Construct[SubconParsedType, SubconBuildTypes] @@ -783,6 +1020,15 @@ class IfThenElse(Construct[ParsedType, BuildTypes]): ) -> IfThenElse[ t.Union[ThenParsedType, ElseParsedType], t.Union[ThenBuildTypes, ElseBuildTypes] ]: ... + def __init__( + self: IfThenElse[ + t.Union[ThenParsedType, ElseParsedType], + t.Union[ThenBuildTypes, ElseBuildTypes], + ], + condfunc: ConstantOrContextLambda[bool], + thensubcon: Construct[ThenParsedType, ThenBuildTypes], + elsesubcon: Construct[ElseParsedType, ElseBuildTypes], + ) -> None: ... def If( condfunc: ConstantOrContextLambda[bool], @@ -809,10 +1055,31 @@ class Switch(Construct[ParsedType, BuildTypes]): 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], + 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: ... class StopIf(Construct[ParsedType, BuildTypes]): condfunc: ConstantOrContextLambda[bool] - def __new__(cls, condfunc: ConstantOrContextLambda[bool]) -> StopIf[None, None]: ... + def __new__( + cls, + condfunc: ConstantOrContextLambda[bool], + ) -> StopIf[None, None]: ... + def __init__( + self: StopIf[None, None], + condfunc: ConstantOrContextLambda[bool], + ) -> None: ... # =============================================================================== # alignment and padding @@ -848,7 +1115,7 @@ class Aligned( def AlignedStruct( modulus: ConstantOrContextLambda[int], *subcons: Construct[t.Any, t.Any], - **subconskw: Construct[t.Any, t.Any] + **subconskw: Construct[t.Any, t.Any], ) -> Struct[Container[t.Any], t.Optional[t.Dict[str, t.Any]]]: ... def BitStruct( *subcons: Construct[t.Any, t.Any], **subconskw: Construct[t.Any, t.Any] @@ -882,6 +1149,15 @@ class Peek(Subconstruct[SubconParsedType, SubconBuildTypes, ParsedType, BuildTyp SubconParsedType, t.Union[SubconBuildTypes, None], ]: ... + def __init__( + self: Peek[ + SubconParsedType, + SubconBuildTypes, + SubconParsedType, + t.Union[SubconBuildTypes, None], + ], + subcon: Construct[SubconParsedType, SubconBuildTypes], + ) -> None: ... class Seek(Construct[int, None]): at: ConstantOrContextLambda[int] @@ -913,13 +1189,23 @@ class RawCopyObj(t.Generic[ParsedType], Container[t.Any]): class RawCopy(Subconstruct[SubconParsedType, SubconBuildTypes, ParsedType, BuildTypes]): def __new__( - cls, subcon: Construct[SubconParsedType, SubconBuildTypes] + cls, + subcon: Construct[SubconParsedType, SubconBuildTypes], ) -> RawCopy[ 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]]], + ], + subcon: Construct[SubconParsedType, SubconBuildTypes], + ) -> None: ... def ByteSwapped( subcon: Construct[SubconParsedType, SubconBuildTypes] @@ -1044,6 +1330,11 @@ class ProcessXor( padfunc: ConstantOrContextLambda2[t.Union[int, bytes]], subcon: Construct[SubconParsedType, SubconBuildTypes], ) -> ProcessXor[SubconParsedType, SubconBuildTypes]: ... + def __init__( + self: ProcessXor[SubconParsedType, SubconBuildTypes], + padfunc: ConstantOrContextLambda2[t.Union[int, bytes]], + subcon: Construct[SubconParsedType, SubconBuildTypes], + ) -> None: ... class ProcessRotateLeft( Subconstruct[SubconParsedType, SubconBuildTypes, SubconParsedType, SubconBuildTypes] @@ -1056,6 +1347,12 @@ class ProcessRotateLeft( group: ConstantOrContextLambda2[int], subcon: Construct[SubconParsedType, SubconBuildTypes], ) -> ProcessRotateLeft[SubconParsedType, SubconBuildTypes]: ... + def __init__( + self: ProcessRotateLeft[SubconParsedType, SubconBuildTypes], + amount: ConstantOrContextLambda2[int], + group: ConstantOrContextLambda2[int], + subcon: Construct[SubconParsedType, SubconBuildTypes], + ) -> None: ... T = t.TypeVar("T") @@ -1111,6 +1408,15 @@ class Lazy(Subconstruct[SubconParsedType, SubconBuildTypes, ParsedType, BuildTyp t.Callable[[], SubconParsedType], t.Union[t.Callable[[], SubconParsedType], SubconParsedType], ]: ... + def __init__( + self: Lazy[ + SubconParsedType, + SubconBuildTypes, + t.Callable[[], SubconParsedType], + t.Union[t.Callable[[], SubconParsedType], SubconParsedType], + ], + subcon: Construct[SubconParsedType, SubconBuildTypes], + ) -> None: ... class LazyContainer(t.Generic[ContainerType], t.Dict[str, ContainerType]): def __getattr__(self, name: str) -> ContainerType: ... @@ -1124,8 +1430,15 @@ class LazyStruct(Construct[ParsedType, BuildTypes]): _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] + 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], + **subconskw: Construct[t.Any, t.Any], + ) -> None: ... def __getattr__(self, name: str) -> t.Any: ... class LazyListContainer(t.List[ListType]): ... @@ -1149,12 +1462,27 @@ class LazyArray( ListContainer[SubconParsedType], t.List[SubconBuildTypes], ]: ... + def __init__( + self: LazyArray[ + SubconParsedType, + SubconBuildTypes, + ListContainer[SubconParsedType], + t.List[SubconBuildTypes], + ], + count: ConstantOrContextLambda[int], + subcon: Construct[SubconParsedType, SubconBuildTypes], + ) -> None: ... class LazyBound(Construct[ParsedType, BuildTypes]): subconfunc: t.Callable[[], Construct[ParsedType, BuildTypes]] def __new__( - cls, subconfunc: t.Callable[[], Construct[ParsedType, BuildTypes]] + cls, + subconfunc: t.Callable[[], Construct[ParsedType, BuildTypes]], ) -> LazyBound[ParsedType, BuildTypes]: ... + def __init__( + self: LazyBound[ParsedType, BuildTypes], + subconfunc: t.Callable[[], Construct[ParsedType, BuildTypes]], + ) -> None: ... # =============================================================================== # adapters and validators From 232fcbd725416d44ec486aa3b01a543402b57cdb Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Fri, 6 Jan 2023 12:00:56 +0100 Subject: [PATCH 29/84] inserted missing asserts --- 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 a50b7c2..4b1e4d0 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -224,8 +224,8 @@ def test_paddedstring() -> None: common(PaddedString(100, e), data, s, 100) for e in ["ascii","utf8","utf16","utf-16-le","utf32","utf-32-le"]: - PaddedString(10, e).sizeof() == 10 - PaddedString(this.n, e).sizeof(n=10) == 10 + assert PaddedString(10, e).sizeof() == 10 + assert PaddedString(this.n, e).sizeof(n=10) == 10 def test_pascalstring() -> None: for e,_ in [("utf8",1),("utf16",2),("utf_16_le",2),("utf32",4),("utf_32_le",4)]: @@ -236,8 +236,8 @@ def test_pascalstring() -> None: common(PascalString(sc, e), sc.build(0), u"") for e in ["utf8","utf16","utf-16-le","utf32","utf-32-le","ascii"]: - raises(PascalString(Byte, e).sizeof) == SizeofError - raises(PascalString(VarInt, e).sizeof) == SizeofError + assert raises(PascalString(Byte, e).sizeof) == SizeofError + assert raises(PascalString(VarInt, e).sizeof) == SizeofError def test_cstring() -> None: s = u"" @@ -246,12 +246,12 @@ def test_cstring() -> None: common(CString(e), s.encode(e)+bytes(us), s) common(CString(e), bytes(us), u"") - CString("utf8").build(s) == b'\xd0\x90\xd1\x84\xd0\xbe\xd0\xbd'+b"\x00" - CString("utf16").build(s) == b'\xff\xfe\x10\x04D\x04>\x04=\x04'+b"\x00\x00" - CString("utf32").build(s) == b'\xff\xfe\x00\x00\x10\x04\x00\x00D\x04\x00\x00>\x04\x00\x00=\x04\x00\x00'+b"\x00\x00\x00\x00" + assert CString("utf8").build(s) == b'\xd0\x90\xd1\x84\xd0\xbe\xd0\xbd'+b"\x00" + assert CString("utf16").build(s) == b'\xff\xfe\x10\x04D\x04>\x04=\x04'+b"\x00\x00" + assert CString("utf32").build(s) == b'\xff\xfe\x00\x00\x10\x04\x00\x00D\x04\x00\x00>\x04\x00\x00=\x04\x00\x00'+b"\x00\x00\x00\x00" for e in ["utf8","utf16","utf-16-le","utf32","utf-32-le","ascii"]: - raises(CString(e).sizeof) == SizeofError + assert raises(CString(e).sizeof) == SizeofError def test_greedystring() -> None: for e,_ in [("utf8",1),("utf16",2),("utf_16_le",2),("utf32",4),("utf_32_le",4)]: @@ -260,7 +260,7 @@ def test_greedystring() -> None: common(GreedyString(e), b"", u"") for e in ["utf8","utf16","utf-16-le","utf32","utf-32-le","ascii"]: - raises(GreedyString(e).sizeof) == SizeofError + assert raises(GreedyString(e).sizeof) == SizeofError def test_string_encodings() -> None: # checks that "-" is replaced with "_" @@ -271,7 +271,7 @@ def test_flag() -> None: d = Flag common(d, b"\x00", False, 1) common(d, b"\x01", True, 1) - d.parse(b"\xff") == True + assert d.parse(b"\xff") == True def test_enum() -> None: d = Enum(Byte, one=1, two=2, four=4, eight=8) @@ -591,7 +591,7 @@ def test_rebuild_issue_664() -> None: def test_default() -> None: d = Default(Byte, 0) common(d, b"\xff", 255, 1) - d.build(None) == b"\x00" + assert d.build(None) == b"\x00" def test_check() -> None: common(Check(True), b"", None, 0) From 238ca5d2dfeff18d471f10d82829aa8b9789c2be Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Fri, 6 Jan 2023 12:05:14 +0100 Subject: [PATCH 30/84] removed not working __init__ --- construct-stubs/core.pyi | 9 --------- 1 file changed, 9 deletions(-) diff --git a/construct-stubs/core.pyi b/construct-stubs/core.pyi index d62f962..83a7525 100644 --- a/construct-stubs/core.pyi +++ b/construct-stubs/core.pyi @@ -1020,15 +1020,6 @@ class IfThenElse(Construct[ParsedType, BuildTypes]): ) -> IfThenElse[ t.Union[ThenParsedType, ElseParsedType], t.Union[ThenBuildTypes, ElseBuildTypes] ]: ... - def __init__( - self: IfThenElse[ - t.Union[ThenParsedType, ElseParsedType], - t.Union[ThenBuildTypes, ElseBuildTypes], - ], - condfunc: ConstantOrContextLambda[bool], - thensubcon: Construct[ThenParsedType, ThenBuildTypes], - elsesubcon: Construct[ElseParsedType, ElseBuildTypes], - ) -> None: ... def If( condfunc: ConstantOrContextLambda[bool], From 80b11b2ef9f4b942699ec324435adcdf19d54630 Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Mon, 9 Jan 2023 08:18:16 +0100 Subject: [PATCH 31/84] added missing parts for cst.Array --- construct_typed/__init__.py | 2 ++ construct_typed/generic_wrapper.py | 1 + 2 files changed, 3 insertions(+) diff --git a/construct_typed/__init__.py b/construct_typed/__init__.py index e052ee5..9ea0ccf 100644 --- a/construct_typed/__init__.py +++ b/construct_typed/__init__.py @@ -17,6 +17,7 @@ from .generic_wrapper import ( Context, ListContainer, PathType, + Array ) from .tenum import EnumBase, EnumValue, FlagsEnumBase, TEnum, TFlagsEnum @@ -42,4 +43,5 @@ __all__ = [ "Context", "ListContainer", "PathType", + "Array" ] diff --git a/construct_typed/generic_wrapper.py b/construct_typed/generic_wrapper.py index 99d8026..f570f70 100644 --- a/construct_typed/generic_wrapper.py +++ b/construct_typed/generic_wrapper.py @@ -16,6 +16,7 @@ if t.TYPE_CHECKING: from construct import Context as Context from construct import ListContainer as ListContainer from construct import PathType as PathType + from construct import Array as Array else: From bea99456d7c2288c5b5cb2db32af79302fa0ce39 Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Mon, 9 Jan 2023 08:58:11 +0100 Subject: [PATCH 32/84] using __new__ instead of __init__ for `EnumBase` to create enum member objects (fixes #18) --- construct_typed/tenum.py | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/construct_typed/tenum.py b/construct_typed/tenum.py index 3ead0dd..3712957 100644 --- a/construct_typed/tenum.py +++ b/construct_typed/tenum.py @@ -14,9 +14,6 @@ class EnumValue: self.value = value self.__doc__ = doc if doc else "" - def __int__(self) -> int: - return self.value - class EnumBase(enum.IntEnum): """ @@ -48,11 +45,16 @@ class EnumBase(enum.IntEnum): 'This is the running state.' """ - def __init__(self, val: t.Union[EnumValue, int]): + def __new__(cls, val: t.Union[EnumValue, int]) -> "EnumBase": if isinstance(val, EnumValue): - self.__doc__ = val.__doc__ + obj = int.__new__(cls, val.value) + obj._value_ = val.value + obj.__doc__ = val.__doc__ else: - self.__doc__ = "" + obj = int.__new__(cls, val) + obj._value_ = val + obj.__doc__ = "" + return obj # Extend the enum type with _missing_ method. So if a enum value # not found in the enum, a new pseudo member is created. @@ -149,11 +151,16 @@ class FlagsEnumBase(enum.IntFlag): 'This is option two.' """ - def __init__(self, val: t.Union[EnumValue, int]): + def __new__(cls, val: t.Union[EnumValue, int]) -> "FlagsEnumBase": if isinstance(val, EnumValue): - self.__doc__ = val.__doc__ + obj = int.__new__(cls, val.value) + obj._value_ = val.value + obj.__doc__ = val.__doc__ else: - self.__doc__ = "" + obj = int.__new__(cls, val) + obj._value_ = val + obj.__doc__ = "" + return obj @classmethod def _missing_(cls, value: t.Any) -> t.Any: From acc3fa344396eeb986859e94a1e761eff67c9a1c Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Mon, 9 Jan 2023 13:23:37 +0100 Subject: [PATCH 33/84] incremented version to 0.5.5 --- 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 e9cf6fc..ee25123 100644 --- a/construct_typed/version.py +++ b/construct_typed/version.py @@ -1,2 +1,2 @@ -version = (0, 5, 4) -version_string = "0.5.4" \ No newline at end of file +version = (0, 5, 5) +version_string = "0.5.5" From ab33490dec3644f5d123994e56088b345f1bfd3b Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Tue, 9 May 2023 10:46:36 +0200 Subject: [PATCH 34/84] Pickle enums by value instead of name (restores pre-3.11 behavior) to support `dataclasses.asdict` --- construct_typed/tenum.py | 14 +++++++++++ tests/test_typed.py | 51 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/construct_typed/tenum.py b/construct_typed/tenum.py index 3712957..08e4a4b 100644 --- a/construct_typed/tenum.py +++ b/construct_typed/tenum.py @@ -74,6 +74,13 @@ class EnumBase(enum.IntEnum): return pseudo_member return None # will raise the ValueError in Enum.__new__ + def __reduce_ex__(self, proto: 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. + """ + return self.__class__, (self._value_,) + EnumType = t.TypeVar("EnumType", bound=EnumBase) @@ -171,6 +178,13 @@ class FlagsEnumBase(enum.IntFlag): new_member.__doc__ = "missing value" return new_member + def __reduce_ex__(self, proto: 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. + """ + return self.__class__, (self._value_,) + FlagsEnumType = t.TypeVar("FlagsEnumType", bound=FlagsEnumBase) diff --git a/tests/test_typed.py b/tests/test_typed.py index 756b0f6..4dd9528 100644 --- a/tests/test_typed.py +++ b/tests/test_typed.py @@ -384,6 +384,32 @@ def test_tenum_no_enumbase() -> None: assert raises(lambda: cst.TEnum(cs.Byte, cls)) == TypeError +def test_tenum_asdict(): + # see: https://github.com/timrid/construct-typing/issues/21 + import construct_typed as cst + import dataclasses + + class TestEnum(cst.EnumBase): + one = 1 + two = 2 + four = 4 + eight = 8 + + @dataclasses.dataclass + class SomeDataclass: + a: TestEnum + + dc = SomeDataclass(TestEnum.one) + dc_dict = dataclasses.asdict(dc) + assert dc_dict["a"] == dc.a + assert dc_dict["a"] is dc.a + + dc = SomeDataclass(TestEnum(5)) + dc_dict = dataclasses.asdict(dc) + assert dc_dict["a"] == dc.a + assert dc_dict["a"] is dc.a + + def test_tenum_docstring() -> None: class TestEnum(cst.EnumBase): """ @@ -472,6 +498,31 @@ def test_tenum_flags() -> None: assert raises(d.build, 2) == TypeError +def test_tenum_flags_asdict(): + import construct_typed as cst + import dataclasses + + class TestEnum(cst.FlagsEnumBase): + one = 1 + two = 2 + four = 4 + eight = 8 + + @dataclasses.dataclass + class SomeDataclass: + a: TestEnum + + dc = SomeDataclass(TestEnum.one) + dc_dict = dataclasses.asdict(dc) + assert dc_dict["a"] == dc.a + assert dc_dict["a"] is dc.a + + dc = SomeDataclass(TestEnum(5)) + dc_dict = dataclasses.asdict(dc) + assert dc_dict["a"] == dc.a + assert dc_dict["a"] is dc.a + + def test_tenum_flags_docstring() -> None: class TestEnum(cst.FlagsEnumBase): """ From 50a2f34fc68d3f81262814ba6d8980e5b056a0ec Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Tue, 9 May 2023 11:12:42 +0200 Subject: [PATCH 35/84] fixed mypy issue --- construct_typed/tenum.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/construct_typed/tenum.py b/construct_typed/tenum.py index 08e4a4b..a71fb7f 100644 --- a/construct_typed/tenum.py +++ b/construct_typed/tenum.py @@ -74,7 +74,7 @@ class EnumBase(enum.IntEnum): return pseudo_member return None # will raise the ValueError in Enum.__new__ - def __reduce_ex__(self, proto: t.Any): + def __reduce_ex__(self, proto: t.Any) -> t.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. @@ -178,7 +178,7 @@ class FlagsEnumBase(enum.IntFlag): new_member.__doc__ = "missing value" return new_member - def __reduce_ex__(self, proto: t.Any): + def __reduce_ex__(self, proto: t.Any) -> t.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. From 3a676478ee56349b6fa80e5ecef12752a6bd1fd4 Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Tue, 9 May 2023 11:27:19 +0200 Subject: [PATCH 36/84] fixed mypy issues --- construct_typed/dataclass_struct.py | 4 +++- tests/test_typed.py | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/construct_typed/dataclass_struct.py b/construct_typed/dataclass_struct.py index 78d2e59..d72ce5c 100644 --- a/construct_typed/dataclass_struct.py +++ b/construct_typed/dataclass_struct.py @@ -27,6 +27,8 @@ class DataclassMixin: methods exists and every name can be used. """ + __dataclass_fields__: t.ClassVar[dict[str, dataclasses.Field[t.Any]]] + def __getitem__(self, key: str) -> t.Any: return getattr(self, key) @@ -269,4 +271,4 @@ TBitStruct = DataclassBitStruct TContainerMixin = DataclassMixin TContainerBase = DataclassMixin TStructField = csfield -sfield = csfield \ No newline at end of file +sfield = csfield diff --git a/tests/test_typed.py b/tests/test_typed.py index 4dd9528..7d726a3 100644 --- a/tests/test_typed.py +++ b/tests/test_typed.py @@ -384,7 +384,7 @@ def test_tenum_no_enumbase() -> None: assert raises(lambda: cst.TEnum(cs.Byte, cls)) == TypeError -def test_tenum_asdict(): +def test_tenum_asdict() -> None: # see: https://github.com/timrid/construct-typing/issues/21 import construct_typed as cst import dataclasses @@ -498,7 +498,7 @@ def test_tenum_flags() -> None: assert raises(d.build, 2) == TypeError -def test_tenum_flags_asdict(): +def test_tenum_flags_asdict() -> None: import construct_typed as cst import dataclasses From d969fab1d3d6e3fa6e136beb70d25101d629f9e3 Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Tue, 9 May 2023 11:31:18 +0200 Subject: [PATCH 37/84] fixed python 3.7 "TypeError: 'type' object is not subscriptable" --- construct_typed/dataclass_struct.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/construct_typed/dataclass_struct.py b/construct_typed/dataclass_struct.py index d72ce5c..6e6c2d7 100644 --- a/construct_typed/dataclass_struct.py +++ b/construct_typed/dataclass_struct.py @@ -27,7 +27,7 @@ class DataclassMixin: methods exists and every name can be used. """ - __dataclass_fields__: t.ClassVar[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) From 6185a95e74da8ebe03171f2b5c9a13b7da4800b5 Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Tue, 9 May 2023 11:44:09 +0200 Subject: [PATCH 38/84] ignored typing error --- construct_typed/dataclass_struct.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/construct_typed/dataclass_struct.py b/construct_typed/dataclass_struct.py index 6e6c2d7..b7dbe14 100644 --- a/construct_typed/dataclass_struct.py +++ b/construct_typed/dataclass_struct.py @@ -212,7 +212,7 @@ class DataclassStruct(Adapter[t.Any, t.Any, DataclassType, DataclassType]): value = obj[field.name] setattr(dc, field.name, value) - return dc + return dc # type: ignore def _encode( self, obj: DataclassType, context: Context, path: PathType From a44ea8429984505f79318ac1d147c13ed300b2c1 Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Tue, 9 May 2023 11:47:10 +0200 Subject: [PATCH 39/84] fixed mypy error --- construct_typed/dataclass_struct.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/construct_typed/dataclass_struct.py b/construct_typed/dataclass_struct.py index b7dbe14..6ecae05 100644 --- a/construct_typed/dataclass_struct.py +++ b/construct_typed/dataclass_struct.py @@ -27,7 +27,7 @@ class DataclassMixin: methods exists and every name can be used. """ - __dataclass_fields__: "t.ClassVar[dict[str, dataclasses.Field[t.Any]]]" + __dataclass_fields__: "t.ClassVar[t.Dict[str, dataclasses.Field[t.Any]]]" def __getitem__(self, key: str) -> t.Any: return getattr(self, key) From bb3935e7ebb9426f54f4bd4a6f0a243dbb7184ff Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Tue, 9 May 2023 12:27:46 +0200 Subject: [PATCH 40/84] fixes #19 --- construct-stubs/core.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/construct-stubs/core.pyi b/construct-stubs/core.pyi index 83a7525..093199f 100644 --- a/construct-stubs/core.pyi +++ b/construct-stubs/core.pyi @@ -30,7 +30,7 @@ from construct.lib import ( # 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.BinaryIO +StreamType = t.IO[bytes] FilenameType = t.Union[str, bytes, os.PathLike[str], os.PathLike[bytes]] PathType = str ContextKWType = t.Any From 2200a0a8d0ee4f965b9462b6001bd1272de95670 Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Tue, 9 May 2023 12:31:38 +0200 Subject: [PATCH 41/84] fixed mypy errors --- 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 093199f..392c8fc 100644 --- a/construct-stubs/core.pyi +++ b/construct-stubs/core.pyi @@ -75,18 +75,18 @@ class CancelParsing(ConstructError): ... # used internally # =============================================================================== def stream_read( - stream: t.BinaryIO, length: int, path: t.Optional[PathType] + stream: StreamType, length: int, path: t.Optional[PathType] ) -> bytes: ... -def stream_read_entire(stream: t.BinaryIO, path: t.Optional[PathType]) -> bytes: ... +def stream_read_entire(stream: StreamType, path: t.Optional[PathType]) -> bytes: ... def stream_write( - stream: t.BinaryIO, data: bytes, length: int, path: t.Optional[PathType] + stream: StreamType, data: bytes, length: int, path: t.Optional[PathType] ) -> None: ... def stream_seek( - stream: t.BinaryIO, offset: int, whence: int, path: t.Optional[PathType] + stream: StreamType, offset: int, whence: int, path: t.Optional[PathType] ) -> int: ... -def stream_tell(stream: t.BinaryIO, path: t.Optional[PathType]) -> int: ... -def stream_size(stream: t.BinaryIO) -> int: ... -def stream_iseof(stream: t.BinaryIO) -> bool: ... +def stream_tell(stream: StreamType, path: t.Optional[PathType]) -> int: ... +def stream_size(stream: StreamType) -> int: ... +def stream_iseof(stream: StreamType) -> bool: ... def evaluate(param: ConstantOrContextLambda2[T], context: Context) -> T: ... # =============================================================================== From 3b51654b1e2a61a57b8e0639f89dc2908bad0509 Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Tue, 9 May 2023 13:03:26 +0200 Subject: [PATCH 42/84] incremented version to 0.5.6 --- 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 ee25123..740da2f 100644 --- a/construct_typed/version.py +++ b/construct_typed/version.py @@ -1,2 +1,2 @@ -version = (0, 5, 5) -version_string = "0.5.5" +version = (0, 5, 6) +version_string = "0.5.6" From 6550e59dd3d9ad51659c3ffcbffbc45e8d65b57f Mon Sep 17 00:00:00 2001 From: Tim Riddermann Date: Fri, 30 Jun 2023 13:06:29 +0200 Subject: [PATCH 43/84] 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 44/84] 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 45/84] 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 46/84] 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 47/84] 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 48/84] 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 49/84] 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 50/84] 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 51/84] 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 52/84] 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 53/84] 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 54/84] 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 55/84] 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 56/84] 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 57/84] 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 58/84] 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 59/84] 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 60/84] 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 61/84] 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 62/84] 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 63/84] 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 64/84] 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 65/84] 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 66/84] 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 67/84] 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 68/84] 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 69/84] 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 70/84] 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 71/84] 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 72/84] 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 73/84] 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 74/84] 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 75/84] 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 76/84] 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 77/84] 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 78/84] 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 79/84] 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 80/84] 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 81/84] 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 82/84] 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 83/84] 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 84/84] 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]