ducktools-classbuilder 0.10.0__py3-none-any.whl → 0.10.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.
- ducktools/classbuilder/__init__.py +26 -18
- ducktools/classbuilder/__init__.pyi +3 -2
- ducktools/classbuilder/_version.py +2 -2
- ducktools/classbuilder/annotations.py +23 -0
- ducktools/classbuilder/annotations.pyi +4 -0
- ducktools/classbuilder/prefab.py +5 -3
- ducktools/classbuilder/prefab.pyi +2 -1
- {ducktools_classbuilder-0.10.0.dist-info → ducktools_classbuilder-0.10.1.dist-info}/METADATA +1 -1
- ducktools_classbuilder-0.10.1.dist-info/RECORD +13 -0
- ducktools_classbuilder-0.10.0.dist-info/RECORD +0 -13
- {ducktools_classbuilder-0.10.0.dist-info → ducktools_classbuilder-0.10.1.dist-info}/WHEEL +0 -0
- {ducktools_classbuilder-0.10.0.dist-info → ducktools_classbuilder-0.10.1.dist-info}/licenses/LICENSE +0 -0
- {ducktools_classbuilder-0.10.0.dist-info → ducktools_classbuilder-0.10.1.dist-info}/top_level.txt +0 -0
|
@@ -217,15 +217,23 @@ class _SignatureMaker:
|
|
|
217
217
|
# help(cls) will fail along with inspect.signature(cls)
|
|
218
218
|
# This signature maker descriptor is placed to override __signature__ and force
|
|
219
219
|
# the `__init__` signature to be generated first if the signature is requested.
|
|
220
|
-
def __get__(self, instance, cls):
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
#
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
220
|
+
def __get__(self, instance, cls=None):
|
|
221
|
+
if cls is None:
|
|
222
|
+
cls = type(instance)
|
|
223
|
+
|
|
224
|
+
# force generation of `__init__` function
|
|
225
|
+
_ = cls.__init__
|
|
226
|
+
|
|
227
|
+
if instance is None:
|
|
228
|
+
raise AttributeError(
|
|
229
|
+
f"type object {cls.__name__!r} "
|
|
230
|
+
"has no attribute '__signature__'"
|
|
231
|
+
)
|
|
232
|
+
else:
|
|
233
|
+
raise AttributeError(
|
|
234
|
+
f"{cls.__name__!r} object"
|
|
235
|
+
"has no attribute '__signature__'"
|
|
236
|
+
)
|
|
229
237
|
|
|
230
238
|
|
|
231
239
|
signature_maker = _SignatureMaker()
|
|
@@ -393,7 +401,7 @@ def replace_generator(cls, funcname="__replace__"):
|
|
|
393
401
|
# Generate the replace method for built classes
|
|
394
402
|
# unlike the dataclasses implementation this is generated
|
|
395
403
|
attribs = get_fields(cls)
|
|
396
|
-
|
|
404
|
+
|
|
397
405
|
# This is essentially the as_dict generator for prefabs
|
|
398
406
|
# except based on attrib.init instead of .serialize
|
|
399
407
|
vals = ", ".join(
|
|
@@ -407,7 +415,7 @@ def replace_generator(cls, funcname="__replace__"):
|
|
|
407
415
|
f"def {funcname}(self, /, **changes):\n"
|
|
408
416
|
f" new_kwargs = {init_dict}\n"
|
|
409
417
|
f" for name, value in changes.items():\n"
|
|
410
|
-
f" if name not in new_kwargs:\n"
|
|
418
|
+
f" if name not in new_kwargs:\n"
|
|
411
419
|
f" raise TypeError(\n"
|
|
412
420
|
f" f\"{{name!r}} is not a valid replacable \"\n"
|
|
413
421
|
f" f\"field on {{self.__class__.__name__!r}}\"\n"
|
|
@@ -578,7 +586,7 @@ class SlotMakerMeta(type):
|
|
|
578
586
|
def __new__(cls, name, bases, ns, slots=True, gatherer=None, **kwargs):
|
|
579
587
|
# This should only run if slots=True is declared
|
|
580
588
|
# and __slots__ have not already been defined
|
|
581
|
-
if slots and "__slots__" not in ns:
|
|
589
|
+
if slots and "__slots__" not in ns:
|
|
582
590
|
# Check if a different gatherer has been set in any base classes
|
|
583
591
|
# Default to unified gatherer
|
|
584
592
|
if gatherer is None:
|
|
@@ -617,7 +625,7 @@ class SlotMakerMeta(type):
|
|
|
617
625
|
# Place pre-gathered field data - modifications are already applied
|
|
618
626
|
modifications = {}
|
|
619
627
|
ns[GATHERED_DATA] = fields, modifications
|
|
620
|
-
|
|
628
|
+
|
|
621
629
|
else:
|
|
622
630
|
if gatherer is not None:
|
|
623
631
|
ns[META_GATHERER_NAME] = gatherer
|
|
@@ -642,7 +650,7 @@ class GatheredFields:
|
|
|
642
650
|
def __eq__(self, other):
|
|
643
651
|
if type(self) is type(other):
|
|
644
652
|
return self.fields == other.fields and self.modifications == other.modifications
|
|
645
|
-
|
|
653
|
+
|
|
646
654
|
def __repr__(self):
|
|
647
655
|
return f"{type(self).__name__}(fields={self.fields!r}, modifications={self.modifications!r})"
|
|
648
656
|
|
|
@@ -761,11 +769,11 @@ def _build_field():
|
|
|
761
769
|
# Complete the construction of the Field class
|
|
762
770
|
field_docs = {
|
|
763
771
|
"default": "Standard default value to be used for attributes with this field.",
|
|
764
|
-
"default_factory":
|
|
772
|
+
"default_factory":
|
|
765
773
|
"A zero-argument function to be called to generate a default value, "
|
|
766
774
|
"useful for mutable obects like lists.",
|
|
767
775
|
"type": "The type of the attribute to be assigned by this field.",
|
|
768
|
-
"doc":
|
|
776
|
+
"doc":
|
|
769
777
|
"The documentation for the attribute that appears when calling "
|
|
770
778
|
"help(...) on the class. (Only in slotted classes).",
|
|
771
779
|
"init": "Include this attribute in the class __init__ parameters.",
|
|
@@ -813,7 +821,7 @@ def pre_gathered_gatherer(cls_or_ns):
|
|
|
813
821
|
cls_dict = cls_or_ns
|
|
814
822
|
else:
|
|
815
823
|
cls_dict = cls_or_ns.__dict__
|
|
816
|
-
|
|
824
|
+
|
|
817
825
|
return cls_dict[GATHERED_DATA]
|
|
818
826
|
|
|
819
827
|
|
|
@@ -1043,7 +1051,7 @@ def make_unified_gatherer(
|
|
|
1043
1051
|
return anno_g(cls_dict)
|
|
1044
1052
|
|
|
1045
1053
|
return attrib_g(cls_dict)
|
|
1046
|
-
|
|
1054
|
+
|
|
1047
1055
|
return field_unified_gatherer
|
|
1048
1056
|
|
|
1049
1057
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import types
|
|
2
2
|
import typing
|
|
3
|
+
import typing_extensions
|
|
3
4
|
|
|
4
5
|
import inspect
|
|
5
6
|
|
|
@@ -57,7 +58,7 @@ class MethodMaker:
|
|
|
57
58
|
def __get__(self, instance, cls) -> Callable: ...
|
|
58
59
|
|
|
59
60
|
class _SignatureMaker:
|
|
60
|
-
def __get__(self, instance, cls) ->
|
|
61
|
+
def __get__(self, instance, cls=None) -> typing_extensions.Never: ...
|
|
61
62
|
|
|
62
63
|
signature_maker: _SignatureMaker
|
|
63
64
|
|
|
@@ -141,7 +142,7 @@ class Field(metaclass=SlotMakerMeta):
|
|
|
141
142
|
|
|
142
143
|
__slots__: dict[str, str]
|
|
143
144
|
__classbuilder_internals__: dict
|
|
144
|
-
__signature__:
|
|
145
|
+
__signature__: _SignatureMaker
|
|
145
146
|
|
|
146
147
|
def __init__(
|
|
147
148
|
self,
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
__version__ = "0.10.
|
|
2
|
-
__version_tuple__ = (0, 10,
|
|
1
|
+
__version__ = "0.10.1"
|
|
2
|
+
__version_tuple__ = (0, 10, 1)
|
|
@@ -33,6 +33,29 @@ class _LazyAnnotationLib:
|
|
|
33
33
|
_lazy_annotationlib = _LazyAnnotationLib()
|
|
34
34
|
|
|
35
35
|
|
|
36
|
+
def get_func_annotations(func):
|
|
37
|
+
"""
|
|
38
|
+
Given a function, return the annotations dictionary
|
|
39
|
+
|
|
40
|
+
:param func: function object
|
|
41
|
+
:return: dictionary of annotations
|
|
42
|
+
"""
|
|
43
|
+
# This method exists for use by prefab in getting annotations from
|
|
44
|
+
# the __prefab_post_init__ function
|
|
45
|
+
try:
|
|
46
|
+
annotations = func.__annotations__
|
|
47
|
+
except Exception:
|
|
48
|
+
if sys.version_info >= (3, 14):
|
|
49
|
+
annotations = _lazy_annotationlib.get_annotations(
|
|
50
|
+
func,
|
|
51
|
+
format=_lazy_annotationlib.Format.FORWARDREF,
|
|
52
|
+
)
|
|
53
|
+
else:
|
|
54
|
+
raise
|
|
55
|
+
|
|
56
|
+
return annotations
|
|
57
|
+
|
|
58
|
+
|
|
36
59
|
def get_ns_annotations(ns):
|
|
37
60
|
"""
|
|
38
61
|
Given a class namespace, attempt to retrieve the
|
|
@@ -3,6 +3,10 @@ import types
|
|
|
3
3
|
|
|
4
4
|
_CopiableMappings = dict[str, typing.Any] | types.MappingProxyType[str, typing.Any]
|
|
5
5
|
|
|
6
|
+
def get_func_annotations(
|
|
7
|
+
func: types.FunctionType,
|
|
8
|
+
) -> dict[str, typing.Any]: ...
|
|
9
|
+
|
|
6
10
|
def get_ns_annotations(
|
|
7
11
|
ns: _CopiableMappings,
|
|
8
12
|
) -> dict[str, typing.Any]: ...
|
ducktools/classbuilder/prefab.py
CHANGED
|
@@ -34,6 +34,8 @@ from . import (
|
|
|
34
34
|
get_repr_generator,
|
|
35
35
|
)
|
|
36
36
|
|
|
37
|
+
from .annotations import get_func_annotations
|
|
38
|
+
|
|
37
39
|
# These aren't used but are re-exported for ease of use
|
|
38
40
|
# noinspection PyUnresolvedReferences
|
|
39
41
|
from . import SlotFields, KW_ONLY # noqa: F401
|
|
@@ -98,7 +100,7 @@ def init_generator(cls, funcname="__init__"):
|
|
|
98
100
|
func_arglist.extend(arglist)
|
|
99
101
|
|
|
100
102
|
if extra_funcname == POST_INIT_FUNC:
|
|
101
|
-
post_init_annotations.update(func
|
|
103
|
+
post_init_annotations.update(get_func_annotations(func))
|
|
102
104
|
|
|
103
105
|
pos_arglist = []
|
|
104
106
|
kw_only_arglist = []
|
|
@@ -204,11 +206,11 @@ def init_generator(cls, funcname="__init__"):
|
|
|
204
206
|
post_init_call = ""
|
|
205
207
|
|
|
206
208
|
code = (
|
|
207
|
-
f"def {funcname}(self, {args}):\n"
|
|
209
|
+
f"def {funcname}(self, {args}) -> None:\n"
|
|
208
210
|
f"{pre_init_call}\n"
|
|
209
211
|
f"{body}\n"
|
|
210
212
|
f"{post_init_call}\n"
|
|
211
|
-
|
|
213
|
+
)
|
|
212
214
|
|
|
213
215
|
return GeneratedCode(code, globs)
|
|
214
216
|
|
|
@@ -13,6 +13,7 @@ from . import (
|
|
|
13
13
|
GeneratedCode,
|
|
14
14
|
MethodMaker,
|
|
15
15
|
SlotMakerMeta,
|
|
16
|
+
_SignatureMaker
|
|
16
17
|
)
|
|
17
18
|
|
|
18
19
|
from . import SlotFields as SlotFields, KW_ONLY as KW_ONLY
|
|
@@ -47,7 +48,7 @@ hash_maker: MethodMaker
|
|
|
47
48
|
|
|
48
49
|
class Attribute(Field):
|
|
49
50
|
__slots__: dict
|
|
50
|
-
__signature__:
|
|
51
|
+
__signature__: _SignatureMaker
|
|
51
52
|
__classbuilder_gathered_fields__: tuple[dict[str, Field], dict[str, typing.Any]]
|
|
52
53
|
|
|
53
54
|
iter: bool
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
ducktools/classbuilder/__init__.py,sha256=zJuGJ8_1EPEYJqO0XXDuknwGD1MxPJSZXS5_wFAW6B0,37299
|
|
2
|
+
ducktools/classbuilder/__init__.pyi,sha256=NazFRfLcMpU533jGixaWHV_kARtc9J4-xXX-gkD8rFY,8177
|
|
3
|
+
ducktools/classbuilder/_version.py,sha256=kdUPXlUQWcTv2wnqFkwrCx7Ue7WU2JVPnG1UU0gmLck,54
|
|
4
|
+
ducktools/classbuilder/annotations.py,sha256=ImEEuzEFUrGNRMlAl7YN-H8PZT1FOK8D_yL1LygNdmo,3626
|
|
5
|
+
ducktools/classbuilder/annotations.pyi,sha256=zAKJbEN1klvZu71ShuvKbf6OE7ddKb5USC6MbOjRPfY,336
|
|
6
|
+
ducktools/classbuilder/prefab.py,sha256=RJfOv9yzJsySaBz6w4e5ZP8Q7K3LWX6_Buuh2zD9YDQ,24689
|
|
7
|
+
ducktools/classbuilder/prefab.pyi,sha256=eZLjFhM-oHeRBONpCWSb1wLJKGs5Xiq0w_Jeor8Go-w,6525
|
|
8
|
+
ducktools/classbuilder/py.typed,sha256=la67KBlbjXN-_-DfGNcdOcjYumVpKG_Tkw-8n5dnGB4,8
|
|
9
|
+
ducktools_classbuilder-0.10.1.dist-info/licenses/LICENSE,sha256=6Thz9Dbw8R4fWInl6sGl8Rj3UnKnRbDwrc6jZerpugQ,1070
|
|
10
|
+
ducktools_classbuilder-0.10.1.dist-info/METADATA,sha256=LkjNjXyb49v3vYBEvbldkThl9xAgCHhVc8dPNgiMsxw,9231
|
|
11
|
+
ducktools_classbuilder-0.10.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
12
|
+
ducktools_classbuilder-0.10.1.dist-info/top_level.txt,sha256=uSDLtio3ZFqdwcsMJ2O5yhjB4Q3ytbBWbA8rJREganc,10
|
|
13
|
+
ducktools_classbuilder-0.10.1.dist-info/RECORD,,
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
ducktools/classbuilder/__init__.py,sha256=nZz_pQM6CN7yCT71oOclih4uls73a6SlW-HY2gxzYIs,37244
|
|
2
|
-
ducktools/classbuilder/__init__.pyi,sha256=v9QDO8A0AdPlAPNOXZGYXu1FaAq3yelwWNucdfWudrs,8143
|
|
3
|
-
ducktools/classbuilder/_version.py,sha256=MdjuHfU3W8hJQpD3kGrPvowqtRDz5JMifDCCjNbrskE,54
|
|
4
|
-
ducktools/classbuilder/annotations.py,sha256=GgBvNthDSRvKKZ9R_qxEVtCV3_vGuEBfuqQJFcDAe1s,3005
|
|
5
|
-
ducktools/classbuilder/annotations.pyi,sha256=c5vYtULdDgMYWtkzeYMsHIbmnEuT2Ru-nNZieWvYuQ4,247
|
|
6
|
-
ducktools/classbuilder/prefab.py,sha256=2GldQTRvOcFzB68qXbymeHKiXoyHx7eOjGxeilFIcn0,24632
|
|
7
|
-
ducktools/classbuilder/prefab.pyi,sha256=q5Zca5wAN80GE4uICY6v3EIB6LvIcjOEhzD1pVDK44U,6507
|
|
8
|
-
ducktools/classbuilder/py.typed,sha256=la67KBlbjXN-_-DfGNcdOcjYumVpKG_Tkw-8n5dnGB4,8
|
|
9
|
-
ducktools_classbuilder-0.10.0.dist-info/licenses/LICENSE,sha256=6Thz9Dbw8R4fWInl6sGl8Rj3UnKnRbDwrc6jZerpugQ,1070
|
|
10
|
-
ducktools_classbuilder-0.10.0.dist-info/METADATA,sha256=zrp9Q-klxkuTdsGSGz87rEZ7nxM8FCEppJfiGwqRh-0,9231
|
|
11
|
-
ducktools_classbuilder-0.10.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
12
|
-
ducktools_classbuilder-0.10.0.dist-info/top_level.txt,sha256=uSDLtio3ZFqdwcsMJ2O5yhjB4Q3ytbBWbA8rJREganc,10
|
|
13
|
-
ducktools_classbuilder-0.10.0.dist-info/RECORD,,
|
|
File without changes
|
{ducktools_classbuilder-0.10.0.dist-info → ducktools_classbuilder-0.10.1.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
{ducktools_classbuilder-0.10.0.dist-info → ducktools_classbuilder-0.10.1.dist-info}/top_level.txt
RENAMED
|
File without changes
|