classcore 1.4.2__tar.gz → 1.5.1__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.
Files changed (24) hide show
  1. {classcore-1.4.2 → classcore-1.5.1}/PKG-INFO +1 -1
  2. {classcore-1.4.2 → classcore-1.5.1}/sources/classcore/__/doctab.py +0 -6
  3. {classcore-1.4.2 → classcore-1.5.1}/sources/classcore/__/imports.py +1 -1
  4. {classcore-1.4.2 → classcore-1.5.1}/sources/classcore/__init__.py +2 -2
  5. {classcore-1.4.2 → classcore-1.5.1}/sources/classcore/factories.py +3 -3
  6. {classcore-1.4.2 → classcore-1.5.1}/sources/classcore/nomina.py +68 -39
  7. {classcore-1.4.2 → classcore-1.5.1}/sources/classcore/standard/behaviors.py +40 -10
  8. {classcore-1.4.2 → classcore-1.5.1}/sources/classcore/standard/decorators.py +118 -56
  9. {classcore-1.4.2 → classcore-1.5.1}/sources/classcore/standard/dynadoc.py +20 -20
  10. {classcore-1.4.2 → classcore-1.5.1}/sources/classcore/standard/modules.py +4 -4
  11. {classcore-1.4.2 → classcore-1.5.1}/sources/classcore/standard/nomina.py +17 -9
  12. {classcore-1.4.2 → classcore-1.5.1}/sources/classcore/utilities.py +3 -0
  13. {classcore-1.4.2 → classcore-1.5.1}/.gitignore +0 -0
  14. {classcore-1.4.2 → classcore-1.5.1}/LICENSE.txt +0 -0
  15. {classcore-1.4.2 → classcore-1.5.1}/README.rst +0 -0
  16. {classcore-1.4.2 → classcore-1.5.1}/pyproject.toml +0 -0
  17. {classcore-1.4.2 → classcore-1.5.1}/sources/classcore/__/__init__.py +0 -0
  18. {classcore-1.4.2 → classcore-1.5.1}/sources/classcore/__/nomina.py +0 -0
  19. {classcore-1.4.2 → classcore-1.5.1}/sources/classcore/decorators.py +0 -0
  20. {classcore-1.4.2 → classcore-1.5.1}/sources/classcore/exceptions.py +0 -0
  21. {classcore-1.4.2 → classcore-1.5.1}/sources/classcore/py.typed +0 -0
  22. {classcore-1.4.2 → classcore-1.5.1}/sources/classcore/standard/__.py +0 -0
  23. {classcore-1.4.2 → classcore-1.5.1}/sources/classcore/standard/__init__.py +0 -0
  24. {classcore-1.4.2 → classcore-1.5.1}/sources/classcore/standard/classes.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: classcore
3
- Version: 1.4.2
3
+ Version: 1.5.1
4
4
  Summary: Foundational class factories and decorators.
5
5
  Project-URL: Homepage, https://github.com/emcd/python-classcore
6
6
  Project-URL: Documentation, https://emcd.github.io/python-classcore
@@ -67,10 +67,4 @@ fragments: _FragmentsTable = __.types.MappingProxyType( {
67
67
 
68
68
  'class dynadoc': ''' Is decorated by Dynadoc. ''',
69
69
 
70
- 'decorators':
71
- ''' Sequence of class decorators.
72
-
73
- Each element takes a class argument and returns a class.
74
- ''',
75
-
76
70
  } )
@@ -33,7 +33,7 @@ import re
33
33
  import sys
34
34
  import types
35
35
 
36
- import dynadoc
36
+ import dynadoc as ddoc
37
37
  import typing_extensions as typx
38
38
  # --- BEGIN: Injected by Copier ---
39
39
  # --- END: Injected by Copier ---
@@ -61,8 +61,8 @@ from .decorators import *
61
61
  from .factories import *
62
62
 
63
63
 
64
- __version__: __.typx.Annotated[ str, __.dynadoc.Visibilities.Reveal ]
65
- __version__ = '1.4.2'
64
+ __version__: __.typx.Annotated[ str, __.ddoc.Visibilities.Reveal ]
65
+ __version__ = '1.5.1'
66
66
 
67
67
 
68
68
  standard.dynadoc.assign_module_docstring( __name__, table = __.fragments )
@@ -29,8 +29,8 @@ from . import utilities as _utilities
29
29
 
30
30
  def produce_class_constructor(
31
31
  attributes_namer: _nomina.AttributesNamer,
32
- preprocessors: _nomina.ProduceConstructorPreprocsArgument[ __.T ] = ( ),
33
- postprocessors: _nomina.ProduceConstructorPostprocsArgument[ __.T ] = ( ),
32
+ preprocessors: _nomina.ClassConstructionPreprocessors[ __.T ] = ( ),
33
+ postprocessors: _nomina.ClassConstructionPostprocessors[ __.T ] = ( ),
34
34
  ) -> _nomina.ClassConstructor[ __.T ]:
35
35
  ''' Produces constructors for classes. '''
36
36
 
@@ -68,7 +68,7 @@ def produce_class_constructor(
68
68
 
69
69
  def produce_class_initializer(
70
70
  attributes_namer: _nomina.AttributesNamer,
71
- completers: _nomina.ProduceInitializerCompletersArgument = ( ),
71
+ completers: _nomina.ClassInitializationCompleters = ( ),
72
72
  ) -> _nomina.ClassInitializer:
73
73
  ''' Produces initializers for classes. '''
74
74
 
@@ -24,36 +24,68 @@
24
24
  from . import __
25
25
 
26
26
 
27
- AttributesNamer: __.typx.TypeAlias = __.cabc.Callable[ [ str, str ], str ]
27
+ AttributesNamer: __.typx.TypeAlias = __.typx.Annotated[
28
+ __.cabc.Callable[ [ str, str ], str ],
29
+ __.ddoc.Doc(
30
+ ''' Names attribute from level and core arguments.
31
+
32
+ Level will be one of 'class', 'instances', or 'instance'.
33
+ Core will be the core of the name as supplied this package.
34
+
35
+ Can be used by downstream packages to determine names of
36
+ bookkeeping attributes assigned by this package.
37
+ ''' ),
38
+ ]
28
39
 
29
40
  Decorator: __.typx.TypeAlias = __.typx.Annotated[
30
41
  __.cabc.Callable[ [ type[ __.U ] ], type[ __.U ] ],
31
- __.dynadoc.Doc(
42
+ __.ddoc.Doc(
32
43
  ''' Class decorator.
33
44
 
34
45
  Takes class argument and returns class.
35
46
  ''' ),
36
47
  ]
37
48
  Decorators: __.typx.TypeAlias = __.typx.Annotated[
38
- __.cabc.Sequence[ Decorator[ __.U ] ], __.dynadoc.Fname( 'decorators' )
49
+ __.cabc.Sequence[ Decorator[ __.U ] ],
50
+ __.ddoc.Doc(
51
+ ''' Sequence of class decorators.
52
+
53
+ Each element takes a class argument and returns a class.
54
+ ''' ),
39
55
  ]
40
56
  DecoratorsMutable: __.typx.TypeAlias = __.typx.Annotated[
41
57
  __.cabc.MutableSequence[ Decorator[ __.U ] ],
42
- __.dynadoc.Fname( 'decorators' ),
43
- __.dynadoc.Doc(
44
- ''' Decorators may be inserted or removed from sequence. ''' ),
58
+ __.ddoc.Doc(
59
+ ''' Sequence of class decorators.
60
+
61
+ Each element takes a class argument and returns a class.
62
+
63
+ Decorators may be inserted or removed from sequence.
64
+ ''' ),
45
65
  ]
46
66
 
47
- DecorationPreparer: __.typx.TypeAlias = (
48
- __.cabc.Callable[ [ type[ __.U ], DecoratorsMutable[ __.U ] ], None ] )
49
- DecorationPreparers: __.typx.TypeAlias = (
50
- __.cabc.Sequence[ DecorationPreparer[ __.U ] ] )
51
- DecorationPreparersFactory: __.typx.TypeAlias = (
52
- __.cabc.Callable[ [ ], DecorationPreparers[ __.U ] ] )
67
+ DecorationPreparer: __.typx.TypeAlias = __.typx.Annotated[
68
+ __.cabc.Callable[ [ type[ __.U ], DecoratorsMutable[ __.U ] ], None ],
69
+ __.ddoc.Doc(
70
+ ''' Class decoration preparer.
71
+
72
+ Takes class and mutable sequence of decorators as arguments.
73
+ Can alter the sequence.
74
+ ''' ),
75
+ ]
76
+ DecorationPreparers: __.typx.TypeAlias = __.typx.Annotated[
77
+ __.cabc.Sequence[ DecorationPreparer[ __.U ] ],
78
+ __.ddoc.Doc(
79
+ ''' Sequence of class decoration preparers.
80
+
81
+ Each element takes class and mutable sequence of decorators as
82
+ arguments. And, each element can alter the sequence.
83
+ ''' ),
84
+ ]
53
85
 
54
86
  ClassConstructorLigation: __.typx.TypeAlias = __.typx.Annotated[
55
87
  __.cabc.Callable[ ..., type ],
56
- __.dynadoc.Doc(
88
+ __.ddoc.Doc(
57
89
  ''' Bound class constructor function.
58
90
 
59
91
  Usually from ``super( ).__new__`` or a partial function.
@@ -61,7 +93,7 @@ ClassConstructorLigation: __.typx.TypeAlias = __.typx.Annotated[
61
93
  ]
62
94
  InitializerLigation: __.typx.TypeAlias = __.typx.Annotated[
63
95
  __.cabc.Callable[ ..., None ],
64
- __.dynadoc.Doc(
96
+ __.ddoc.Doc(
65
97
  ''' Bound initializer function.
66
98
 
67
99
  Usually from ``super( ).__init__`` or a partial function.
@@ -69,7 +101,7 @@ InitializerLigation: __.typx.TypeAlias = __.typx.Annotated[
69
101
  ]
70
102
  AssignerLigation: __.typx.TypeAlias = __.typx.Annotated[
71
103
  __.cabc.Callable[ [ str, __.typx.Any ], None ],
72
- __.dynadoc.Doc(
104
+ __.ddoc.Doc(
73
105
  ''' Bound attributes assigner function.
74
106
 
75
107
  Usually from ``super( ).__setattr__`` or a partial function.
@@ -77,7 +109,7 @@ AssignerLigation: __.typx.TypeAlias = __.typx.Annotated[
77
109
  ]
78
110
  DeleterLigation: __.typx.TypeAlias = __.typx.Annotated[
79
111
  __.cabc.Callable[ [ str ], None ],
80
- __.dynadoc.Doc(
112
+ __.ddoc.Doc(
81
113
  ''' Bound attributes deleter function.
82
114
 
83
115
  Usually from ``super( ).__delattr__`` or a partial function.
@@ -85,7 +117,7 @@ DeleterLigation: __.typx.TypeAlias = __.typx.Annotated[
85
117
  ]
86
118
  SurveyorLigation: __.typx.TypeAlias = __.typx.Annotated[
87
119
  __.cabc.Callable[ [ ], __.cabc.Iterable[ str ] ],
88
- __.dynadoc.Doc(
120
+ __.ddoc.Doc(
89
121
  ''' Bound attributes surveyor function.
90
122
 
91
123
  Usually from ``super( ).__dir__`` or a partial function.
@@ -105,30 +137,44 @@ ClassConstructionPreprocessor: __.typx.TypeAlias = __.typx.Annotated[
105
137
  ],
106
138
  None
107
139
  ],
108
- __.dynadoc.Doc(
140
+ __.ddoc.Doc(
109
141
  ''' Processes class data before construction.
110
142
 
111
143
  For use cases, such as argument conversion.
112
144
  ''' ),
113
145
  ]
146
+ ClassConstructionPreprocessors: __.typx.TypeAlias = __.typx.Annotated[
147
+ __.cabc.Sequence[ ClassConstructionPreprocessor[ __.U ] ],
148
+ __.ddoc.Doc( ''' Processors to apply before construction of class. ''' ),
149
+ ]
114
150
  ClassConstructionPostprocessor: __.typx.TypeAlias = __.typx.Annotated[
115
151
  __.cabc.Callable[ [ type, DecoratorsMutable[ __.U ] ], None ],
116
- __.dynadoc.Doc(
152
+ __.ddoc.Doc(
117
153
  ''' Processes class before decoration.
118
154
 
119
155
  For use cases, such as decorator list manipulation.
120
156
  ''' ),
121
157
  ]
158
+ ClassConstructionPostprocessors: __.typx.TypeAlias = __.typx.Annotated[
159
+ __.cabc.Sequence[ ClassConstructionPostprocessor[ __.U ] ],
160
+ __.ddoc.Doc(
161
+ ''' Processors to apply before decoration of class. ''' ),
162
+ ]
122
163
  # TODO: ClassInitializationPreparer (arguments mutation)
123
164
  ClassInitializationCompleter: __.typx.TypeAlias = __.typx.Annotated[
124
165
  __.cabc.Callable[ [ type ], None ],
125
- __.dynadoc.Doc(
166
+ __.ddoc.Doc(
126
167
  ''' Completes initialization of class.
127
168
 
128
169
  For use cases, such as enabling immutability once all other
129
170
  initialization has occurred.
130
171
  ''' ),
131
172
  ]
173
+ ClassInitializationCompleters: __.typx.TypeAlias = __.typx.Annotated[
174
+ __.cabc.Sequence[ ClassInitializationCompleter ],
175
+ __.ddoc.Doc(
176
+ ''' Processors to apply at final stage of class initialization. ''' ),
177
+ ]
132
178
 
133
179
 
134
180
  ClassConstructor: __.typx.TypeAlias = __.typx.Annotated[
@@ -144,7 +190,7 @@ ClassConstructor: __.typx.TypeAlias = __.typx.Annotated[
144
190
  ],
145
191
  type
146
192
  ],
147
- __.dynadoc.Doc( ''' Constructor to use with metaclass. ''' ),
193
+ __.ddoc.Doc( ''' Constructor to use with metaclass. ''' ),
148
194
  ]
149
195
  ClassInitializer: __.typx.TypeAlias = __.typx.Annotated[
150
196
  __.cabc.Callable[
@@ -156,22 +202,5 @@ ClassInitializer: __.typx.TypeAlias = __.typx.Annotated[
156
202
  ],
157
203
  None
158
204
  ],
159
- __.dynadoc.Doc( ''' Initializer to use with metaclass. ''' ),
160
- ]
161
-
162
-
163
- ProduceConstructorPreprocsArgument: __.typx.TypeAlias = __.typx.Annotated[
164
- __.cabc.Sequence[ ClassConstructionPreprocessor[ __.U ] ],
165
- __.dynadoc.Doc(
166
- ''' Processors to apply before construction of class. ''' ),
167
- ]
168
- ProduceConstructorPostprocsArgument: __.typx.TypeAlias = __.typx.Annotated[
169
- __.cabc.Sequence[ ClassConstructionPostprocessor[ __.U ] ],
170
- __.dynadoc.Doc(
171
- ''' Processors to apply before decoration of class. ''' ),
172
- ]
173
- ProduceInitializerCompletersArgument: __.typx.TypeAlias = __.typx.Annotated[
174
- __.cabc.Sequence[ ClassInitializationCompleter ],
175
- __.dynadoc.Doc(
176
- ''' Processors to apply at final stage of class initialization. ''' ),
205
+ __.ddoc.Doc( ''' Initializer to use with metaclass. ''' ),
177
206
  ]
@@ -28,6 +28,26 @@ from . import __
28
28
  from . import nomina as _nomina
29
29
 
30
30
 
31
+ def access_core_function( # noqa: PLR0913
32
+ cls: type, /, *,
33
+ attributes_namer: _nomina.AttributesNamer,
34
+ arguments: __.cabc.Mapping[ str, __.typx.Any ],
35
+ level: str,
36
+ name: str,
37
+ default: __.cabc.Callable[ ..., __.typx.Any ],
38
+ ) -> __.cabc.Callable[ ..., __.typx.Any ]:
39
+ ''' Accesses core behavior function.
40
+
41
+ First checks for override argument, then checks for heritable
42
+ attribute. Finally, falls back to provided default.
43
+ '''
44
+ argument_name = f"{level}_{name}_core"
45
+ attribute_name = attributes_namer( level, f"{name}_core" )
46
+ return (
47
+ arguments.get( argument_name )
48
+ or getattr( cls, attribute_name, default ) )
49
+
50
+
31
51
  def assign_attribute_if_mutable( # noqa: PLR0913
32
52
  obj: object, /, *,
33
53
  ligation: _nomina.AssignerLigation,
@@ -225,6 +245,10 @@ def produce_class_construction_postprocessor(
225
245
  ) -> _nomina.ClassConstructionPostprocessor[ __.U ]:
226
246
  ''' Produces construction processor which determines class decorators. '''
227
247
  arguments_name = attributes_namer( 'class', 'construction_arguments' )
248
+ cores_default = dict(
249
+ assigner = assign_attribute_if_mutable,
250
+ deleter = delete_attribute_if_mutable,
251
+ surveyor = survey_visible_attributes )
228
252
 
229
253
  def postprocess(
230
254
  cls: type, decorators: _nomina.DecoratorsMutable[ __.U ]
@@ -236,16 +260,19 @@ def produce_class_construction_postprocessor(
236
260
  dynadoc_cfg_name = (
237
261
  attributes_namer( 'classes', 'dynadoc_configuration' ) )
238
262
  dynadoc_cfg = getattr( clscls, dynadoc_cfg_name, { } )
239
- decorators.append( __.dynadoc.with_docstring( **dynadoc_cfg ) )
263
+ decorators.append( __.ddoc.with_docstring( **dynadoc_cfg ) )
240
264
  dcls_spec = getattr( cls, '__dataclass_transform__', None )
241
265
  if not dcls_spec: # either base class or metaclass may be marked
242
266
  dcls_spec = getattr( clscls, '__dataclass_transform__', None )
243
- instances_assigner = arguments.get(
244
- 'instances_assigner_core', assign_attribute_if_mutable )
245
- instances_deleter = arguments.get(
246
- 'instances_deleter_core', delete_attribute_if_mutable )
247
- instances_surveyor = arguments.get(
248
- 'instances_surveyor_core', survey_visible_attributes )
267
+ cores = { }
268
+ for core_name in ( 'assigner', 'deleter', 'surveyor' ):
269
+ core_function = access_core_function(
270
+ cls,
271
+ attributes_namer = attributes_namer,
272
+ arguments = arguments,
273
+ level = 'instances', name = core_name,
274
+ default = cores_default[ core_name ] )
275
+ cores[ core_name ] = core_function
249
276
  instances_mutables = arguments.get(
250
277
  'instances_mutables', __.mutables_default )
251
278
  instances_visibles = arguments.get(
@@ -261,9 +288,12 @@ def produce_class_construction_postprocessor(
261
288
  decorator: _nomina.Decorator[ __.U ] = decorator_factory(
262
289
  attributes_namer = attributes_namer,
263
290
  error_class_provider = error_class_provider,
264
- assigner_core = instances_assigner,
265
- deleter_core = instances_deleter,
266
- surveyor_core = instances_surveyor,
291
+ assigner_core = __.typx.cast(
292
+ _nomina.AssignerCore, cores[ 'assigner' ] ),
293
+ deleter_core = __.typx.cast(
294
+ _nomina.DeleterCore, cores[ 'deleter' ] ),
295
+ surveyor_core = __.typx.cast(
296
+ _nomina.SurveyorCore, cores[ 'surveyor' ] ),
267
297
  mutables = instances_mutables,
268
298
  visibles = instances_visibles )
269
299
  decorators.append( decorator )
@@ -21,8 +21,6 @@
21
21
  ''' Standard decorators. '''
22
22
  # TODO? Add attribute value transformer as standard decorator argument.
23
23
 
24
- # ruff: noqa: F401
25
-
26
24
 
27
25
  from .. import factories as _factories
28
26
  from .. import utilities as _utilities
@@ -56,6 +54,33 @@ def prepare_dataclass_for_instances(
56
54
  setattr( cls, behaviors_name_m, __.dcls.field( init = False ) )
57
55
 
58
56
 
57
+ def apply_cfc_core_functions(
58
+ clscls: type[ __.T ], /,
59
+ attributes_namer: _nomina.AttributesNamer,
60
+ assigner_core: __.typx.Optional[ _nomina.AssignerCore ] = None,
61
+ deleter_core: __.typx.Optional[ _nomina.DeleterCore ] = None,
62
+ surveyor_core: __.typx.Optional[ _nomina.SurveyorCore ] = None,
63
+ ) -> None:
64
+ ''' Stores core functions on metaclass. '''
65
+ cores = dict(
66
+ classes_assigner_core = assigner_core,
67
+ classes_deleter_core = deleter_core,
68
+ classes_surveyor_core = surveyor_core )
69
+ cores_default = dict(
70
+ assigner = _behaviors.assign_attribute_if_mutable,
71
+ deleter = _behaviors.delete_attribute_if_mutable,
72
+ surveyor = _behaviors.survey_visible_attributes )
73
+ for core_name in ( 'assigner', 'deleter', 'surveyor' ):
74
+ core_function = _behaviors.access_core_function(
75
+ clscls,
76
+ attributes_namer = attributes_namer,
77
+ arguments = cores,
78
+ level = 'classes', name = core_name,
79
+ default = cores_default[ core_name ] )
80
+ core_aname = attributes_namer( 'classes', f"{core_name}_core" )
81
+ setattr( clscls, core_aname, core_function )
82
+
83
+
59
84
  def apply_cfc_dynadoc_configuration(
60
85
  clscls: type[ __.T ], /,
61
86
  attributes_namer: _nomina.AttributesNamer,
@@ -109,7 +134,7 @@ def apply_cfc_attributes_assigner(
109
134
  clscls: type[ __.T ], /,
110
135
  attributes_namer: _nomina.AttributesNamer,
111
136
  error_class_provider: _nomina.ErrorClassProvider,
112
- implementation_core: _nomina.AssignerCore,
137
+ implementation_core: __.typx.Optional[ _nomina.AssignerCore ],
113
138
  ) -> None:
114
139
  ''' Injects '__setattr__' method into metaclass. '''
115
140
  decorator = produce_attributes_assignment_decorator(
@@ -124,7 +149,7 @@ def apply_cfc_attributes_deleter(
124
149
  clscls: type[ __.T ], /,
125
150
  attributes_namer: _nomina.AttributesNamer,
126
151
  error_class_provider: _nomina.ErrorClassProvider,
127
- implementation_core: _nomina.DeleterCore,
152
+ implementation_core: __.typx.Optional[ _nomina.DeleterCore ],
128
153
  ) -> None:
129
154
  ''' Injects '__delattr__' method into metaclass. '''
130
155
  decorator = produce_attributes_deletion_decorator(
@@ -138,7 +163,7 @@ def apply_cfc_attributes_deleter(
138
163
  def apply_cfc_attributes_surveyor(
139
164
  clscls: type[ __.T ],
140
165
  attributes_namer: _nomina.AttributesNamer,
141
- implementation_core: _nomina.SurveyorCore,
166
+ implementation_core: __.typx.Optional[ _nomina.SurveyorCore ],
142
167
  ) -> None:
143
168
  ''' Injects '__dir__' method into metaclass. '''
144
169
  decorator = produce_attributes_surveillance_decorator(
@@ -151,17 +176,20 @@ def apply_cfc_attributes_surveyor(
151
176
  def class_factory( # noqa: PLR0913
152
177
  attributes_namer: _nomina.AttributesNamer = __.calculate_attrname,
153
178
  error_class_provider: _nomina.ErrorClassProvider = __.provide_error_class,
154
- assigner_core: _nomina.AssignerCore = (
155
- _behaviors.assign_attribute_if_mutable ),
156
- deleter_core: _nomina.DeleterCore = (
157
- _behaviors.delete_attribute_if_mutable ),
158
- surveyor_core: _nomina.SurveyorCore = (
159
- _behaviors.survey_visible_attributes ),
179
+ assigner_core: __.typx.Optional[ _nomina.AssignerCore ] = None,
180
+ deleter_core: __.typx.Optional[ _nomina.DeleterCore ] = None,
181
+ surveyor_core: __.typx.Optional[ _nomina.SurveyorCore ] = None,
160
182
  dynadoc_configuration: __.cabc.Mapping[ str, __.typx.Any ] = (
161
183
  _dynadoc_configuration ),
162
184
  ) -> _nomina.Decorator[ __.T ]:
163
185
  ''' Produces decorator to apply standard behaviors to metaclass. '''
164
186
  def decorate( clscls: type[ __.T ] ) -> type[ __.T ]:
187
+ apply_cfc_core_functions(
188
+ clscls,
189
+ attributes_namer = attributes_namer,
190
+ assigner_core = assigner_core,
191
+ deleter_core = deleter_core,
192
+ surveyor_core = surveyor_core )
165
193
  apply_cfc_dynadoc_configuration(
166
194
  clscls,
167
195
  attributes_namer = attributes_namer,
@@ -190,13 +218,34 @@ def class_factory( # noqa: PLR0913
190
218
  return decorate
191
219
 
192
220
 
193
- def produce_instances_initialization_decorator(
221
+ def produce_instances_initialization_decorator( # noqa: PLR0913
194
222
  attributes_namer: _nomina.AttributesNamer,
223
+ assigner_core: __.typx.Optional[ _nomina.AssignerCore ],
224
+ deleter_core: __.typx.Optional[ _nomina.DeleterCore ],
225
+ surveyor_core: __.typx.Optional[ _nomina.SurveyorCore ],
195
226
  mutables: _nomina.BehaviorExclusionVerifiersOmni,
196
227
  visibles: _nomina.BehaviorExclusionVerifiersOmni,
197
228
  ) -> _nomina.Decorator[ __.U ]:
198
229
  ''' Produces decorator to inject '__init__' method into class. '''
230
+ cores = dict(
231
+ instances_assigner_core = assigner_core,
232
+ instances_deleter_core = deleter_core,
233
+ instances_surveyor_core = surveyor_core )
234
+ cores_default = dict(
235
+ assigner = _behaviors.assign_attribute_if_mutable,
236
+ deleter = _behaviors.delete_attribute_if_mutable,
237
+ surveyor = _behaviors.survey_visible_attributes )
238
+
199
239
  def decorate( cls: type[ __.U ] ) -> type[ __.U ]:
240
+ for core_name in ( 'assigner', 'deleter', 'surveyor' ):
241
+ core_function = _behaviors.access_core_function(
242
+ cls,
243
+ attributes_namer = attributes_namer,
244
+ arguments = cores,
245
+ level = 'instances', name = core_name,
246
+ default = cores_default[ core_name ] )
247
+ core_aname = attributes_namer( 'instances', f"{core_name}_core" )
248
+ setattr( cls, core_aname, core_function )
200
249
  behaviors: set[ str ] = set( )
201
250
  behaviors_name = attributes_namer( 'instance', 'behaviors' )
202
251
  _behaviors.record_behavior(
@@ -253,12 +302,18 @@ def produce_attributes_assignment_decorator(
253
302
  level: str,
254
303
  attributes_namer: _nomina.AttributesNamer,
255
304
  error_class_provider: _nomina.ErrorClassProvider,
256
- implementation_core: _nomina.AssignerCore,
305
+ implementation_core: __.typx.Optional[ _nomina.AssignerCore ],
257
306
  ) -> _nomina.Decorator[ __.U ]:
258
307
  ''' Produces decorator to inject '__setattr__' method into class. '''
259
308
  def decorate( cls: type[ __.U ] ) -> type[ __.U ]:
260
309
  leveli = 'class' if level == 'classes' else level
261
310
  original = cls.__dict__.get( '__setattr__' )
311
+ core = _behaviors.access_core_function(
312
+ cls,
313
+ attributes_namer = attributes_namer,
314
+ arguments = { f"{level}_assigner": implementation_core },
315
+ level = level, name = 'assigner',
316
+ default = _behaviors.assign_attribute_if_mutable )
262
317
 
263
318
  if original is None:
264
319
 
@@ -270,7 +325,7 @@ def produce_attributes_assignment_decorator(
270
325
  if cls is not type( self ):
271
326
  ligation( name, value )
272
327
  return
273
- implementation_core(
328
+ core(
274
329
  self,
275
330
  ligation = ligation,
276
331
  attributes_namer = attributes_namer,
@@ -291,7 +346,7 @@ def produce_attributes_assignment_decorator(
291
346
  if cls is not type( self ):
292
347
  ligation( name, value )
293
348
  return
294
- implementation_core(
349
+ core(
295
350
  self,
296
351
  ligation = ligation,
297
352
  attributes_namer = attributes_namer,
@@ -310,12 +365,18 @@ def produce_attributes_deletion_decorator(
310
365
  level: str,
311
366
  attributes_namer: _nomina.AttributesNamer,
312
367
  error_class_provider: _nomina.ErrorClassProvider,
313
- implementation_core: _nomina.DeleterCore,
368
+ implementation_core: __.typx.Optional[ _nomina.DeleterCore ],
314
369
  ) -> _nomina.Decorator[ __.U ]:
315
370
  ''' Produces decorator to inject '__delattr__' method into class. '''
316
371
  def decorate( cls: type[ __.U ] ) -> type[ __.U ]:
317
372
  leveli = 'class' if level == 'classes' else level
318
373
  original = cls.__dict__.get( '__delattr__' )
374
+ core = _behaviors.access_core_function(
375
+ cls,
376
+ attributes_namer = attributes_namer,
377
+ arguments = { f"{level}_deleter": implementation_core },
378
+ level = level, name = 'deleter',
379
+ default = _behaviors.delete_attribute_if_mutable )
319
380
 
320
381
  if original is None:
321
382
 
@@ -325,7 +386,7 @@ def produce_attributes_deletion_decorator(
325
386
  if cls is not type( self ):
326
387
  ligation( name )
327
388
  return
328
- implementation_core(
389
+ core(
329
390
  self,
330
391
  ligation = ligation,
331
392
  attributes_namer = attributes_namer,
@@ -344,7 +405,7 @@ def produce_attributes_deletion_decorator(
344
405
  if cls is not type( self ):
345
406
  ligation( name )
346
407
  return
347
- implementation_core(
408
+ core(
348
409
  self,
349
410
  ligation = ligation,
350
411
  attributes_namer = attributes_namer,
@@ -362,12 +423,18 @@ def produce_attributes_deletion_decorator(
362
423
  def produce_attributes_surveillance_decorator(
363
424
  level: str,
364
425
  attributes_namer: _nomina.AttributesNamer,
365
- implementation_core: _nomina.SurveyorCore,
426
+ implementation_core: __.typx.Optional[ _nomina.SurveyorCore ],
366
427
  ) -> _nomina.Decorator[ __.U ]:
367
428
  ''' Produces decorator to inject '__dir__' method into class. '''
368
429
  def decorate( cls: type[ __.U ] ) -> type[ __.U ]:
369
430
  leveli = 'class' if level == 'classes' else level
370
431
  original = cls.__dict__.get( '__dir__' )
432
+ core = _behaviors.access_core_function(
433
+ cls,
434
+ attributes_namer = attributes_namer,
435
+ arguments = { f"{level}_surveyor": implementation_core },
436
+ level = level, name = 'surveyor',
437
+ default = _behaviors.survey_visible_attributes )
371
438
 
372
439
  if original is None:
373
440
 
@@ -377,7 +444,7 @@ def produce_attributes_surveillance_decorator(
377
444
  ligation = super( cls, self ).__dir__
378
445
  # Only enforce behaviors at start of MRO.
379
446
  if cls is not type( self ): return ligation( )
380
- return implementation_core(
447
+ return core(
381
448
  self,
382
449
  ligation = ligation,
383
450
  attributes_namer = attributes_namer,
@@ -394,7 +461,7 @@ def produce_attributes_surveillance_decorator(
394
461
  ligation = __.funct.partial( original, self )
395
462
  # Only enforce behaviors at start of MRO.
396
463
  if cls is not type( self ): return ligation( )
397
- return implementation_core(
464
+ return core(
398
465
  self,
399
466
  ligation = ligation,
400
467
  attributes_namer = attributes_namer,
@@ -412,12 +479,9 @@ def dataclass_with_standard_behaviors( # noqa: PLR0913
412
479
  attributes_namer: _nomina.AttributesNamer = __.calculate_attrname,
413
480
  error_class_provider: _nomina.ErrorClassProvider = __.provide_error_class,
414
481
  decorators: _nomina.Decorators[ __.U ] = ( ),
415
- assigner_core: _nomina.AssignerCore = (
416
- _behaviors.assign_attribute_if_mutable ),
417
- deleter_core: _nomina.DeleterCore = (
418
- _behaviors.delete_attribute_if_mutable ),
419
- surveyor_core: _nomina.SurveyorCore = (
420
- _behaviors.survey_visible_attributes ),
482
+ assigner_core: __.typx.Optional[ _nomina.AssignerCore ] = None,
483
+ deleter_core: __.typx.Optional[ _nomina.DeleterCore ] = None,
484
+ surveyor_core: __.typx.Optional[ _nomina.SurveyorCore ] = None,
421
485
  mutables: _nomina.BehaviorExclusionVerifiersOmni = __.mutables_default,
422
486
  visibles: _nomina.BehaviorExclusionVerifiersOmni = __.visibles_default,
423
487
  ) -> _nomina.Decorator[ __.U ]:
@@ -445,12 +509,9 @@ def with_standard_behaviors( # noqa: PLR0913
445
509
  attributes_namer: _nomina.AttributesNamer = __.calculate_attrname,
446
510
  error_class_provider: _nomina.ErrorClassProvider = __.provide_error_class,
447
511
  decorators: _nomina.Decorators[ __.U ] = ( ),
448
- assigner_core: _nomina.AssignerCore = (
449
- _behaviors.assign_attribute_if_mutable ),
450
- deleter_core: _nomina.DeleterCore = (
451
- _behaviors.delete_attribute_if_mutable ),
452
- surveyor_core: _nomina.SurveyorCore = (
453
- _behaviors.survey_visible_attributes ),
512
+ assigner_core: __.typx.Optional[ _nomina.AssignerCore ] = None,
513
+ deleter_core: __.typx.Optional[ _nomina.DeleterCore ] = None,
514
+ surveyor_core: __.typx.Optional[ _nomina.SurveyorCore ] = None,
454
515
  mutables: _nomina.BehaviorExclusionVerifiersOmni = __.mutables_default,
455
516
  visibles: _nomina.BehaviorExclusionVerifiersOmni = __.visibles_default,
456
517
  ) -> _nomina.Decorator[ __.U ]:
@@ -481,16 +542,16 @@ def _produce_instances_decoration_preparers(
481
542
  if class_preparer is not None:
482
543
  preprocessors.append(
483
544
  __.funct.partial(
484
- class_preparer, attributes_namer = attributes_namer ) )
545
+ class_preparer, attributes_namer = attributes_namer ) )
485
546
  return tuple( preprocessors )
486
547
 
487
548
 
488
549
  def _produce_instances_decorators( # noqa: PLR0913
489
550
  attributes_namer: _nomina.AttributesNamer,
490
551
  error_class_provider: _nomina.ErrorClassProvider,
491
- assigner_core: _nomina.AssignerCore,
492
- deleter_core: _nomina.DeleterCore,
493
- surveyor_core: _nomina.SurveyorCore,
552
+ assigner_core: __.typx.Optional[ _nomina.AssignerCore ],
553
+ deleter_core: __.typx.Optional[ _nomina.DeleterCore ],
554
+ surveyor_core: __.typx.Optional[ _nomina.SurveyorCore ],
494
555
  mutables: _nomina.BehaviorExclusionVerifiersOmni,
495
556
  visibles: _nomina.BehaviorExclusionVerifiersOmni,
496
557
  ) -> _nomina.Decorators[ __.U ]:
@@ -499,24 +560,25 @@ def _produce_instances_decorators( # noqa: PLR0913
499
560
  decorators.append(
500
561
  produce_instances_initialization_decorator(
501
562
  attributes_namer = attributes_namer,
563
+ assigner_core = assigner_core,
564
+ deleter_core = deleter_core,
565
+ surveyor_core = surveyor_core,
502
566
  mutables = mutables, visibles = visibles ) )
503
- if mutables != '*':
504
- decorators.append(
505
- produce_attributes_assignment_decorator(
506
- level = 'instances',
507
- attributes_namer = attributes_namer,
508
- error_class_provider = error_class_provider,
509
- implementation_core = assigner_core ) )
510
- decorators.append(
511
- produce_attributes_deletion_decorator(
512
- level = 'instances',
513
- attributes_namer = attributes_namer,
514
- error_class_provider = error_class_provider,
515
- implementation_core = deleter_core ) )
516
- if visibles != '*':
517
- decorators.append(
518
- produce_attributes_surveillance_decorator(
519
- level = 'instances',
520
- attributes_namer = attributes_namer,
521
- implementation_core = surveyor_core ) )
567
+ decorators.append(
568
+ produce_attributes_assignment_decorator(
569
+ level = 'instances',
570
+ attributes_namer = attributes_namer,
571
+ error_class_provider = error_class_provider,
572
+ implementation_core = assigner_core ) )
573
+ decorators.append(
574
+ produce_attributes_deletion_decorator(
575
+ level = 'instances',
576
+ attributes_namer = attributes_namer,
577
+ error_class_provider = error_class_provider,
578
+ implementation_core = deleter_core ) )
579
+ decorators.append(
580
+ produce_attributes_surveillance_decorator(
581
+ level = 'instances',
582
+ attributes_namer = attributes_namer,
583
+ implementation_core = surveyor_core ) )
522
584
  return decorators
@@ -26,34 +26,34 @@ from . import __
26
26
  from . import nomina as _nomina
27
27
 
28
28
 
29
- dynadoc_context = __.dynadoc.produce_context( )
29
+ dynadoc_context = __.ddoc.produce_context( )
30
30
  dynadoc_class_introspection_control = (
31
- __.dynadoc.ClassIntrospectionControl(
31
+ __.ddoc.ClassIntrospectionControl(
32
32
  inheritance = True,
33
33
  introspectors = (
34
- __.dynadoc.introspection.introspect_special_classes, ) ) )
34
+ __.ddoc.introspection.introspect_special_classes, ) ) )
35
35
  dynadoc_module_introspection_control = (
36
- __.dynadoc.ModuleIntrospectionControl( ) )
36
+ __.ddoc.ModuleIntrospectionControl( ) )
37
37
 
38
38
 
39
39
  def dynadoc_avoid_immutables(
40
40
  objct: object,
41
- introspection: __.dynadoc.IntrospectionControl,
41
+ introspection: __.ddoc.IntrospectionControl,
42
42
  attributes_namer: _nomina.AttributesNamer,
43
- ) -> __.dynadoc.IntrospectionControl:
43
+ ) -> __.ddoc.IntrospectionControl:
44
44
  ''' Disables introspection of immutable objects. '''
45
45
  if __.inspect.isclass( objct ):
46
46
  behaviors_name = attributes_namer( 'class', 'behaviors' )
47
47
  behaviors = _utilities.getattr0( objct, behaviors_name, frozenset( ) )
48
48
  if _nomina.immutability_label in behaviors:
49
49
  return introspection.with_limit(
50
- __.dynadoc.IntrospectionLimit( disable = True ) )
50
+ __.ddoc.IntrospectionLimit( disable = True ) )
51
51
  return introspection
52
52
 
53
53
 
54
54
  def produce_dynadoc_introspection_limiter(
55
55
  attributes_namer: _nomina.AttributesNamer = __.calculate_attrname,
56
- ) -> __.dynadoc.IntrospectionLimiter:
56
+ ) -> __.ddoc.IntrospectionLimiter:
57
57
  ''' Produces introspection limiter which avoids immutable objects. '''
58
58
  return __.funct.partial(
59
59
  dynadoc_avoid_immutables, attributes_namer = attributes_namer )
@@ -63,17 +63,17 @@ dynadoc_introspection_limiter = produce_dynadoc_introspection_limiter( )
63
63
 
64
64
  def produce_dynadoc_introspection_control(
65
65
  enable: bool = True,
66
- class_control: __.dynadoc.ClassIntrospectionControl = (
66
+ class_control: __.ddoc.ClassIntrospectionControl = (
67
67
  dynadoc_class_introspection_control ),
68
- module_control: __.dynadoc.ModuleIntrospectionControl = (
68
+ module_control: __.ddoc.ModuleIntrospectionControl = (
69
69
  dynadoc_module_introspection_control ),
70
- limiters: __.dynadoc.IntrospectionLimiters = (
70
+ limiters: __.ddoc.IntrospectionLimiters = (
71
71
  dynadoc_introspection_limiter, ),
72
- targets: __.dynadoc.IntrospectionTargets = (
73
- __.dynadoc.IntrospectionTargetsSansModule ),
74
- ) -> __.dynadoc.IntrospectionControl:
72
+ targets: __.ddoc.IntrospectionTargets = (
73
+ __.ddoc.IntrospectionTargetsSansModule ),
74
+ ) -> __.ddoc.IntrospectionControl:
75
75
  ''' Produces compatible Dynadoc introspection control. '''
76
- return __.dynadoc.IntrospectionControl(
76
+ return __.ddoc.IntrospectionControl(
77
77
  enable = enable,
78
78
  class_control = class_control,
79
79
  module_control = module_control,
@@ -83,18 +83,18 @@ def produce_dynadoc_introspection_control(
83
83
  dynadoc_introspection_on_class = produce_dynadoc_introspection_control( )
84
84
  dynadoc_introspection_on_package = (
85
85
  produce_dynadoc_introspection_control(
86
- targets = __.dynadoc.IntrospectionTargetsOmni ) )
86
+ targets = __.ddoc.IntrospectionTargetsOmni ) )
87
87
 
88
88
 
89
89
  def assign_module_docstring( # noqa: PLR0913
90
90
  module: str | __.types.ModuleType, /,
91
- *fragments: __.dynadoc.interfaces.Fragment,
91
+ *fragments: __.ddoc.interfaces.Fragment,
92
92
  context: _nomina.DynadocContextArgument = dynadoc_context,
93
93
  introspection: _nomina.DynadocIntrospectionArgument = (
94
94
  dynadoc_introspection_on_package ),
95
95
  preserve: _nomina.DynadocPreserveArgument = True,
96
- renderer: __.dynadoc.xtnsapi.Renderer = (
97
- __.dynadoc.assembly.renderer_default ),
96
+ renderer: __.ddoc.xtnsapi.Renderer = (
97
+ __.ddoc.assembly.renderer_default ),
98
98
  table: _nomina.DynadocTableArgument = __.dictproxy_empty,
99
99
  ) -> None:
100
100
  ''' Updates module docstring based on introspection.
@@ -104,7 +104,7 @@ def assign_module_docstring( # noqa: PLR0913
104
104
 
105
105
  By default, ignores previously-decorated immutable classes.
106
106
  '''
107
- __.dynadoc.assign_module_docstring(
107
+ __.ddoc.assign_module_docstring(
108
108
  module,
109
109
  *fragments,
110
110
  context = context,
@@ -34,20 +34,20 @@ class Module( _classes.Object, __.types.ModuleType ):
34
34
  def reclassify_modules(
35
35
  attributes: __.typx.Annotated[
36
36
  __.cabc.Mapping[ str, __.typx.Any ] | __.types.ModuleType | str,
37
- __.dynadoc.Doc(
37
+ __.ddoc.Doc(
38
38
  ''' Module, module name, or dictionary of object attributes. ''' ),
39
39
  ], /, *,
40
40
  attributes_namer: __.typx.Annotated[
41
41
  _nomina.AttributesNamer,
42
- __.dynadoc.Doc(
42
+ __.ddoc.Doc(
43
43
  ''' Attributes namer function with which to seal class. ''' ),
44
44
  ] = __.calculate_attrname,
45
45
  recursive: __.typx.Annotated[
46
- bool, __.dynadoc.Doc( ''' Recursively reclassify package modules? ''' )
46
+ bool, __.ddoc.Doc( ''' Recursively reclassify package modules? ''' )
47
47
  ] = False,
48
48
  replacement_class: __.typx.Annotated[
49
49
  type[ __.types.ModuleType ],
50
- __.dynadoc.Doc( ''' New class for module. ''' ),
50
+ __.ddoc.Doc( ''' New class for module. ''' ),
51
51
  ] = Module,
52
52
  ) -> None:
53
53
  # TODO? Ensure correct operation with namespace packages.
@@ -46,8 +46,15 @@ BehaviorExclusionVerifiers: __.typx.TypeAlias = (
46
46
  __.cabc.Sequence[ BehaviorExclusionVerifier ] )
47
47
  BehaviorExclusionVerifiersOmni: __.typx.TypeAlias = (
48
48
  BehaviorExclusionVerifiers | __.typx.Literal[ '*' ] )
49
- ErrorClassProvider: __.typx.TypeAlias = (
50
- __.cabc.Callable[ [ str ], type[ Exception ] ] )
49
+ ErrorClassProvider: __.typx.TypeAlias = __.typx.Annotated[
50
+ __.cabc.Callable[ [ str ], type[ Exception ] ],
51
+ __.ddoc.Doc(
52
+ ''' Takes name of exception class and returns corresponding class.
53
+
54
+ Can be used by downstream packages to provide exceptions from their
55
+ own hierarchies rather than the hierarchy from this package.
56
+ ''' ),
57
+ ]
51
58
 
52
59
 
53
60
  class AssignerCore( __.typx.Protocol ):
@@ -103,9 +110,10 @@ class ClassPreparer( __.typx.Protocol ):
103
110
 
104
111
 
105
112
  DynadocConfiguration: __.typx.TypeAlias = __.cabc.Mapping[ str, __.typx.Any ]
113
+ # TODO: Use argument type aliases from 'dynadoc' package.
106
114
  DynadocContextArgument: __.typx.TypeAlias = __.typx.Annotated[
107
- __.dynadoc.Context,
108
- __.dynadoc.Doc(
115
+ __.ddoc.Context,
116
+ __.ddoc.Doc(
109
117
  ''' Dynadoc context.
110
118
 
111
119
  Renderer, dictionaries for resolution of stringified annotations,
@@ -113,8 +121,8 @@ DynadocContextArgument: __.typx.TypeAlias = __.typx.Annotated[
113
121
  ''' ),
114
122
  ]
115
123
  DynadocIntrospectionArgument: __.typx.TypeAlias = __.typx.Annotated[
116
- __.dynadoc.IntrospectionControl,
117
- __.dynadoc.Doc(
124
+ __.ddoc.IntrospectionControl,
125
+ __.ddoc.Doc(
118
126
  ''' Dynadoc introspection control.
119
127
 
120
128
  Which kinds of object to recursively introspect?
@@ -124,15 +132,15 @@ DynadocIntrospectionArgument: __.typx.TypeAlias = __.typx.Annotated[
124
132
  ''' ),
125
133
  ]
126
134
  DynadocPreserveArgument: __.typx.TypeAlias = __.typx.Annotated[
127
- bool, __.dynadoc.Doc( ''' Preserve existing docstring? ''' )
135
+ bool, __.ddoc.Doc( ''' Preserve existing docstring? ''' )
128
136
  ]
129
137
  DynadocTableArgument: __.typx.TypeAlias = __.typx.Annotated[
130
138
  __.cabc.Mapping[ str, str ],
131
- __.dynadoc.Doc( ''' Table of documentation fragments. ''' ),
139
+ __.ddoc.Doc( ''' Table of documentation fragments. ''' ),
132
140
  ]
133
141
  ProduceDynadocConfigurationReturn: __.typx.TypeAlias = __.typx.Annotated[
134
142
  DynadocConfiguration,
135
- __.dynadoc.Doc(
143
+ __.ddoc.Doc(
136
144
  ''' Dynadoc configuration dictionary.
137
145
 
138
146
  Suitable as a keyword expansion (``**``) argument to
@@ -95,8 +95,11 @@ def mangle_name( objct: object, /, name: str ) -> str:
95
95
  Effectively provides name of private member attribute,
96
96
  which is unique across class inheritance.
97
97
  '''
98
+ # TODO: Replace expensive SHA-256 hash with simple 'id'.
99
+ # Need to debug weird issue with using 'id' early on dataclasses.
98
100
  if not __.inspect.isclass( objct ):
99
101
  return mangle_name( type( objct ), name )
102
+ # return "{name}_{uid}".format( name = name, uid = id( objct ) )
100
103
  namehash = __.hashlib.sha256( )
101
104
  namehash.update( qualify_class_name( objct ).encode( ) )
102
105
  namehash_hex = namehash.hexdigest( )
File without changes
File without changes
File without changes
File without changes