Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@
- Added `csfield_const` to create dataclass fields that are excluded from constructor and have a constant value.
- Added `csfield_default` to create dataclass fields that have a default value.
- Added `csfield_noinit` to create dataclass fields that are excluded from constructor.

**Changes:**
- Optimize type stubs for `Computed`, `Default` and `Rebuild` in conjunction with `ty`.
- Optimize type stubs for `Checksum`, to represent that it can build from `None`.
- Use PEP604 union syntax "X | Y" instead of "Union[X, Y]" and "X | None" instead of "Optional[X]" in type hints.

**Organizational changes:**
- Use `uv` as a project management tool and `poe` as a task runner.
234 changes: 96 additions & 138 deletions construct-stubs/core.pyi

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion construct-stubs/debug.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ ContextLambda = t.Callable[[Context], t.Any]

class Probe(Construct[None, None]):
def __init__(
self, into: t.Optional[ContextLambda] = ..., lookahead: int = ...
self, into: ContextLambda | None = ..., lookahead: int = ...
) -> None: ...

class Debugger(Subconstruct[None, None, None, None]): ...
18 changes: 9 additions & 9 deletions construct-stubs/expr.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ ReturnType = t.TypeVar("ReturnType")
LhsReturnType = t.TypeVar("LhsReturnType")
RhsReturnType = t.TypeVar("RhsReturnType")

ConstOrCallable = t.Union[ReturnType, t.Callable[[ReturnType], ReturnType]]
ConstOrCallable = ReturnType | t.Callable[[ReturnType], ReturnType]

class ExprMixin(t.Generic[ReturnType], object):
# __add__ ##########################################################################################################
Expand Down Expand Up @@ -767,24 +767,24 @@ class ExprMixin(t.Generic[ReturnType], object):
class UniExpr(ExprMixin[ReturnType]):
def __init__(self, op: UniOperator, operand: t.Any) -> None: ...
def __call__(
self, obj: t.Union[Context, dict[str, t.Any], t.Any], *args: t.Any
self, obj: Context | dict[str, t.Any] | t.Any, *args: t.Any
) -> ReturnType: ...

class BinExpr(ExprMixin[ReturnType]):
def __init__(self, op: BinOperator, lhs: t.Any, rhs: t.Any) -> None: ...
def __call__(
self, obj: t.Union[Context, dict[str, t.Any], t.Any], *args: t.Any
self, obj: Context | dict[str, t.Any] | t.Any, *args: t.Any
) -> ReturnType: ...

class Path(ExprMixin[ReturnType]):
def __init__(
self,
name: str,
field: t.Optional[str] = ...,
parent: t.Optional[Path[t.Any]] = ...,
field: str | None = ...,
parent: Path[t.Any] | None = ...,
) -> None: ...
def __call__(
self, obj: t.Union[Context, dict[str, t.Any], t.Any], *args: t.Any
self, obj: Context | dict[str, t.Any] | t.Any, *args: t.Any
) -> ReturnType: ...
def __getattr__(self, name: str) -> Path[t.Any]: ...
def __getitem__(self, name: str) -> Path[t.Any]: ...
Expand All @@ -793,15 +793,15 @@ class Path2(ExprMixin[ReturnType]):
def __init__(
self,
name: str,
index: t.Optional[int] = ...,
parent: t.Optional[Path2[t.Any]] = ...,
index: int | None = ...,
parent: Path2[t.Any] | None = ...,
) -> None: ...
def __call__(self, *args: t.Any) -> ReturnType: ...
def __getitem__(self, index: int) -> Path2[t.Any]: ...

class FuncPath(ExprMixin[ReturnType]):
def __init__(
self, func: t.Callable[[t.Any], ReturnType], operand: t.Optional[t.Any] = ...
self, func: t.Callable[[t.Any], ReturnType], operand: t.Any | None = ...
) -> None: ...
def __call__(self, operand: t.Any, *args: t.Any) -> ReturnType: ...

Expand Down
18 changes: 9 additions & 9 deletions construct-stubs/lib/bitstream.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import io
import typing as t

class RestreamedBytesIO(object):
substream: t.Optional[io.BytesIO]
substream: io.BytesIO | None
encoder: t.Callable[[bytes], bytes]
encoderunit: int
decoder: t.Callable[[bytes], bytes]
Expand All @@ -12,31 +12,31 @@ class RestreamedBytesIO(object):
sincereadwritten: int
def __init__(
self,
substream: t.Optional[io.BytesIO],
substream: io.BytesIO | None,
decoder: t.Callable[[bytes], bytes],
decoderunit: int,
encoder: t.Callable[[bytes], bytes],
encoderunit: int,
) -> None: ...
def read(self, count: t.Optional[int] = ...) -> bytes: ...
def write(self, data: t.Union[bytes, bytearray, memoryview]) -> int: ...
def read(self, count: int | None = ...) -> bytes: ...
def write(self, data: bytes | bytearray | memoryview) -> int: ...
def close(self) -> None: ...
def seek(self, at: int, whence: int = ...) -> int: ...
def seekable(self) -> bool: ...
def tell(self) -> int: ...
def tellable(self) -> bool: ...

class RebufferedBytesIO(object):
substream: t.Optional[io.BytesIO]
substream: io.BytesIO | None
offset: int
rwbuffer: bytes
moved: int
tailcutoff: t.Optional[int]
tailcutoff: int | None
def __init__(
self, substream: t.Optional[io.BytesIO], tailcutoff: t.Optional[int] = ...
self, substream: io.BytesIO | None, tailcutoff: int | None = ...
) -> None: ...
def read(self, count: t.Optional[int] = ...) -> bytes: ...
def write(self, data: t.Union[bytes, bytearray, memoryview]) -> int: ...
def read(self, count: int | None = ...) -> bytes: ...
def write(self, data: bytes | bytearray | memoryview) -> int: ...
def seek(self, at: int, whence: int = ...) -> int: ...
def seekable(self) -> bool: ...
def tell(self) -> int: ...
Expand Down
4 changes: 2 additions & 2 deletions construct-stubs/lib/containers.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import typing as t
ContainerType = t.TypeVar("ContainerType")
ListType = t.TypeVar("ListType")

SearchPattern = t.Union[t.AnyStr, re.Pattern[t.AnyStr]]
SearchPattern = t.AnyStr | re.Pattern[t.AnyStr]

globalPrintFullStrings: bool
globalPrintFalseFlags: bool
Expand All @@ -21,7 +21,7 @@ class Container(t.Generic[ContainerType], t.Dict[str, ContainerType]):
def __getattr__(self, name: str) -> ContainerType: ...
def update( # type: ignore
self,
seqordict: t.Union[t.Dict[str, ContainerType], t.Tuple[str, ContainerType]],
seqordict: t.Dict[str, ContainerType] | t.Tuple[str, ContainerType],
) -> None: ...
def search(self, pattern: SearchPattern[t.Any]) -> t.Any: ...
def search_all(self, pattern: SearchPattern[t.Any]) -> t.Any: ...
Expand Down
4 changes: 2 additions & 2 deletions construct-stubs/lib/py3compat.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def int2byte(character: int) -> bytes: ...
def byte2int(character: bytes) -> int: ...
def str2bytes(string: str) -> bytes: ...
def bytes2str(string: bytes) -> str: ...
def reprstring(data: t.Union[bytes, str]) -> str: ...
def trimstring(data: t.Union[bytes, str]) -> str: ...
def reprstring(data: bytes | str) -> str: ...
def trimstring(data: bytes | str) -> str: ...
def integers2bytes(ints: t.Iterable[int]) -> bytes: ...
def bytes2integers(data: bytes) -> list[int]: ...
34 changes: 17 additions & 17 deletions construct_typed/dataclass_struct.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@
class DataclassFieldError(Exception):
"""Exception raised by csfield, csfield_noinit, csfield_const and csfield_default."""


def _rename_subcon(
subcon: Construct[T, 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,
) -> Construct[T, t.Any]:
"""Helper method to rename a subcon if doc or parsed are available."""
if (doc is not None) or (parsed is not None):
Expand All @@ -35,8 +36,8 @@ def _rename_subcon(

def csfield(
subcon: Construct[T, 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,
*,
kw_only: bool = False,
) -> T:
Expand Down Expand Up @@ -71,8 +72,8 @@ def csfield(

def csfield_noinit(
subcon: Construct[T, None],
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,
*,
# "init" should not be used by users. It is only for type checkers to see that this field is excluded from __init__.
init: t.Literal[False] = False,
Expand All @@ -92,7 +93,7 @@ def csfield_noinit(
raise DataclassFieldError(
"csfield_noinit() can only be used with constructs that have flagbuildnone=True (Const, Rebuild, Computed, Padding, Tell, Pass, Terminated)."
)

subcon = _rename_subcon(subcon, doc, parsed)

return t.cast(
Expand All @@ -108,8 +109,8 @@ def csfield_noinit(
def csfield_const(
subcon: Construct[T, t.Any],
const: T,
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,
*,
# "init" should not be used by users. It is only for type checkers to see that this field is excluded from __init__.
init: t.Literal[False] = False,
Expand All @@ -126,7 +127,9 @@ def csfield_const(
"``cs.Const``, ``cs.Default`` or ``cs.Computed``). Pass the plain, unwrapped subcon instead."
)
if callable(const):
raise DataclassFieldError("csfield_const() cannot be used with context lambdas.")
raise DataclassFieldError(
"csfield_const() cannot be used with context lambdas."
)
if isinstance(subcon, cs.Const):
raise DataclassFieldError(
"csfield_const() cannot be used with a subcon that is already a ``cs.Const``. Pass the plain, unwrapped subcon instead."
Expand All @@ -135,7 +138,7 @@ def csfield_const(
subcon = cs.Const(const, subcon)
subcon = _rename_subcon(subcon, doc, parsed)

return t.cast(
return t.cast(
T,
dataclasses.field(
default=const,
Expand All @@ -147,8 +150,8 @@ def csfield_const(

def csfield_default(
subcon: Construct[T, 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,
*,
default: T,
) -> T:
Expand Down Expand Up @@ -363,10 +366,7 @@ def _encode(

def DataclassBitStruct(
dc_type: t.Type[DataclassType], reverse: bool = False
) -> t.Union[
"cs.Transformed[DataclassType, DataclassType]",
"cs.Restreamed[DataclassType, DataclassType]",
]:
) -> "cs.Transformed[DataclassType, DataclassType] | cs.Restreamed[DataclassType, DataclassType]":
r"""
Makes a DataclassStruct inside a Bitwise.

Expand Down
2 changes: 1 addition & 1 deletion construct_typed/generic_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,5 @@ class Array(
):
pass

ConstantOrContextLambda = t.Union[ValueType, t.Callable[[Context], t.Any]]
ConstantOrContextLambda = ValueType | t.Callable[[Context], t.Any]
PathType = str
8 changes: 4 additions & 4 deletions construct_typed/tenum.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ 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:
def __init__(self, value: int, doc: str | None = None) -> None:
self.value = value
self.__doc__ = doc if doc else ""

Expand Down Expand Up @@ -47,7 +47,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
Expand All @@ -62,7 +62,7 @@ def __new__(cls, val: t.Union[EnumValue, int]) -> "Self":
# 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]:
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:
Expand Down Expand Up @@ -153,7 +153,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
Expand Down
4 changes: 3 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,9 @@ output-format = "concise" # "full" | "concise" | "grouped" | "json" | "junit" |
[tool.ruff.lint]
allowed-confusables = ["×", "–", "‘", "’"]
select = [
"I"
"I",
"UP007",
"UP045"
]
Comment thread
timrid marked this conversation as resolved.

[tool.poe.tasks.test]
Expand Down
Loading