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.

@@ -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,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: bdist_wheel (0.43.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ ducktools