ducktools-classbuilder 0.5.1__py3-none-any.whl → 0.6.1__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.

@@ -1,270 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: ducktools-classbuilder
3
- Version: 0.5.1
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
- Requires-Dist: mypy ; extra == 'testing'
48
- Requires-Dist: typing-extensions ; (python_version < "3.10") and extra == 'testing'
49
-
50
- # Ducktools: Class Builder #
51
-
52
- `ducktools-classbuilder` is *the* Python package that will bring you the **joy**
53
- of writing... functions... that will bring back the **joy** of writing classes.
54
-
55
- Maybe.
56
-
57
- While `attrs` and `dataclasses` are class boilerplate generators,
58
- `ducktools.classbuilder` is intended to be a `@dataclass`-like generator.
59
- The goal is to handle some of the basic functions and to allow for flexible
60
- customization of both the field collection and the method generation.
61
-
62
- `ducktools.classbuilder.prefab` includes a prebuilt implementation using these tools.
63
-
64
- Install from PyPI with:
65
- `python -m pip install ducktools-classbuilder`
66
-
67
- ## Usage: building a class decorator ##
68
-
69
- In order to create a class decorator using `ducktools.classbuilder` there are
70
- a few things you need to prepare.
71
-
72
- 1. A field gathering function to analyse the class and collect valid `Field`s and provide
73
- any modifications that need to be applied to the class attributes.
74
- * An example `slot_gatherer` is included.
75
- 2. Code generators that can make use of the gathered `Field`s to create magic method
76
- source code. To be made into descriptors by `MethodMaker`.
77
- * Example `init_generator`, `repr_generator` and `eq_generator` generators are included.
78
- 3. A function that calls the `builder` function to apply both of these steps.
79
-
80
- A field gathering function needs to take the original class as an argument and
81
- return a dictionary of `{key: Field(...)}` pairs.
82
-
83
- > [!NOTE]
84
- > The `builder` will handle inheritance so do not collect fields from parent classes.
85
-
86
- The code generators take the class as the only argument and return a tuple
87
- of method source code and globals to be provided to `exec(code, globs)` in order
88
- to generate the actual method.
89
-
90
- The provided `slot_gatherer` looks for `__slots__` being assigned a `SlotFields`
91
- class[^1] where keyword arguments define the names and values for the fields.
92
-
93
- Code generator functions need to be converted to descriptors before being used.
94
- This is done using the provided `MethodMaker` descriptor class.
95
- ex: `init_maker = MethodMaker("__init__", init_generator)`.
96
-
97
- These parts can then be used to make a basic class boilerplate generator by
98
- providing them to the `builder` function.
99
-
100
- ```python
101
- from ducktools.classbuilder import (
102
- builder,
103
- slot_gatherer,
104
- init_generator, eq_generator, repr_generator,
105
- MethodMaker,
106
- )
107
-
108
- init_maker = MethodMaker("__init__", init_generator)
109
- repr_maker = MethodMaker("__repr__", repr_generator)
110
- eq_maker = MethodMaker("__eq__", eq_generator)
111
-
112
-
113
- def slotclass(cls):
114
- return builder(cls, gatherer=slot_gatherer, methods={init_maker, repr_maker, eq_maker})
115
- ```
116
-
117
- ## Slot Class Usage ##
118
-
119
- This created `slotclass` function can then be used as a decorator to generate classes in
120
- a similar manner to the `@dataclass` decorator from `dataclasses`.
121
-
122
- > [!NOTE]
123
- > `ducktools.classbuilder` includes a premade version of `slotclass` that can
124
- > be used directly. (The included version has some extra features).
125
-
126
- ```python
127
- from ducktools.classbuilder import Field, SlotFields, slotclass
128
-
129
- @slotclass
130
- class SlottedDC:
131
- __slots__ = SlotFields(
132
- the_answer=42,
133
- the_question=Field(
134
- default="What do you get if you multiply six by nine?",
135
- doc="Life, the Universe, and Everything",
136
- ),
137
- )
138
-
139
- ex = SlottedDC()
140
- print(ex)
141
- ```
142
-
143
- > [!TIP]
144
- > For more information and examples of creating class generators with additional
145
- > features using the builder see
146
- > [the docs](https://ducktools-classbuilder.readthedocs.io/en/latest/extension_examples.html)
147
-
148
- ## Why does your example use `__slots__` instead of annotations? ##
149
-
150
- If you want to use `__slots__` in order to save memory you have to declare
151
- them when the class is originally created as you can't add them later.
152
-
153
- When you use `@dataclass(slots=True)`[^2] with `dataclasses` in order for
154
- this to work, `dataclasses` has to make a new class and attempt to
155
- copy over everything from the original.
156
- This is because decorators operate on classes *after they have been created*
157
- while slots need to be declared beforehand.
158
- While you can change the value of `__slots__` after a class has been created,
159
- this will have no effect on the internal structure of the class.
160
-
161
- By declaring the class using `__slots__` on the other hand, we can take
162
- advantage of the fact that it accepts a mapping, where the keys will be
163
- used as the attributes to create as slots. The values can then be used as
164
- the default values equivalently to how type hints are used in `dataclasses`.
165
-
166
- For example these two classes would be roughly equivalent, except that
167
- `@dataclass` has had to recreate the class from scratch while `@slotclass`
168
- has added the methods on to the original class.
169
- This means that any references stored to the original class *before*
170
- `@dataclass` has rebuilt the class will not be pointing towards the
171
- correct class.
172
- This can be demonstrated using a simple class register decorator.
173
-
174
- > This example requires Python 3.10 as earlier versions of
175
- > `dataclasses` did not support the `slots` argument.
176
-
177
- ```python
178
- from dataclasses import dataclass
179
- from ducktools.classbuilder import slotclass, SlotFields
180
-
181
- class_register = {}
182
-
183
-
184
- def register(cls):
185
- class_register[cls.__name__] = cls
186
- return cls
187
-
188
-
189
- @dataclass(slots=True)
190
- @register
191
- class DataCoords:
192
- x: float = 0.0
193
- y: float = 0.0
194
-
195
-
196
- @slotclass
197
- @register
198
- class SlotCoords:
199
- __slots__ = SlotFields(x=0.0, y=0.0)
200
- # Type hints don't affect class construction, these are optional.
201
- x: float
202
- y: float
203
-
204
-
205
- print(DataCoords())
206
- print(SlotCoords())
207
-
208
- print(f"{DataCoords is class_register[DataCoords.__name__] = }")
209
- print(f"{SlotCoords is class_register[SlotCoords.__name__] = }")
210
- ```
211
-
212
- ## Using annotations anyway ##
213
-
214
- For those that really want to use type annotations a basic `annotation_gatherer`
215
- function and `@annotationclass` decorator are also included. Slots are not generated
216
- in this case.
217
-
218
- ```python
219
- from ducktools.classbuilder import annotationclass
220
-
221
- @annotationclass
222
- class AnnotatedDC:
223
- the_answer: int = 42
224
- the_question: str = "What do you get if you multiply six by nine?"
225
-
226
-
227
- ex = AnnotatedDC()
228
- print(ex)
229
- ```
230
-
231
- ## What features does this have? ##
232
-
233
- Included as an example implementation, the `slotclass` generator supports
234
- `default_factory` for creating mutable defaults like lists, dicts etc.
235
- It also supports default values that are not builtins (try this on
236
- [Cluegen](https://github.com/dabeaz/cluegen)).
237
-
238
- It will copy values provided as the `type` to `Field` into the
239
- `__annotations__` dictionary of the class.
240
- Values provided to `doc` will be placed in the final `__slots__`
241
- field so they are present on the class if `help(...)` is called.
242
-
243
- A fairly basic `annotations_gatherer` and `annotationclass` are also included
244
- and can be used to generate classbuilders that rely on annotations.
245
-
246
- If you want something with more features you can look at the `prefab.py`
247
- implementation which provides a 'prebuilt' implementation.
248
-
249
- ## Will you add \<feature\> to `classbuilder.prefab`? ##
250
-
251
- No. Not unless it's something I need or find interesting.
252
-
253
- The original version of `prefab_classes` was intended to have every feature
254
- anybody could possibly require, but this is no longer the case with this
255
- rebuilt version.
256
-
257
- I will fix bugs (assuming they're not actually intended behaviour).
258
-
259
- However the whole goal of this module is if you want to have a class generator
260
- with a specific feature, you can create or add it yourself.
261
-
262
- ## Credit ##
263
-
264
- Heavily inspired by [David Beazley's Cluegen](https://github.com/dabeaz/cluegen)
265
-
266
- [^1]: `SlotFields` is actually just a subclassed `dict` with no changes. `__slots__`
267
- works with dictionaries using the values of the keys, while fields are normally
268
- used for documentation.
269
-
270
- [^2]: or `@attrs.define`.
@@ -1,10 +0,0 @@
1
- ducktools/classbuilder/__init__.py,sha256=rl5oc0azae-32EjeCTzhM1DR5JNR-AgOriyH5zkf4WI,20856
2
- ducktools/classbuilder/__init__.pyi,sha256=5gnHhSVMP5yArA-_cuvIeLnLAlmY_EmPMfVY9dRi0CA,4784
3
- ducktools/classbuilder/prefab.py,sha256=K9_bKh24OiGJ40BbJWVfwDObArMUxi2JRbB5ZN-t--M,28984
4
- ducktools/classbuilder/prefab.pyi,sha256=sNladRJM3lcZo8zQWvWCIInBx0wUD7PT6fhdE89OpG0,3960
5
- ducktools/classbuilder/py.typed,sha256=la67KBlbjXN-_-DfGNcdOcjYumVpKG_Tkw-8n5dnGB4,8
6
- ducktools_classbuilder-0.5.1.dist-info/LICENSE.md,sha256=6Thz9Dbw8R4fWInl6sGl8Rj3UnKnRbDwrc6jZerpugQ,1070
7
- ducktools_classbuilder-0.5.1.dist-info/METADATA,sha256=B0KO5vvdZOUZ4o28GA4zlgXuIkA9j4SuplzFByvRhjs,10143
8
- ducktools_classbuilder-0.5.1.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
9
- ducktools_classbuilder-0.5.1.dist-info/top_level.txt,sha256=uSDLtio3ZFqdwcsMJ2O5yhjB4Q3ytbBWbA8rJREganc,10
10
- ducktools_classbuilder-0.5.1.dist-info/RECORD,,