ducktools-classbuilder 0.8.1__tar.gz → 0.8.2__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.

Potentially problematic release.


This version of ducktools-classbuilder might be problematic. Click here for more details.

Files changed (88) hide show
  1. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/PKG-INFO +1 -1
  2. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/docs/extension_examples.md +19 -0
  3. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/src/ducktools/classbuilder/__init__.py +15 -5
  4. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/src/ducktools/classbuilder/__init__.pyi +3 -0
  5. ducktools_classbuilder-0.8.2/src/ducktools/classbuilder/_version.py +2 -0
  6. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/src/ducktools/classbuilder/annotations.py +47 -10
  7. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/src/ducktools/classbuilder/prefab.py +6 -1
  8. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/src/ducktools/classbuilder/prefab.pyi +5 -2
  9. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/src/ducktools_classbuilder.egg-info/PKG-INFO +1 -1
  10. ducktools_classbuilder-0.8.1/src/ducktools/classbuilder/_version.py +0 -2
  11. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/.github/dependabot.yml +0 -0
  12. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/.github/workflows/auto_test.yml +0 -0
  13. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/.github/workflows/publish_to_pypi.yml +0 -0
  14. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/.github/workflows/publish_to_testpypi.yml +0 -0
  15. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/.gitignore +0 -0
  16. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/.readthedocs.yaml +0 -0
  17. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/LICENSE +0 -0
  18. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/MANIFEST.in +0 -0
  19. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/README.md +0 -0
  20. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/docs/Makefile +0 -0
  21. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/docs/api.md +0 -0
  22. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/docs/approach_vs_tool.md +0 -0
  23. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/docs/conf.py +0 -0
  24. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/docs/generated_code.md +0 -0
  25. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/docs/index.md +0 -0
  26. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/docs/make.bat +0 -0
  27. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/docs/perf/performance_tests.md +0 -0
  28. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/docs/prefab/index.md +0 -0
  29. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/docs/tutorial.md +0 -0
  30. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/docs_code/docs_ex10_frozen_attributes.py +0 -0
  31. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/docs_code/docs_ex1_basic.py +0 -0
  32. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/docs_code/docs_ex2_register.py +0 -0
  33. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/docs_code/docs_ex3_iterable.py +0 -0
  34. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/docs_code/docs_ex5_frozen.py +0 -0
  35. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/docs_code/docs_ex7_posonly.py +0 -0
  36. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/docs_code/docs_ex8_converters.py +0 -0
  37. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/docs_code/docs_ex9_annotated.py +0 -0
  38. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/docs_code/index_example.py +0 -0
  39. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/docs_code/tutorial_code.py +0 -0
  40. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/pyproject.toml +0 -0
  41. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/setup.cfg +0 -0
  42. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/src/ducktools/classbuilder/annotations.pyi +0 -0
  43. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/src/ducktools/classbuilder/py.typed +0 -0
  44. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/src/ducktools_classbuilder.egg-info/SOURCES.txt +0 -0
  45. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/src/ducktools_classbuilder.egg-info/dependency_links.txt +0 -0
  46. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/src/ducktools_classbuilder.egg-info/requires.txt +0 -0
  47. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/src/ducktools_classbuilder.egg-info/top_level.txt +0 -0
  48. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/annotations/test_annotated.py +0 -0
  49. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/annotations/test_annotations_module.py +0 -0
  50. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/annotations/test_future_annotations.py +0 -0
  51. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/conftest.py +0 -0
  52. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/prefab/dynamic/test_compare_attrib.py +0 -0
  53. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/prefab/dynamic/test_construction.py +0 -0
  54. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/prefab/dynamic/test_frozen.py +0 -0
  55. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/prefab/dynamic/test_internals.py +0 -0
  56. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/prefab/dynamic/test_pre_post_init.py +0 -0
  57. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/prefab/dynamic/test_private.py +0 -0
  58. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/prefab/dynamic/test_slots_novalues.py +0 -0
  59. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/prefab/dynamic/test_slotted_class.py +0 -0
  60. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/prefab/dynamic/test_subclass_implementation.py +0 -0
  61. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/prefab/shared/conftest.py +0 -0
  62. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/prefab/shared/examples/creation.py +0 -0
  63. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/prefab/shared/examples/creation_empty.py +0 -0
  64. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/prefab/shared/examples/dunders.py +0 -0
  65. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/prefab/shared/examples/fails/creation_2.py +0 -0
  66. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/prefab/shared/examples/fails/creation_3.py +0 -0
  67. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/prefab/shared/examples/fails/creation_5.py +0 -0
  68. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/prefab/shared/examples/fails/inheritance_1.py +0 -0
  69. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/prefab/shared/examples/fails/inheritance_2.py +0 -0
  70. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/prefab/shared/examples/funcs_prefabs.py +0 -0
  71. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/prefab/shared/examples/hint_syntax.py +0 -0
  72. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/prefab/shared/examples/inheritance.py +0 -0
  73. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/prefab/shared/examples/init_ex.py +0 -0
  74. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/prefab/shared/examples/kw_only.py +0 -0
  75. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/prefab/shared/examples/repr_func.py +0 -0
  76. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/prefab/shared/test_creation.py +0 -0
  77. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/prefab/shared/test_dunders.py +0 -0
  78. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/prefab/shared/test_funcs.py +0 -0
  79. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/prefab/shared/test_hint_syntax.py +0 -0
  80. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/prefab/shared/test_inheritance.py +0 -0
  81. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/prefab/shared/test_init.py +0 -0
  82. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/prefab/shared/test_kw_only.py +0 -0
  83. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/prefab/shared/test_repr.py +0 -0
  84. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/py312_tests/test_generic_annotations.py +0 -0
  85. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/py314_tests/test_forwardref_annotations.py +0 -0
  86. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/test_core.py +0 -0
  87. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/test_field_flags.py +0 -0
  88. {ducktools_classbuilder-0.8.1 → ducktools_classbuilder-0.8.2}/tests/test_slotmakermeta.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ducktools-classbuilder
3
- Version: 0.8.1
3
+ Version: 0.8.2
4
4
  Summary: Toolkit for creating class boilerplate generators
5
5
  Author: David C Ellis
6
6
  Project-URL: Homepage, https://github.com/davidcellis/ducktools-classbuilder
@@ -116,6 +116,25 @@ You could also choose to yield tuples of `name, value` pairs in your implementat
116
116
 
117
117
  ### Extending Field ###
118
118
 
119
+ The `Field` class can also be extended as if it is a slotclass, with annotations or
120
+ with `Field` declarations.
121
+
122
+ One notable caveat - if you want to use a `default_factory` in extending `Field` you
123
+ need to declare `default=FIELD_NOTHING` also in order for default to be ignored. This
124
+ is a special case for `Field` and is not needed in general.
125
+
126
+ ```python
127
+ from ducktools.classbuilder import Field, FIELD_NOTHING
128
+
129
+ class MetadataField(Field):
130
+ metadata: dict = Field(default=FIELD_NOTHING, default_factory=dict)
131
+ ```
132
+
133
+ In regular classes the `__init__` function generator considers `NOTHING` to be an
134
+ ignored value, but for `Field` subclasses it is a valid value so `FIELD_NOTHING` is
135
+ the ignored term. This is all because `None` *is* a valid value and can't be used
136
+ as a sentinel for Fields (otherwise `Field(default=None)` couldn't work).
137
+
119
138
  #### Positional Only Arguments? ####
120
139
 
121
140
  This is possible, but a little longer as we also need to modify multiple methods
@@ -99,11 +99,16 @@ def _get_inst_fields(inst):
99
99
  # As 'None' can be a meaningful value we need a sentinel value
100
100
  # to use to show no value has been provided.
101
101
  class _NothingType:
102
+ def __init__(self, custom=None):
103
+ self.custom = custom
102
104
  def __repr__(self):
105
+ if self.custom:
106
+ return f"<{self.custom} NOTHING OBJECT>"
103
107
  return "<NOTHING OBJECT>"
104
108
 
105
109
 
106
110
  NOTHING = _NothingType()
111
+ FIELD_NOTHING = _NothingType("FIELD")
107
112
 
108
113
 
109
114
  # KW_ONLY sentinel 'type' to use to indicate all subsequent attributes are
@@ -432,11 +437,11 @@ frozen_setattr_maker = MethodMaker("__setattr__", frozen_setattr_generator)
432
437
  frozen_delattr_maker = MethodMaker("__delattr__", frozen_delattr_generator)
433
438
  default_methods = frozenset({init_maker, repr_maker, eq_maker})
434
439
 
435
- # Special `__init__` maker for 'Field' subclasses
440
+ # Special `__init__` maker for 'Field' subclasses - needs its own NOTHING option
436
441
  _field_init_maker = MethodMaker(
437
442
  funcname="__init__",
438
443
  code_generator=get_init_generator(
439
- null=_NothingType(),
444
+ null=FIELD_NOTHING,
440
445
  extra_code=["self.validate_field()"],
441
446
  )
442
447
  )
@@ -649,7 +654,7 @@ class Field(metaclass=SlotMakerMeta):
649
654
 
650
655
  def validate_field(self):
651
656
  cls_name = self.__class__.__name__
652
- if self.default is not NOTHING and self.default_factory is not NOTHING:
657
+ if type(self.default) is not _NothingType and type(self.default_factory) is not _NothingType:
653
658
  raise AttributeError(
654
659
  f"{cls_name} cannot define both a default value and a default factory."
655
660
  )
@@ -807,6 +812,7 @@ def make_annotation_gatherer(
807
812
  def make_field_gatherer(
808
813
  field_type=Field,
809
814
  leave_default_values=False,
815
+ assign_types=True,
810
816
  ):
811
817
  def field_attribute_gatherer(cls_or_ns):
812
818
  if isinstance(cls_or_ns, (_MappingProxyType, dict)):
@@ -819,7 +825,11 @@ def make_field_gatherer(
819
825
  for k, v in cls_dict.items()
820
826
  if isinstance(v, field_type)
821
827
  }
822
- cls_annotations = get_ns_annotations(cls_dict)
828
+
829
+ if assign_types:
830
+ cls_annotations = get_ns_annotations(cls_dict)
831
+ else:
832
+ cls_annotations = {}
823
833
 
824
834
  cls_modifications = {}
825
835
 
@@ -830,7 +840,7 @@ def make_field_gatherer(
830
840
  else:
831
841
  cls_modifications[name] = NOTHING
832
842
 
833
- if (anno := cls_annotations.get(name, NOTHING)) is not NOTHING:
843
+ if assign_types and (anno := cls_annotations.get(name, NOTHING)) is not NOTHING:
834
844
  cls_attributes[name] = field_type.from_field(attrib, type=anno)
835
845
 
836
846
  return cls_attributes, cls_modifications
@@ -24,8 +24,10 @@ def get_methods(cls: type) -> types.MappingProxyType[str, MethodMaker]: ...
24
24
  def _get_inst_fields(inst: typing.Any) -> dict[str, typing.Any]: ...
25
25
 
26
26
  class _NothingType:
27
+ def __init__(self, custom: str | None = ...) -> None: ...
27
28
  def __repr__(self) -> str: ...
28
29
  NOTHING: _NothingType
30
+ FIELD_NOTHING: _NothingType
29
31
 
30
32
  # noinspection PyPep8Naming
31
33
  class _KW_ONLY_TYPE:
@@ -191,6 +193,7 @@ def make_annotation_gatherer(
191
193
  def make_field_gatherer(
192
194
  field_type: type[_FieldType],
193
195
  leave_default_values: bool = False,
196
+ assign_types: bool = True,
194
197
  ) -> Callable[[type | _CopiableMappings], tuple[dict[str, _FieldType], dict[str, typing.Any]]]: ...
195
198
 
196
199
  @typing.overload
@@ -0,0 +1,2 @@
1
+ __version__ = "0.8.2"
2
+ __version_tuple__ = (0, 8, 2)
@@ -22,6 +22,44 @@
22
22
  import sys
23
23
 
24
24
 
25
+ class _LazyAnnotationLib:
26
+ def __init__(self):
27
+ if sys.version_info < (3, 14):
28
+ self.annotationlib_unavailable = True
29
+ else:
30
+ self.annotationlib_unavailable = None
31
+
32
+ def __getattr__(self, item):
33
+ if self.annotationlib_unavailable:
34
+ raise ImportError("'annotationlib' is not available")
35
+
36
+ try:
37
+ import annotationlib
38
+ except ImportError:
39
+ self.annotationlib_unavailable = True
40
+ raise ImportError("'annotationlib' is not available")
41
+ else:
42
+ self.Format = annotationlib.Format
43
+ self.call_annotate_function = annotationlib.call_annotate_function
44
+
45
+ # This function keeps getting changed and renamed
46
+ get_ns_annotate = getattr(annotationlib, "get_annotate_from_class_namespace", None)
47
+ if get_ns_annotate is None:
48
+ get_ns_annotate = getattr(annotationlib, "get_annotate_function")
49
+ self.get_ns_annotate = get_ns_annotate
50
+
51
+ if item == "Format":
52
+ return self.Format
53
+ elif item == "call_annotate_function":
54
+ return self.call_annotate_function
55
+ elif item == "get_ns_annotate":
56
+ return get_ns_annotate
57
+
58
+ raise AttributeError(f"{item!r} is not available from this lazy importer")
59
+
60
+ _lazy_annotationlib = _LazyAnnotationLib()
61
+
62
+
25
63
  def get_ns_annotations(ns):
26
64
  """
27
65
  Given a class namespace, attempt to retrieve the
@@ -35,19 +73,18 @@ def get_ns_annotations(ns):
35
73
  if annotations is not None:
36
74
  annotations = annotations.copy()
37
75
  else:
38
- # See if we're using PEP-649 annotations
39
- # Guarding this with a try/except instead of a version check
40
- # In case there's a change and PEP-649 somehow doesn't make 3.14
41
76
  try:
42
- from annotationlib import Format, call_annotate_function, get_annotate_function
43
- except ImportError:
44
- pass
45
- else:
46
- annotate = ns.get("__annotate__") # Works in the alphas, but may break
77
+ # See if we're using PEP-649 annotations
78
+ annotate = ns.get("__annotate__") # Works in the early alphas
47
79
  if not annotate:
48
- annotate = get_annotate_function(ns)
80
+ annotate = _lazy_annotationlib.get_ns_annotate(ns)
49
81
  if annotate:
50
- annotations = call_annotate_function(annotate, format=Format.FORWARDREF)
82
+ annotations = _lazy_annotationlib.call_annotate_function(
83
+ annotate,
84
+ format=_lazy_annotationlib.Format.FORWARDREF
85
+ )
86
+ except ImportError:
87
+ pass
51
88
 
52
89
  if annotations is None:
53
90
  annotations = {}
@@ -26,7 +26,7 @@ A 'prebuilt' implementation of class generation.
26
26
  Includes pre and post init functions along with other methods.
27
27
  """
28
28
  from . import (
29
- INTERNALS_DICT, NOTHING,
29
+ INTERNALS_DICT, NOTHING, FIELD_NOTHING,
30
30
  Field, MethodMaker, GatheredFields, GeneratedCode, SlotMakerMeta,
31
31
  builder, get_flags, get_fields,
32
32
  make_unified_gatherer,
@@ -289,10 +289,12 @@ class Attribute(Field):
289
289
  :param kw_only: Make this argument keyword only in init
290
290
  :param serialize: Include this attribute in methods that serialize to dict
291
291
  :param doc: Parameter documentation for slotted classes
292
+ :param metadata: Additional non-construction related metadata
292
293
  :param type: Type of this attribute (for slotted classes)
293
294
  """
294
295
  iter: bool = True
295
296
  serialize: bool = True
297
+ metadata: dict = Field(default=FIELD_NOTHING, default_factory=dict)
296
298
 
297
299
 
298
300
  # noinspection PyShadowingBuiltins
@@ -309,6 +311,7 @@ def attribute(
309
311
  exclude_field=False,
310
312
  private=False,
311
313
  doc=None,
314
+ metadata=None,
312
315
  type=NOTHING,
313
316
  ):
314
317
  """
@@ -326,6 +329,7 @@ def attribute(
326
329
  :param exclude_field: Shorthand for setting repr, compare, iter and serialize to False
327
330
  :param private: Short for init, repr, compare, iter, serialize = False, must have default or factory
328
331
  :param doc: Parameter documentation for slotted classes
332
+ :param metadata: Dictionary for additional non-construction metadata
329
333
  :param type: Type of this attribute (for slotted classes)
330
334
 
331
335
  :return: Attribute generated with these parameters.
@@ -356,6 +360,7 @@ def attribute(
356
360
  serialize=serialize,
357
361
  doc=doc,
358
362
  type=type,
363
+ metadata=metadata,
359
364
  )
360
365
 
361
366
 
@@ -50,6 +50,7 @@ class Attribute(Field):
50
50
 
51
51
  iter: bool
52
52
  serialize: bool
53
+ metadata: dict
53
54
 
54
55
  def __init__(
55
56
  self,
@@ -64,6 +65,7 @@ class Attribute(Field):
64
65
  iter: bool = True,
65
66
  kw_only: bool = False,
66
67
  serialize: bool = True,
68
+ metadata: dict | None = None,
67
69
  ) -> None: ...
68
70
 
69
71
  def __repr__(self) -> str: ...
@@ -74,8 +76,6 @@ def attribute(
74
76
  *,
75
77
  default: typing.Any | _NothingType = NOTHING,
76
78
  default_factory: typing.Any | _NothingType = NOTHING,
77
- type: type | _NothingType = NOTHING,
78
- doc: str | None = None,
79
79
  init: bool = True,
80
80
  repr: bool = True,
81
81
  compare: bool = True,
@@ -84,6 +84,9 @@ def attribute(
84
84
  serialize: bool = True,
85
85
  exclude_field: bool = False,
86
86
  private: bool = False,
87
+ doc: str | None = None,
88
+ metadata: dict | None = None,
89
+ type: type | _NothingType = NOTHING,
87
90
  ) -> Attribute: ...
88
91
 
89
92
  def prefab_gatherer(cls_or_ns: type | MappingProxyType) -> tuple[dict[str, Attribute], dict[str, typing.Any]]: ...
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ducktools-classbuilder
3
- Version: 0.8.1
3
+ Version: 0.8.2
4
4
  Summary: Toolkit for creating class boilerplate generators
5
5
  Author: David C Ellis
6
6
  Project-URL: Homepage, https://github.com/davidcellis/ducktools-classbuilder
@@ -1,2 +0,0 @@
1
- __version__ = "0.8.1"
2
- __version_tuple__ = (0, 8, 1)