Skip to content
Merged
3 changes: 1 addition & 2 deletions dissect/cstruct/cstruct.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@

if TYPE_CHECKING:
from collections.abc import Iterable

from typing_extensions import TypeAlias
from typing import TypeAlias


T = TypeVar("T", bound=BaseType)
Expand Down
4 changes: 3 additions & 1 deletion dissect/cstruct/expression.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
from __future__ import annotations

import string
from typing import TYPE_CHECKING, Callable, ClassVar
from typing import TYPE_CHECKING, ClassVar

from dissect.cstruct.exceptions import ExpressionParserError, ExpressionTokenizerError

if TYPE_CHECKING:
from collections.abc import Callable

from dissect.cstruct import cstruct


Expand Down
3 changes: 1 addition & 2 deletions dissect/cstruct/tools/stubgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,9 @@ def generate_file_stub(path: Path, base: Path) -> str:

header = [
"# Generated by cstruct-stubgen",
"from typing import BinaryIO, Literal, overload",
"from typing import BinaryIO, Literal, TypeAlias, overload",
"",
"import dissect.cstruct as __cs__",
"from typing_extensions import TypeAlias",
]
body = []

Expand Down
8 changes: 3 additions & 5 deletions dissect/cstruct/types/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

import functools
from io import BytesIO
from typing import TYPE_CHECKING, Any, BinaryIO, Callable, ClassVar, TypeVar
from typing import TYPE_CHECKING, Any, BinaryIO, ClassVar, TypeVar

from dissect.cstruct.exceptions import ArraySizeError
from dissect.cstruct.expression import Expression

if TYPE_CHECKING:
from collections.abc import Callable

from typing_extensions import Self

from dissect.cstruct.cstruct import cstruct
Expand Down Expand Up @@ -60,10 +62,6 @@ def __bool__(cls) -> bool:

def __len__(cls) -> int:
"""Return the byte size of the type."""
# Python 3.9 compat thing for bound type vars
if cls is BaseType:
return 0

if cls.size is None:
raise TypeError("Dynamic size")

Expand Down
6 changes: 3 additions & 3 deletions dissect/cstruct/types/structure.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@

import io
from collections import ChainMap
from collections.abc import MutableMapping
from collections.abc import Callable, MutableMapping
from contextlib import contextmanager
from enum import Enum
from functools import lru_cache
from itertools import chain
from operator import attrgetter
from textwrap import dedent
from types import FunctionType
from typing import TYPE_CHECKING, Any, BinaryIO, Callable
from typing import TYPE_CHECKING, Any, BinaryIO

from dissect.cstruct.bitbuffer import BitBuffer
from dissect.cstruct.types.base import (
Expand Down Expand Up @@ -467,7 +467,7 @@ def __call__(cls, *args, **kwargs) -> Self: # type: ignore

# User (partial) initialization, rebuild the union
# First user-provided field is the one used to rebuild the union
arg_fields = (field._name for _, field in zip(args, cls.__fields__))
arg_fields = (field._name for _, field in zip(args, cls.__fields__, strict=False))
kwarg_fields = (name for name in kwargs if name in cls.lookup)
if (first_field := next(chain(arg_fields, kwarg_fields), None)) is not None:
obj._rebuild(first_field)
Expand Down
34 changes: 26 additions & 8 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
[build-system]
requires = ["setuptools>=65.5.0", "setuptools_scm[toml]>=6.4.0"]
requires = ["setuptools>=77.0.0", "setuptools_scm[toml]>=6.4.0"]
build-backend = "setuptools.build_meta"

[project]
name = "dissect.cstruct"
description = "A Dissect module implementing a parser for C-like structures: structure parsing in Python made easy"
readme = "README.md"
requires-python = "~=3.9"
license.text = "Apache License 2.0"
requires-python = ">=3.10"
license = "Apache-2.0"
license-files = ["LICENSE", "COPYRIGHT"]
authors = [
{name = "Dissect Team", email = "dissect@fox-it.com"}
]
Expand All @@ -16,7 +17,6 @@ classifiers = [
"Environment :: Console",
"Intended Audience :: Developers",
"Intended Audience :: Information Technology",
"License :: OSI Approved",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Topic :: Internet :: Log Analysis",
Expand All @@ -37,12 +37,33 @@ dev = [
"typing_extensions"
]

[dependency-groups]
test = [
"pytest",
]
lint = [
"ruff==0.13.1",
"typing_extensions",
"vermin",
]
build = [
"build",
]
debug = [
"ipdb",
]
dev = [
{include-group = "test"},
{include-group = "lint"},
{include-group = "debug"},
]

[project.scripts]
cstruct-stubgen = "dissect.cstruct.tools.stubgen:main"

[tool.ruff]
line-length = 120
required-version = ">=0.12.0"
required-version = ">=0.13.1"

[tool.ruff.format]
docstring-code-format = true
Expand Down Expand Up @@ -91,9 +112,6 @@ ignore = ["E203", "B904", "UP024", "ANN002", "ANN003", "ANN204", "ANN401", "SIM1
known-first-party = ["dissect.cstruct"]
known-third-party = ["dissect"]

[tool.setuptools]
license-files = ["LICENSE", "COPYRIGHT"]

[tool.setuptools.packages.find]
include = ["dissect.*"]

Expand Down
2 changes: 1 addition & 1 deletion tests/test_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def test_load_init_kwargs_only() -> None:
"""

# kwargs only check
with pytest.raises(TypeError, match="takes from .* positional arguments but .* were given"):
with pytest.raises(TypeError, match=r"takes from .* positional arguments but .* were given"):
cs = cstruct(cdef, ">")

cs = cstruct(cdef, endian=">")
Expand Down
2 changes: 1 addition & 1 deletion tests/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ def test_conditional_parsing_error(cs: cstruct) -> None:
};
#endif
"""
with pytest.raises(ParserError, match="line 8: unexpected token .+ENDIF"):
with pytest.raises(ParserError, match=r"line 8: unexpected token .+ENDIF"):
cs.load(cdef)

cdef = """
Expand Down
3 changes: 1 addition & 2 deletions tests/test_tools_stubgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -376,10 +376,9 @@ def test_generate_file_stub(tmp_path: Path, monkeypatch: pytest.MonkeyPatch, cap

expected = """
# Generated by cstruct-stubgen
from typing import BinaryIO, Literal, overload
from typing import BinaryIO, Literal, TypeAlias, overload

import dissect.cstruct as __cs__
from typing_extensions import TypeAlias

class _c_structure(__cs__.cstruct):
class Test(__cs__.Structure):
Expand Down
20 changes: 8 additions & 12 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ envlist = lint, py3, pypy3
# requires if they are not available on the host system. This requires the
# locally installed tox to have a minimum version 3.3.0. This means the names
# of the configuration options are still according to the tox 3.x syntax.
minversion = 4.4.3
minversion = 4.27.0
# This version of virtualenv will install setuptools version 68.2.2 and pip
# 23.3.1. These versions fully support python projects defined only through a
# pyproject.toml file (PEP-517/PEP-518/PEP-621). This pip version also support
Expand All @@ -14,38 +14,34 @@ requires = virtualenv>=20.24.6
[testenv]
extras = dev
deps =
pytest
pytest-cov
coverage
dependency_groups = test
commands =
pytest --basetemp="{envtmpdir}" {posargs:--color=yes --cov=dissect --cov-report=term-missing -v tests}
coverage report
coverage xml

[testenv:build]
package = skip
deps =
build
dependency_groups = build
commands =
pyproject-build

[testenv:fix]
package = skip
deps =
ruff==0.12.4
dependency_groups = lint
commands =
ruff format dissect tests
ruff check --fix dissect tests
ruff format dissect tests

[testenv:lint]
package = skip
deps =
ruff==0.12.4
vermin
dependency_groups = lint
commands =
ruff format --check dissect tests
ruff check dissect tests
vermin -t=3.9- --no-tips --lint dissect tests
ruff format --check dissect tests
vermin -t=3.10- --no-tips --lint dissect tests

[testenv:docs-build]
allowlist_externals = make
Expand Down
Loading