ducktools-classbuilder 0.1.0__py3-none-any.whl
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.
Potentially problematic release.
This version of ducktools-classbuilder might be problematic. Click here for more details.
- ducktools/classbuilder/__init__.py +418 -0
- ducktools/classbuilder/__init__.pyi +111 -0
- ducktools/classbuilder/prefab.py +909 -0
- ducktools/classbuilder/prefab.pyi +151 -0
- ducktools/classbuilder/py.typed +1 -0
- ducktools_classbuilder-0.1.0.dist-info/LICENSE.md +21 -0
- ducktools_classbuilder-0.1.0.dist-info/METADATA +179 -0
- ducktools_classbuilder-0.1.0.dist-info/RECORD +10 -0
- ducktools_classbuilder-0.1.0.dist-info/WHEEL +5 -0
- ducktools_classbuilder-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import typing
|
|
2
|
+
from collections.abc import Callable
|
|
3
|
+
|
|
4
|
+
from . import (
|
|
5
|
+
INTERNALS_DICT, NOTHING,
|
|
6
|
+
Field, MethodMaker, SlotFields as SlotFields,
|
|
7
|
+
builder, fieldclass, get_internals, slot_gatherer
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
PREFAB_FIELDS: str
|
|
11
|
+
PREFAB_INIT_FUNC: str
|
|
12
|
+
PRE_INIT_FUNC: str
|
|
13
|
+
POST_INIT_FUNC: str
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# noinspection PyPep8Naming
|
|
17
|
+
class _KW_ONLY_TYPE:
|
|
18
|
+
def __repr__(self) -> str: ...
|
|
19
|
+
|
|
20
|
+
KW_ONLY: _KW_ONLY_TYPE
|
|
21
|
+
|
|
22
|
+
class PrefabError(Exception): ...
|
|
23
|
+
|
|
24
|
+
def _is_classvar(hint: type | str) -> bool: ...
|
|
25
|
+
|
|
26
|
+
def get_attributes(cls: type) -> dict[str, Attribute]: ...
|
|
27
|
+
|
|
28
|
+
def get_init_maker(*, init_name: str="__init__") -> MethodMaker: ...
|
|
29
|
+
|
|
30
|
+
def get_repr_maker(*, recursion_safe: bool = False) -> MethodMaker: ...
|
|
31
|
+
|
|
32
|
+
def get_eq_maker() -> MethodMaker: ...
|
|
33
|
+
|
|
34
|
+
def get_iter_maker() -> MethodMaker: ...
|
|
35
|
+
|
|
36
|
+
def get_frozen_setattr_maker() -> MethodMaker: ...
|
|
37
|
+
|
|
38
|
+
def get_frozen_delattr_maker() -> MethodMaker: ...
|
|
39
|
+
|
|
40
|
+
def get_asdict_maker() -> MethodMaker: ...
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
init_desc: MethodMaker
|
|
44
|
+
prefab_init_desc: MethodMaker
|
|
45
|
+
repr_desc: MethodMaker
|
|
46
|
+
recursive_repr_desc: MethodMaker
|
|
47
|
+
eq_desc: MethodMaker
|
|
48
|
+
iter_desc: MethodMaker
|
|
49
|
+
frozen_setattr_desc: MethodMaker
|
|
50
|
+
frozen_delattr_desc: MethodMaker
|
|
51
|
+
asdict_desc: MethodMaker
|
|
52
|
+
|
|
53
|
+
class Attribute(Field):
|
|
54
|
+
__slots__: dict
|
|
55
|
+
|
|
56
|
+
init: bool
|
|
57
|
+
repr: bool
|
|
58
|
+
compare: bool
|
|
59
|
+
kw_only: bool
|
|
60
|
+
in_dict: bool
|
|
61
|
+
exclude_field: bool
|
|
62
|
+
|
|
63
|
+
def __init__(
|
|
64
|
+
self,
|
|
65
|
+
*,
|
|
66
|
+
default: typing.Any | NOTHING =NOTHING,
|
|
67
|
+
default_factory: typing.Any | NOTHING = NOTHING,
|
|
68
|
+
type: type | NOTHING = NOTHING,
|
|
69
|
+
doc: str | None = None,
|
|
70
|
+
init: bool = True,
|
|
71
|
+
repr: bool = True,
|
|
72
|
+
compare: bool = True,
|
|
73
|
+
kw_only: bool = False,
|
|
74
|
+
in_dict: bool = True,
|
|
75
|
+
exclude_field: bool = False,
|
|
76
|
+
) -> None: ...
|
|
77
|
+
|
|
78
|
+
def __repr__(self) -> str: ...
|
|
79
|
+
@typing.overload
|
|
80
|
+
def __eq__(self, other: Attribute) -> bool: ...
|
|
81
|
+
def __eq__(self, other: object) -> NotImplemented: ...
|
|
82
|
+
|
|
83
|
+
def validate_field(self) -> None: ...
|
|
84
|
+
|
|
85
|
+
def attribute(
|
|
86
|
+
*,
|
|
87
|
+
default: typing.Any | NOTHING = NOTHING,
|
|
88
|
+
default_factory: typing.Any | NOTHING = NOTHING,
|
|
89
|
+
type: type | NOTHING = NOTHING,
|
|
90
|
+
doc: str | None = None,
|
|
91
|
+
init: bool = True,
|
|
92
|
+
repr: bool = True,
|
|
93
|
+
compare: bool = True,
|
|
94
|
+
kw_only: bool = False,
|
|
95
|
+
in_dict: bool = True,
|
|
96
|
+
exclude_field: bool = False,
|
|
97
|
+
) -> Attribute: ...
|
|
98
|
+
|
|
99
|
+
def attribute_gatherer(cls: type) -> dict[str, Attribute]: ...
|
|
100
|
+
|
|
101
|
+
def _make_prefab(
|
|
102
|
+
cls: type,
|
|
103
|
+
*,
|
|
104
|
+
init: bool = True,
|
|
105
|
+
repr: bool = True,
|
|
106
|
+
eq: bool = True,
|
|
107
|
+
iter: bool = False,
|
|
108
|
+
match_args: bool = True,
|
|
109
|
+
kw_only: bool = False,
|
|
110
|
+
frozen: bool = False,
|
|
111
|
+
dict_method: bool = False,
|
|
112
|
+
recursive_repr: bool = False,
|
|
113
|
+
) -> type: ...
|
|
114
|
+
|
|
115
|
+
@typing.dataclass_transform
|
|
116
|
+
def prefab(
|
|
117
|
+
cls: type | None = None,
|
|
118
|
+
*,
|
|
119
|
+
init: bool = True,
|
|
120
|
+
repr: bool = True,
|
|
121
|
+
eq: bool = True,
|
|
122
|
+
iter: bool = False,
|
|
123
|
+
match_args: bool = True,
|
|
124
|
+
kw_only: bool = False,
|
|
125
|
+
frozen: bool = False,
|
|
126
|
+
dict_method: bool = False,
|
|
127
|
+
recursive_repr: bool = False,
|
|
128
|
+
) -> type | Callable[[type], type]: ...
|
|
129
|
+
|
|
130
|
+
def build_prefab(
|
|
131
|
+
class_name: str,
|
|
132
|
+
attributes: list[tuple[str, Attribute]],
|
|
133
|
+
*,
|
|
134
|
+
bases: tuple[type, ...] = (),
|
|
135
|
+
class_dict: dict[str, typing.Any] | None = None,
|
|
136
|
+
init: bool = True,
|
|
137
|
+
repr: bool = True,
|
|
138
|
+
eq: bool = True,
|
|
139
|
+
iter: bool = False,
|
|
140
|
+
match_args: bool = True,
|
|
141
|
+
kw_only: bool = False,
|
|
142
|
+
frozen: bool = False,
|
|
143
|
+
dict_method: bool = False,
|
|
144
|
+
recursive_repr: bool = False,
|
|
145
|
+
) -> type: ...
|
|
146
|
+
|
|
147
|
+
def is_prefab(o: typing.Any) -> bool: ...
|
|
148
|
+
|
|
149
|
+
def is_prefab_instance(o: object) -> bool: ...
|
|
150
|
+
|
|
151
|
+
def as_dict(o) -> dict[str, typing.Any]: ...
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
partial
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 David C Ellis
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: ducktools-classbuilder
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Toolkit for creating class boilerplate generators
|
|
5
|
+
Author: David C Ellis
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2024 David C Ellis
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Homepage, https://github.com/davidcellis/ducktools-classbuilder
|
|
29
|
+
Classifier: Development Status :: 4 - Beta
|
|
30
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
31
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
32
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
33
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
34
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
35
|
+
Classifier: Operating System :: OS Independent
|
|
36
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
37
|
+
Requires-Python: >=3.8
|
|
38
|
+
Description-Content-Type: text/markdown
|
|
39
|
+
License-File: LICENSE.md
|
|
40
|
+
Provides-Extra: docs
|
|
41
|
+
Requires-Dist: sphinx ; extra == 'docs'
|
|
42
|
+
Requires-Dist: myst-parser ; extra == 'docs'
|
|
43
|
+
Requires-Dist: sphinx-rtd-theme ; extra == 'docs'
|
|
44
|
+
Provides-Extra: testing
|
|
45
|
+
Requires-Dist: pytest ; extra == 'testing'
|
|
46
|
+
Requires-Dist: pytest-cov ; extra == 'testing'
|
|
47
|
+
|
|
48
|
+
# Ducktools: Class Builder #
|
|
49
|
+
|
|
50
|
+
`ducktools-classbuilder` is *the* Python package that will bring you the **joy**
|
|
51
|
+
of writing... functions... that will bring back the **joy** of writing classes.
|
|
52
|
+
|
|
53
|
+
Maybe.
|
|
54
|
+
|
|
55
|
+
While `attrs` and `dataclasses` are class boilerplate generators,
|
|
56
|
+
`ducktools.classbuilder` is intended to be a dataclasses-like generator.
|
|
57
|
+
The goal is to handle some of the basic functions and to allow for flexible
|
|
58
|
+
customization of both the field collection and the method generation.
|
|
59
|
+
|
|
60
|
+
`ducktools.classbuilder.prefab` includes a prebuilt implementation using these tools.
|
|
61
|
+
|
|
62
|
+
## Slot Class Usage ##
|
|
63
|
+
|
|
64
|
+
The building toolkit also includes a basic implementation that uses
|
|
65
|
+
`__slots__` to define the fields by assigning a `SlotFields` instance.
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
from ducktools.classbuilder import slotclass, Field, SlotFields
|
|
69
|
+
|
|
70
|
+
@slotclass
|
|
71
|
+
class SlottedDC:
|
|
72
|
+
__slots__ = SlotFields(
|
|
73
|
+
the_answer=42,
|
|
74
|
+
the_question=Field(
|
|
75
|
+
default="What do you get if you multiply six by nine?",
|
|
76
|
+
doc="Life, the Universe, and Everything",
|
|
77
|
+
),
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
ex = SlottedDC()
|
|
81
|
+
print(ex)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Why does the basic implementation use slots? ##
|
|
85
|
+
|
|
86
|
+
Dataclasses has a problem when you use `@dataclass(slots=True)`,
|
|
87
|
+
although this is not unique to dataclasses but inherent to the way both
|
|
88
|
+
`__slots__` and decorators work.
|
|
89
|
+
|
|
90
|
+
In order for this to *appear* to work, dataclasses has to make a new class
|
|
91
|
+
and attempt to copy over everything from the original. This is because
|
|
92
|
+
decorators operate on classes *after they have been created* while slots
|
|
93
|
+
need to be declared beforehand. While you can change the value of `__slots__`
|
|
94
|
+
after a class has been created, this will have no effect on the internal
|
|
95
|
+
structure of the class.
|
|
96
|
+
|
|
97
|
+
By declaring the class using `__slots__` on the other hand, we can take
|
|
98
|
+
advantage of the fact that it accepts a mapping, where the keys will be
|
|
99
|
+
used as the attributes to create as slots. The values can then be used as
|
|
100
|
+
the default values equivalently to how type hints are used in dataclasses.
|
|
101
|
+
|
|
102
|
+
For example these two classes would be roughly equivalent, except
|
|
103
|
+
`@dataclass` has had to recreate the class from scratch while `@slotclass`
|
|
104
|
+
has simply added the methods on to the original class. This is easy to
|
|
105
|
+
demonstrate using another decorator.
|
|
106
|
+
|
|
107
|
+
> This example requires Python 3.10 as earlier versions of
|
|
108
|
+
> `dataclasses` did not support the `slots` argument.
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
from dataclasses import dataclass
|
|
112
|
+
from ducktools.classbuilder import slotclass, SlotFields
|
|
113
|
+
|
|
114
|
+
class_register = {}
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def register(cls):
|
|
118
|
+
class_register[cls.__name__] = cls
|
|
119
|
+
return cls
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
@dataclass(slots=True)
|
|
123
|
+
@register
|
|
124
|
+
class DataCoords:
|
|
125
|
+
x: float = 0.0
|
|
126
|
+
y: float = 0.0
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
@slotclass
|
|
130
|
+
@register
|
|
131
|
+
class SlotCoords:
|
|
132
|
+
__slots__ = SlotFields(x=0.0, y=0.0)
|
|
133
|
+
# Type hints don't affect class construction, these are optional.
|
|
134
|
+
x: float
|
|
135
|
+
y: float
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
print(DataCoords())
|
|
139
|
+
print(SlotCoords())
|
|
140
|
+
|
|
141
|
+
print(f"{DataCoords is class_register[DataCoords.__name__] = }")
|
|
142
|
+
print(f"{SlotCoords is class_register[SlotCoords.__name__] = }")
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## What features does this have? ##
|
|
147
|
+
|
|
148
|
+
Included as an example implementation, the `slotclass` generator supports
|
|
149
|
+
`default_factory` for creating mutable defaults like lists, dicts etc.
|
|
150
|
+
It also supports default values that are not builtins (try this on
|
|
151
|
+
[Cluegen](https://github.com/dabeaz/cluegen)).
|
|
152
|
+
|
|
153
|
+
It will copy values provided as the `type` to `Field` into the
|
|
154
|
+
`__annotations__` dictionary of the class.
|
|
155
|
+
Values provided to `doc` will be placed in the final `__slots__`
|
|
156
|
+
field so they are present on the class if `help(...)` is called.
|
|
157
|
+
|
|
158
|
+
If you want something with more features you can look at the `prefab.py`
|
|
159
|
+
implementation which provides a 'prebuilt' implementation.
|
|
160
|
+
|
|
161
|
+
For more information on creating class generators using the builder
|
|
162
|
+
see [the docs](https://ducktools-classbuilder.readthedocs.io/en/latest/extension_examples.html)
|
|
163
|
+
|
|
164
|
+
## Will you add \<feature\> to `classbuilder.prefab`? ##
|
|
165
|
+
|
|
166
|
+
No. Not unless it's something I need or find interesting.
|
|
167
|
+
|
|
168
|
+
The original version of `prefab_classes` was intended to have every feature
|
|
169
|
+
anybody could possibly require, but this is no longer the case with this
|
|
170
|
+
rebuilt version.
|
|
171
|
+
|
|
172
|
+
I will fix bugs (assuming they're not actually intended behaviour).
|
|
173
|
+
|
|
174
|
+
However the whole goal of this module is if you want to have a class generator
|
|
175
|
+
with a specific feature, you can create or add it yourself.
|
|
176
|
+
|
|
177
|
+
## Credit ##
|
|
178
|
+
|
|
179
|
+
Heavily inspired by [David Beazley's Cluegen](https://github.com/dabeaz/cluegen)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
ducktools/classbuilder/__init__.py,sha256=oEdcQdMEqaQjUfbPkHpe55iCiPssDQxf4zxoAMdsTt8,12950
|
|
2
|
+
ducktools/classbuilder/__init__.pyi,sha256=BlpHmxIL4dAiVKgqElRR3wVs7aw73qyJRaSvr-Tuyc0,2770
|
|
3
|
+
ducktools/classbuilder/prefab.py,sha256=qQJzN4ys6Av6s9NaabzSqRKE5BXDfhidt3EtGZ0HAxQ,29405
|
|
4
|
+
ducktools/classbuilder/prefab.pyi,sha256=wrq8NKwy9TsQ6fpnMyTf4DaGtCOK_90NHeU61CfNOo4,3589
|
|
5
|
+
ducktools/classbuilder/py.typed,sha256=la67KBlbjXN-_-DfGNcdOcjYumVpKG_Tkw-8n5dnGB4,8
|
|
6
|
+
ducktools_classbuilder-0.1.0.dist-info/LICENSE.md,sha256=6Thz9Dbw8R4fWInl6sGl8Rj3UnKnRbDwrc6jZerpugQ,1070
|
|
7
|
+
ducktools_classbuilder-0.1.0.dist-info/METADATA,sha256=FHgeLZx-RfcvY2ty1l6O19z449So-UQZIcBinJ8n5xU,6675
|
|
8
|
+
ducktools_classbuilder-0.1.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
9
|
+
ducktools_classbuilder-0.1.0.dist-info/top_level.txt,sha256=uSDLtio3ZFqdwcsMJ2O5yhjB4Q3ytbBWbA8rJREganc,10
|
|
10
|
+
ducktools_classbuilder-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ducktools
|