construct-classes 0.1.1__tar.gz → 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- construct_classes-0.2.0/CHANGELOG.rst +50 -0
- construct_classes-0.2.0/LICENSE +7 -0
- {construct-classes-0.1.1 → construct_classes-0.2.0}/PKG-INFO +31 -6
- {construct-classes-0.1.1 → construct_classes-0.2.0}/README.rst +23 -2
- {construct-classes-0.1.1 → construct_classes-0.2.0}/pyproject.toml +11 -2
- {construct-classes-0.1.1 → construct_classes-0.2.0}/src/construct_classes/__init__.py +32 -11
- construct-classes-0.1.1/setup.py +0 -34
- {construct-classes-0.1.1 → construct_classes-0.2.0}/src/construct_classes/py.typed +0 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
Changelog
|
|
2
|
+
=========
|
|
3
|
+
|
|
4
|
+
All notable changes to this project will be documented in this file.
|
|
5
|
+
|
|
6
|
+
The format is based on `Keep a Changelog`_, and this project adheres to
|
|
7
|
+
`Semantic Versioning`_.
|
|
8
|
+
|
|
9
|
+
Unreleased
|
|
10
|
+
------------
|
|
11
|
+
|
|
12
|
+
Please see all `Unreleased Changes`_ for more information.
|
|
13
|
+
|
|
14
|
+
.. _Unreleased Changes: https://github.com/matejcik/construct-classes/compare/v0.2.0...HEAD
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
0.2.0 - 2025-08-25
|
|
18
|
+
--------------------
|
|
19
|
+
|
|
20
|
+
Added
|
|
21
|
+
~~~~~
|
|
22
|
+
|
|
23
|
+
- Allow pass-through of dataclass arguments via class attributes.
|
|
24
|
+
|
|
25
|
+
Incompatible changes
|
|
26
|
+
~~~~~~~~~~~~~~~~~~~~
|
|
27
|
+
|
|
28
|
+
- Subclasses of :code:`Struct` are now :code:`kw_only` by default. This will break
|
|
29
|
+
any constructor invocations using positional arguments. You can explicitly
|
|
30
|
+
set :code:`kw_only=False` on your :code:`Struct` subclass to restore the old
|
|
31
|
+
behavior.
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
0.1.2 - 2022-10-07
|
|
35
|
+
--------------------
|
|
36
|
+
|
|
37
|
+
Fixed
|
|
38
|
+
~~~~~
|
|
39
|
+
|
|
40
|
+
- Support for dataclasses that do not contain all the attributes described
|
|
41
|
+
in :code:`SUBCON`.
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
0.1.1 - 2022-10-05
|
|
45
|
+
------------------
|
|
46
|
+
|
|
47
|
+
Initial version.
|
|
48
|
+
|
|
49
|
+
.. _Keep a Changelog: https://keepachangelog.com/en/1.0.0/
|
|
50
|
+
.. _Semantic Versioning: https://semver.org/spec/v2.0.0.html
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copyright 2022 matejcik <ja@matejcik.cz>
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: construct-classes
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Parse your binary structs into dataclasses
|
|
5
5
|
Home-page: https://github.com/matejcik/construct-classes
|
|
6
6
|
License: MIT
|
|
@@ -12,13 +12,17 @@ Classifier: Intended Audience :: Developers
|
|
|
12
12
|
Classifier: License :: OSI Approved :: MIT License
|
|
13
13
|
Classifier: Natural Language :: English
|
|
14
14
|
Classifier: Programming Language :: Python :: 3
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.6
|
|
18
15
|
Classifier: Programming Language :: Python :: 3.7
|
|
19
16
|
Classifier: Programming Language :: Python :: 3.8
|
|
20
17
|
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.6
|
|
21
24
|
Requires-Dist: construct (>=2.10,<3.0)
|
|
25
|
+
Requires-Dist: dataclasses (>=0.8,<0.9) ; python_full_version >= "3.6.0" and python_full_version < "3.7.0"
|
|
22
26
|
Project-URL: Repository, https://github.com/matejcik/construct-classes
|
|
23
27
|
Description-Content-Type: text/x-rst
|
|
24
28
|
|
|
@@ -107,8 +111,21 @@ must match the names of the fields in the Construct struct.
|
|
|
107
111
|
|
|
108
112
|
Use :code:`dataclasses.field()` to specify attributes on fields that are not subcons.
|
|
109
113
|
|
|
110
|
-
|
|
111
|
-
|
|
114
|
+
By default, subclasses of :code:`Struct` are :code:`kw_only`. This is specifically to
|
|
115
|
+
allow setting default values on any fields regardless of order, so that your attributes
|
|
116
|
+
can be listed in the subcon order.
|
|
117
|
+
|
|
118
|
+
However, you can pass any valid dataclass parameters to the :code:`Struct` class via
|
|
119
|
+
class attributes:
|
|
120
|
+
|
|
121
|
+
.. code-block:: python
|
|
122
|
+
|
|
123
|
+
class MyStruct(Struct, kw_only=False, frozen=True):
|
|
124
|
+
a: int
|
|
125
|
+
b: int
|
|
126
|
+
|
|
127
|
+
my_struct = MyStruct(1, 2) # ok
|
|
128
|
+
my_struct.a = 2 # FrozenInstanceError
|
|
112
129
|
|
|
113
130
|
|
|
114
131
|
Installing
|
|
@@ -119,6 +136,14 @@ Install using pip:
|
|
|
119
136
|
$ pip install construct-classes
|
|
120
137
|
|
|
121
138
|
|
|
139
|
+
Changelog
|
|
140
|
+
~~~~~~~~~
|
|
141
|
+
|
|
142
|
+
See `CHANGELOG.rst`_.
|
|
143
|
+
|
|
144
|
+
.. _CHANGELOG.rst: https://github.com/matejcik/construct-classes/blob/master/CHANGELOG.rst
|
|
145
|
+
|
|
146
|
+
|
|
122
147
|
Footer
|
|
123
148
|
------
|
|
124
149
|
|
|
@@ -83,8 +83,21 @@ must match the names of the fields in the Construct struct.
|
|
|
83
83
|
|
|
84
84
|
Use :code:`dataclasses.field()` to specify attributes on fields that are not subcons.
|
|
85
85
|
|
|
86
|
-
|
|
87
|
-
|
|
86
|
+
By default, subclasses of :code:`Struct` are :code:`kw_only`. This is specifically to
|
|
87
|
+
allow setting default values on any fields regardless of order, so that your attributes
|
|
88
|
+
can be listed in the subcon order.
|
|
89
|
+
|
|
90
|
+
However, you can pass any valid dataclass parameters to the :code:`Struct` class via
|
|
91
|
+
class attributes:
|
|
92
|
+
|
|
93
|
+
.. code-block:: python
|
|
94
|
+
|
|
95
|
+
class MyStruct(Struct, kw_only=False, frozen=True):
|
|
96
|
+
a: int
|
|
97
|
+
b: int
|
|
98
|
+
|
|
99
|
+
my_struct = MyStruct(1, 2) # ok
|
|
100
|
+
my_struct.a = 2 # FrozenInstanceError
|
|
88
101
|
|
|
89
102
|
|
|
90
103
|
Installing
|
|
@@ -95,6 +108,14 @@ Install using pip:
|
|
|
95
108
|
$ pip install construct-classes
|
|
96
109
|
|
|
97
110
|
|
|
111
|
+
Changelog
|
|
112
|
+
~~~~~~~~~
|
|
113
|
+
|
|
114
|
+
See `CHANGELOG.rst`_.
|
|
115
|
+
|
|
116
|
+
.. _CHANGELOG.rst: https://github.com/matejcik/construct-classes/blob/master/CHANGELOG.rst
|
|
117
|
+
|
|
118
|
+
|
|
98
119
|
Footer
|
|
99
120
|
------
|
|
100
121
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "construct-classes"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.2.0"
|
|
4
4
|
authors = ["matejcik <ja@matejcik.cz>"]
|
|
5
5
|
classifiers = [
|
|
6
6
|
"Development Status :: 2 - Pre-Alpha",
|
|
@@ -14,16 +14,25 @@ classifiers = [
|
|
|
14
14
|
"Programming Language :: Python :: 3.9",
|
|
15
15
|
"Programming Language :: Python :: 3.10",
|
|
16
16
|
"Programming Language :: Python :: 3.11",
|
|
17
|
+
"Programming Language :: Python :: 3.12",
|
|
18
|
+
"Programming Language :: Python :: 3.13",
|
|
19
|
+
"Programming Language :: Python :: 3.14",
|
|
17
20
|
]
|
|
18
21
|
description = "Parse your binary structs into dataclasses"
|
|
19
22
|
homepage = "https://github.com/matejcik/construct-classes"
|
|
20
23
|
license = "MIT"
|
|
21
24
|
repository = "https://github.com/matejcik/construct-classes"
|
|
22
25
|
readme = "README.rst"
|
|
26
|
+
include = [
|
|
27
|
+
{ path = "CHANGELOG.rst", format = "sdist" },
|
|
28
|
+
{ path = "LICENSE", format = "sdist" },
|
|
29
|
+
{ path = "README.rst", format = "sdist" }
|
|
30
|
+
]
|
|
23
31
|
|
|
24
32
|
[tool.poetry.dependencies]
|
|
25
33
|
python = ">=3.6.2,<4.0"
|
|
26
34
|
construct = "^2.10"
|
|
35
|
+
dataclasses = { version = "^0.8", python = "~3.6.0" }
|
|
27
36
|
|
|
28
37
|
[tool.poetry.dev-dependencies]
|
|
29
38
|
pytest = ">5"
|
|
@@ -31,7 +40,7 @@ black = "^22.8.0"
|
|
|
31
40
|
isort = "^5.10.1"
|
|
32
41
|
flake8 = "^5.0.4"
|
|
33
42
|
construct-typing = { version = "^0.5.2", python = ">=3.7" }
|
|
34
|
-
typing-extensions = ">4"
|
|
43
|
+
typing-extensions = { version = ">4.2", python = ">=3.7" }
|
|
35
44
|
|
|
36
45
|
[build-system]
|
|
37
46
|
requires = ["poetry-core>=1.0.0"]
|
|
@@ -2,7 +2,17 @@ import dataclasses
|
|
|
2
2
|
import typing as t
|
|
3
3
|
|
|
4
4
|
import construct as c
|
|
5
|
-
|
|
5
|
+
|
|
6
|
+
if t.TYPE_CHECKING:
|
|
7
|
+
from typing_extensions import dataclass_transform
|
|
8
|
+
else:
|
|
9
|
+
|
|
10
|
+
def dataclass_transform(**kwargs: t.Any) -> t.Any:
|
|
11
|
+
def inner(cls: t.Any) -> t.Any:
|
|
12
|
+
return cls
|
|
13
|
+
|
|
14
|
+
return inner
|
|
15
|
+
|
|
6
16
|
|
|
7
17
|
# workaround for mypy self type bug
|
|
8
18
|
Self = t.TypeVar("Self", bound="Struct")
|
|
@@ -20,13 +30,23 @@ def subcon(
|
|
|
20
30
|
return dataclasses.field(metadata=metadata, **kwargs)
|
|
21
31
|
|
|
22
32
|
|
|
23
|
-
@dataclass_transform(
|
|
33
|
+
@dataclass_transform(field_specifiers=(subcon,), kw_only_default=True)
|
|
24
34
|
class _StructMeta(type):
|
|
25
35
|
def __new__(
|
|
26
|
-
cls,
|
|
36
|
+
cls,
|
|
37
|
+
name: str,
|
|
38
|
+
bases: t.Tuple[type, ...],
|
|
39
|
+
namespace: t.Dict[str, t.Any],
|
|
40
|
+
*,
|
|
41
|
+
kw_only: bool = True,
|
|
42
|
+
**kwargs: t.Any,
|
|
27
43
|
) -> type:
|
|
28
44
|
new_cls = super().__new__(cls, name, bases, namespace)
|
|
29
|
-
|
|
45
|
+
if bases:
|
|
46
|
+
assert bases[0].__name__ == "Struct"
|
|
47
|
+
return dataclasses.dataclass(kw_only=kw_only, **kwargs)(new_cls)
|
|
48
|
+
else:
|
|
49
|
+
return new_cls
|
|
30
50
|
|
|
31
51
|
|
|
32
52
|
class Struct(metaclass=_StructMeta):
|
|
@@ -43,17 +63,18 @@ class Struct(metaclass=_StructMeta):
|
|
|
43
63
|
|
|
44
64
|
@classmethod
|
|
45
65
|
def from_parsed(cls: t.Type[Self], data: c.Container) -> Self:
|
|
46
|
-
|
|
66
|
+
args = {}
|
|
47
67
|
for field in dataclasses.fields(cls):
|
|
68
|
+
field_data = data.get(field.name)
|
|
48
69
|
subcls = field.metadata.get("substruct")
|
|
49
70
|
if subcls is None:
|
|
71
|
+
args[field.name] = field_data
|
|
50
72
|
continue
|
|
51
73
|
|
|
52
|
-
field_data = data.get(field.name)
|
|
53
74
|
if isinstance(field_data, c.ListContainer):
|
|
54
|
-
|
|
75
|
+
args[field.name] = [subcls.from_parsed(d) for d in field_data]
|
|
55
76
|
elif isinstance(field_data, c.Container):
|
|
56
|
-
|
|
77
|
+
args[field.name] = subcls.from_parsed(field_data)
|
|
57
78
|
elif field_data is None:
|
|
58
79
|
continue
|
|
59
80
|
else:
|
|
@@ -61,9 +82,9 @@ class Struct(metaclass=_StructMeta):
|
|
|
61
82
|
f"Mismatched type for field {field.name}: expected a struct, found {type(field_data)}"
|
|
62
83
|
)
|
|
63
84
|
|
|
64
|
-
for key in
|
|
65
|
-
|
|
66
|
-
return cls(**
|
|
85
|
+
for key in args:
|
|
86
|
+
args[key] = cls._decontainerize(args[key])
|
|
87
|
+
return cls(**args)
|
|
67
88
|
|
|
68
89
|
@classmethod
|
|
69
90
|
def parse(cls: t.Type[Self], data: bytes) -> Self:
|
construct-classes-0.1.1/setup.py
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
from setuptools import setup
|
|
3
|
-
|
|
4
|
-
package_dir = \
|
|
5
|
-
{'': 'src'}
|
|
6
|
-
|
|
7
|
-
packages = \
|
|
8
|
-
['construct_classes']
|
|
9
|
-
|
|
10
|
-
package_data = \
|
|
11
|
-
{'': ['*']}
|
|
12
|
-
|
|
13
|
-
install_requires = \
|
|
14
|
-
['construct>=2.10,<3.0']
|
|
15
|
-
|
|
16
|
-
setup_kwargs = {
|
|
17
|
-
'name': 'construct-classes',
|
|
18
|
-
'version': '0.1.1',
|
|
19
|
-
'description': 'Parse your binary structs into dataclasses',
|
|
20
|
-
'long_description': '=================\nconstruct-classes\n=================\n\n.. image:: https://img.shields.io/pypi/v/construct-classes.svg\n :target: https://pypi.python.org/pypi/construct-classes\n\n.. .. image:: https://readthedocs.org/projects/construct-classes/badge/?version=latest\n.. :target: https://construct-classes.readthedocs.io/en/latest/?badge=latest\n.. :alt: Documentation Status\n\n.. image:: https://pyup.io/repos/github/trezor/construct-classes/shield.svg\n :target: https://pyup.io/repos/github/trezor/construct-classes/\n :alt: Updates\n\n\nParse your binary data into dataclasses. Pack your dataclasses into binary data.\n\n:code:`construct-classes` rely on `construct`_ for parsing and packing. The\nprogrammer needs to manually write the Construct expressions. There is also no type\nverification, so it is the programmer\'s responsibility that the dataclass and the\nConstruct expression match.\n\nFor fully type annotated experience, install `construct-typing`_.\n\nThis package typechecks with `mypy`_ and `pyright`_.\n\n.. _construct: https://construct.readthedocs.io/en/latest/\n.. _construct-typing: https://github.com/timrid/construct-typing\n.. _mypy: https://mypy.readthedocs.io/en/stable/\n.. _pyright: https://github.com/microsoft/pyright\n\nUsage\n-----\n\nAny child of :code:`Struct` is a Python dataclass. It expects a Construct :code:`Struct`\nexpression in the :code:`SUBCON` attribute. The names of the attributes of the dataclass\nmust match the names of the fields in the Construct struct.\n\n.. code-block:: python\n\n import construct as c\n from construct_classes import Struct, subcon\n\n class BasicStruct(Struct):\n x: int\n y: int\n description: str\n\n SUBCON = c.Struct(\n "x" / c.Int32ul,\n "y" / c.Int32ul,\n "description" / c.PascalString(c.Int8ul, "utf8"),\n )\n\n\n data = b"\\x01\\x00\\x00\\x00\\x02\\x00\\x00\\x00\\x05hello"\n parsed = BasicStruct.parse(data)\n print(parsed) # BasicStruct(x=1, y=2, description=\'hello\')\n\n new_data = BasicStruct(x=100, y=200, description="world")\n print(new_data.build()) # b\'\\x64\\x00\\x00\\x00\\xc8\\x00\\x00\\x00\\x05world\'\n\n\n:code:`construct-classes` support nested structs, but you need to declare them explicitly:\n\n.. code-block:: python\n\n class LargerStruct(Struct):\n # specify the subclass type:\n basic: BasicStruct = subcon(BasicStruct)\n # in case of a list, specify the item type:\n basic_array: List[BasicStruct] = subcon(BasicStruct)\n # the `subcon()` function supports all arguments of `dataclass.field`:\n default_array: List[BasicStruct] = subcon(BasicStruct, default_factory=list)\n\n # to refer to the subcon, use the `SUBCON` class attribute:\n SUBCON = c.Struct(\n "basic" / BasicStruct.SUBCON,\n "basic_array" / c.Array(2, BasicStruct.SUBCON),\n "default_array" / c.PrefixedArray(c.Int8ul, BasicStruct.SUBCON),\n )\n\nUse :code:`dataclasses.field()` to specify attributes on fields that are not subcons.\n\nThere are currently no other features. In particular, the resulting class is a Python\ndataclass, but you cannot specify its parameters like `frozen` etc.\n\n\nInstalling\n----------\n\nInstall using pip:\n\n $ pip install construct-classes\n\n\nFooter\n------\n\n* Free software: MIT License\n\n.. * Documentation: https://construct-classes.readthedocs.io.\n',
|
|
21
|
-
'author': 'matejcik',
|
|
22
|
-
'author_email': 'ja@matejcik.cz',
|
|
23
|
-
'maintainer': None,
|
|
24
|
-
'maintainer_email': None,
|
|
25
|
-
'url': 'https://github.com/matejcik/construct-classes',
|
|
26
|
-
'package_dir': package_dir,
|
|
27
|
-
'packages': packages,
|
|
28
|
-
'package_data': package_data,
|
|
29
|
-
'install_requires': install_requires,
|
|
30
|
-
'python_requires': '>=3.6.2,<4.0',
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
setup(**setup_kwargs)
|
|
File without changes
|