classcore 1.2rc0__tar.gz → 1.3.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.2rc0 → classcore-1.3.1}/PKG-INFO +1 -1
  2. {classcore-1.2rc0 → classcore-1.3.1}/sources/classcore/__init__.py +1 -1
  3. {classcore-1.2rc0 → classcore-1.3.1}/sources/classcore/standard/behaviors.py +18 -2
  4. {classcore-1.2rc0 → classcore-1.3.1}/sources/classcore/standard/decorators.py +97 -84
  5. {classcore-1.2rc0 → classcore-1.3.1}/sources/classcore/standard/modules.py +19 -9
  6. {classcore-1.2rc0 → classcore-1.3.1}/.gitignore +0 -0
  7. {classcore-1.2rc0 → classcore-1.3.1}/LICENSE.txt +0 -0
  8. {classcore-1.2rc0 → classcore-1.3.1}/README.rst +0 -0
  9. {classcore-1.2rc0 → classcore-1.3.1}/pyproject.toml +0 -0
  10. {classcore-1.2rc0 → classcore-1.3.1}/sources/classcore/__/__init__.py +0 -0
  11. {classcore-1.2rc0 → classcore-1.3.1}/sources/classcore/__/doctab.py +0 -0
  12. {classcore-1.2rc0 → classcore-1.3.1}/sources/classcore/__/imports.py +0 -0
  13. {classcore-1.2rc0 → classcore-1.3.1}/sources/classcore/__/nomina.py +0 -0
  14. {classcore-1.2rc0 → classcore-1.3.1}/sources/classcore/decorators.py +0 -0
  15. {classcore-1.2rc0 → classcore-1.3.1}/sources/classcore/exceptions.py +0 -0
  16. {classcore-1.2rc0 → classcore-1.3.1}/sources/classcore/factories.py +0 -0
  17. {classcore-1.2rc0 → classcore-1.3.1}/sources/classcore/nomina.py +0 -0
  18. {classcore-1.2rc0 → classcore-1.3.1}/sources/classcore/py.typed +0 -0
  19. {classcore-1.2rc0 → classcore-1.3.1}/sources/classcore/standard/__.py +0 -0
  20. {classcore-1.2rc0 → classcore-1.3.1}/sources/classcore/standard/__init__.py +0 -0
  21. {classcore-1.2rc0 → classcore-1.3.1}/sources/classcore/standard/classes.py +0 -0
  22. {classcore-1.2rc0 → classcore-1.3.1}/sources/classcore/standard/dynadoc.py +0 -0
  23. {classcore-1.2rc0 → classcore-1.3.1}/sources/classcore/standard/nomina.py +0 -0
  24. {classcore-1.2rc0 → classcore-1.3.1}/sources/classcore/utilities.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: classcore
3
- Version: 1.2rc0
3
+ Version: 1.3.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
@@ -62,7 +62,7 @@ from .factories import *
62
62
 
63
63
 
64
64
  __version__: __.typx.Annotated[ str, __.dynadoc.Visibilities.Reveal ]
65
- __version__ = '1.2rc0'
65
+ __version__ = '1.3.1'
66
66
 
67
67
 
68
68
  standard.dynadoc.assign_module_docstring( __name__, table = __.fragments )
@@ -195,7 +195,8 @@ def produce_class_construction_preprocessor(
195
195
 
196
196
 
197
197
  def produce_class_construction_postprocessor(
198
- attributes_namer: _nomina.AttributesNamer
198
+ attributes_namer: _nomina.AttributesNamer,
199
+ error_class_provider: _nomina.ErrorClassProvider,
199
200
  ) -> _nomina.ClassConstructionPostprocessor[ __.U ]:
200
201
  ''' Produces construction processor which determines class decorators. '''
201
202
  arguments_name = attributes_namer( 'class', 'construction_arguments' )
@@ -214,6 +215,12 @@ def produce_class_construction_postprocessor(
214
215
  dcls_spec = getattr( cls, '__dataclass_transform__', None )
215
216
  if not dcls_spec: # either base class or metaclass may be marked
216
217
  dcls_spec = getattr( clscls, '__dataclass_transform__', None )
218
+ instances_assigner = arguments.get(
219
+ 'instances_assigner_core', assign_attribute_if_mutable )
220
+ instances_deleter = arguments.get(
221
+ 'instances_deleter_core', delete_attribute_if_mutable )
222
+ instances_surveyor = arguments.get(
223
+ 'instances_surveyor_core', survey_visible_attributes )
217
224
  instances_mutables = arguments.get(
218
225
  'instances_mutables', __.mutables_default )
219
226
  instances_visibles = arguments.get(
@@ -227,7 +234,13 @@ def produce_class_construction_postprocessor(
227
234
  from .decorators import with_standard_behaviors
228
235
  decorator_factory = with_standard_behaviors
229
236
  decorator: _nomina.Decorator[ __.U ] = decorator_factory(
230
- mutables = instances_mutables, visibles = instances_visibles )
237
+ attributes_namer = attributes_namer,
238
+ error_class_provider = error_class_provider,
239
+ assigner_core = instances_assigner,
240
+ deleter_core = instances_deleter,
241
+ surveyor_core = instances_surveyor,
242
+ mutables = instances_mutables,
243
+ visibles = instances_visibles )
231
244
  decorators.append( decorator )
232
245
 
233
246
  return postprocess
@@ -316,6 +329,9 @@ def record_class_construction_arguments(
316
329
  arguments_ = { }
317
330
  for name in (
318
331
  'class_mutables', 'class_visibles',
332
+ 'instances_assigner_core',
333
+ 'instances_deleter_core',
334
+ 'instances_surveyor_core',
319
335
  'instances_mutables', 'instances_visibles',
320
336
  'dynadoc_configuration',
321
337
  ):
@@ -66,7 +66,9 @@ def apply_cfc_dynadoc_configuration(
66
66
 
67
67
 
68
68
  def apply_cfc_constructor(
69
- clscls: type[ __.T ], /, attributes_namer: _nomina.AttributesNamer
69
+ clscls: type[ __.T ], /,
70
+ attributes_namer: _nomina.AttributesNamer,
71
+ error_class_provider: _nomina.ErrorClassProvider,
70
72
  ) -> None:
71
73
  ''' Injects '__new__' method into metaclass. '''
72
74
  preprocessors = (
@@ -74,7 +76,8 @@ def apply_cfc_constructor(
74
76
  attributes_namer = attributes_namer ), )
75
77
  postprocessors = (
76
78
  _behaviors.produce_class_construction_postprocessor(
77
- attributes_namer = attributes_namer ), )
79
+ attributes_namer = attributes_namer,
80
+ error_class_provider = error_class_provider ), )
78
81
  constructor: _nomina.ClassConstructor[ __.T ] = (
79
82
  _factories.produce_class_constructor(
80
83
  attributes_namer = attributes_namer,
@@ -162,7 +165,10 @@ def class_factory( # noqa: PLR0913
162
165
  clscls,
163
166
  attributes_namer = attributes_namer,
164
167
  configuration = dynadoc_configuration )
165
- apply_cfc_constructor( clscls, attributes_namer = attributes_namer )
168
+ apply_cfc_constructor(
169
+ clscls,
170
+ attributes_namer = attributes_namer,
171
+ error_class_provider = error_class_provider )
166
172
  apply_cfc_initializer( clscls, attributes_namer = attributes_namer )
167
173
  apply_cfc_attributes_assigner(
168
174
  clscls,
@@ -311,109 +317,116 @@ def produce_attributes_surveillance_decorator(
311
317
  return decorate
312
318
 
313
319
 
314
- def produce_decorators_factory( # noqa: PLR0913
315
- level: str,
320
+ @__.typx.dataclass_transform( frozen_default = True, kw_only_default = True )
321
+ def dataclass_with_standard_behaviors( # noqa: PLR0913
316
322
  attributes_namer: _nomina.AttributesNamer = __.calculate_attrname,
317
323
  error_class_provider: _nomina.ErrorClassProvider = __.provide_error_class,
324
+ decorators: _nomina.Decorators[ __.U ] = ( ),
318
325
  assigner_core: _nomina.AssignerCore = (
319
326
  _behaviors.assign_attribute_if_mutable ),
320
327
  deleter_core: _nomina.DeleterCore = (
321
328
  _behaviors.delete_attribute_if_mutable ),
322
329
  surveyor_core: _nomina.SurveyorCore = (
323
330
  _behaviors.survey_visible_attributes ),
324
- ) -> __.cabc.Callable[
325
- [
326
- _nomina.BehaviorExclusionVerifiersOmni,
327
- _nomina.BehaviorExclusionVerifiersOmni
328
- ],
329
- _nomina.Decorators[ __.U ]
330
- ]:
331
- ''' Produces decorators to imbue class with standard behaviors. '''
332
- def produce(
333
- mutables: _nomina.BehaviorExclusionVerifiersOmni,
334
- visibles: _nomina.BehaviorExclusionVerifiersOmni,
335
- ) -> _nomina.Decorators[ __.U ]:
336
- ''' Produces standard decorators. '''
337
- decorators: list[ _nomina.Decorator[ __.U ] ] = [ ]
338
- decorators.append(
339
- produce_instances_initialization_decorator(
340
- attributes_namer = attributes_namer,
341
- mutables = mutables, visibles = visibles ) )
342
- if mutables != '*':
343
- decorators.append(
344
- produce_attributes_assignment_decorator(
345
- level = level,
346
- attributes_namer = attributes_namer,
347
- error_class_provider = error_class_provider,
348
- implementation_core = assigner_core ) )
349
- decorators.append(
350
- produce_attributes_deletion_decorator(
351
- level = level,
352
- attributes_namer = attributes_namer,
353
- error_class_provider = error_class_provider,
354
- implementation_core = deleter_core ) )
355
- if visibles != '*':
356
- decorators.append(
357
- produce_attributes_surveillance_decorator(
358
- level = level,
359
- attributes_namer = attributes_namer,
360
- implementation_core = surveyor_core ) )
361
- return decorators
362
-
363
- return produce
364
-
365
-
366
- def produce_decoration_preparers_factory(
367
- attributes_namer: _nomina.AttributesNamer = __.calculate_attrname,
368
- error_class_provider: _nomina.ErrorClassProvider = __.provide_error_class,
369
- class_preparer: __.typx.Optional[ _nomina.ClassPreparer ] = None,
370
- ) -> _nomina.DecorationPreparersFactory[ __.U ]:
371
- ''' Produces factory to produce class decoration preparers.
372
-
373
- E.g., a preparer needs to inject special annotations to ensure
374
- compatibility with standard behaviors before
375
- :py:func:`dataclasses.dataclass` decorates a class.
376
- '''
377
- def produce( ) -> _nomina.DecorationPreparers[ __.U ]:
378
- ''' Produces processors for standard decorators. '''
379
- preprocessors: list[ _nomina.DecorationPreparer[ __.U ] ] = [ ]
380
- if class_preparer is not None:
381
- preprocessors.append(
382
- __.funct.partial(
383
- class_preparer,
384
- attributes_namer = attributes_namer ) )
385
- return tuple( preprocessors )
386
-
387
- return produce
388
-
389
-
390
- @__.typx.dataclass_transform( frozen_default = True, kw_only_default = True )
391
- def dataclass_with_standard_behaviors(
392
- decorators: _nomina.Decorators[ __.U ] = ( ),
393
331
  mutables: _nomina.BehaviorExclusionVerifiersOmni = __.mutables_default,
394
332
  visibles: _nomina.BehaviorExclusionVerifiersOmni = __.visibles_default,
395
333
  ) -> _nomina.Decorator[ __.U ]:
396
334
  # https://github.com/microsoft/pyright/discussions/10344
397
335
  ''' Dataclass decorator factory. '''
398
- decorators_factory = produce_decorators_factory( level = 'instances' )
399
336
  decorators_: _nomina.Decorators[ __.U ] = (
400
- decorators_factory( mutables, visibles ) )
401
- preparers_factory = produce_decoration_preparers_factory(
402
- class_preparer = prepare_dataclass_for_instances )
403
- preparers: _nomina.DecorationPreparers[ __.U ] = preparers_factory( )
337
+ _produce_instances_decorators(
338
+ attributes_namer = attributes_namer,
339
+ error_class_provider = error_class_provider,
340
+ assigner_core = assigner_core,
341
+ deleter_core = deleter_core,
342
+ surveyor_core = surveyor_core,
343
+ mutables = mutables,
344
+ visibles = visibles ) )
345
+ preparers: _nomina.DecorationPreparers[ __.U ] = (
346
+ _produce_instances_decoration_preparers(
347
+ attributes_namer = attributes_namer,
348
+ error_class_provider = error_class_provider,
349
+ class_preparer = prepare_dataclass_for_instances ) )
404
350
  return decoration_by(
405
351
  *decorators, _dataclass_core, *decorators_, preparers = preparers )
406
352
 
407
353
 
408
- def with_standard_behaviors(
354
+ def with_standard_behaviors( # noqa: PLR0913
355
+ attributes_namer: _nomina.AttributesNamer = __.calculate_attrname,
356
+ error_class_provider: _nomina.ErrorClassProvider = __.provide_error_class,
409
357
  decorators: _nomina.Decorators[ __.U ] = ( ),
358
+ assigner_core: _nomina.AssignerCore = (
359
+ _behaviors.assign_attribute_if_mutable ),
360
+ deleter_core: _nomina.DeleterCore = (
361
+ _behaviors.delete_attribute_if_mutable ),
362
+ surveyor_core: _nomina.SurveyorCore = (
363
+ _behaviors.survey_visible_attributes ),
410
364
  mutables: _nomina.BehaviorExclusionVerifiersOmni = __.mutables_default,
411
365
  visibles: _nomina.BehaviorExclusionVerifiersOmni = __.visibles_default,
412
366
  ) -> _nomina.Decorator[ __.U ]:
413
367
  ''' Class decorator factory. '''
414
- decorators_factory = produce_decorators_factory( level = 'instances' )
415
368
  decorators_: _nomina.Decorators[ __.U ] = (
416
- decorators_factory( mutables, visibles ) )
417
- preparers_factory = produce_decoration_preparers_factory( )
418
- preparers: _nomina.DecorationPreparers[ __.U ] = preparers_factory( )
369
+ _produce_instances_decorators(
370
+ attributes_namer = attributes_namer,
371
+ error_class_provider = error_class_provider,
372
+ assigner_core = assigner_core,
373
+ deleter_core = deleter_core,
374
+ surveyor_core = surveyor_core,
375
+ mutables = mutables,
376
+ visibles = visibles ) )
377
+ preparers: _nomina.DecorationPreparers[ __.U ] = (
378
+ _produce_instances_decoration_preparers(
379
+ attributes_namer = attributes_namer,
380
+ error_class_provider = error_class_provider ) )
419
381
  return decoration_by( *decorators, *decorators_, preparers = preparers )
382
+
383
+
384
+ def _produce_instances_decoration_preparers(
385
+ attributes_namer: _nomina.AttributesNamer,
386
+ error_class_provider: _nomina.ErrorClassProvider,
387
+ class_preparer: __.typx.Optional[ _nomina.ClassPreparer ] = None,
388
+ ) -> _nomina.DecorationPreparers[ __.U ]:
389
+ ''' Produces processors for standard decorators. '''
390
+ preprocessors: list[ _nomina.DecorationPreparer[ __.U ] ] = [ ]
391
+ if class_preparer is not None:
392
+ preprocessors.append(
393
+ __.funct.partial(
394
+ class_preparer, attributes_namer = attributes_namer ) )
395
+ return tuple( preprocessors )
396
+
397
+
398
+ def _produce_instances_decorators( # noqa: PLR0913
399
+ attributes_namer: _nomina.AttributesNamer,
400
+ error_class_provider: _nomina.ErrorClassProvider,
401
+ assigner_core: _nomina.AssignerCore,
402
+ deleter_core: _nomina.DeleterCore,
403
+ surveyor_core: _nomina.SurveyorCore,
404
+ mutables: _nomina.BehaviorExclusionVerifiersOmni,
405
+ visibles: _nomina.BehaviorExclusionVerifiersOmni,
406
+ ) -> _nomina.Decorators[ __.U ]:
407
+ ''' Produces standard decorators. '''
408
+ decorators: list[ _nomina.Decorator[ __.U ] ] = [ ]
409
+ decorators.append(
410
+ produce_instances_initialization_decorator(
411
+ attributes_namer = attributes_namer,
412
+ mutables = mutables, visibles = visibles ) )
413
+ if mutables != '*':
414
+ decorators.append(
415
+ produce_attributes_assignment_decorator(
416
+ level = 'instances',
417
+ attributes_namer = attributes_namer,
418
+ error_class_provider = error_class_provider,
419
+ implementation_core = assigner_core ) )
420
+ decorators.append(
421
+ produce_attributes_deletion_decorator(
422
+ level = 'instances',
423
+ attributes_namer = attributes_namer,
424
+ error_class_provider = error_class_provider,
425
+ implementation_core = deleter_core ) )
426
+ if visibles != '*':
427
+ decorators.append(
428
+ produce_attributes_surveillance_decorator(
429
+ level = 'instances',
430
+ attributes_namer = attributes_namer,
431
+ implementation_core = surveyor_core ) )
432
+ return decorators
@@ -35,7 +35,7 @@ def reclassify_modules(
35
35
  attributes: __.typx.Annotated[
36
36
  __.cabc.Mapping[ str, __.typx.Any ] | __.types.ModuleType | str,
37
37
  __.dynadoc.Doc(
38
- 'Module, module name, or dictionary of object attributes.' ),
38
+ ''' Module, module name, or dictionary of object attributes. ''' ),
39
39
  ], /, *,
40
40
  attributes_namer: __.typx.Annotated[
41
41
  _nomina.AttributesNamer,
@@ -43,8 +43,12 @@ def reclassify_modules(
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, __.dynadoc.Doc( ''' Recursively reclassify package modules? ''' )
47
47
  ] = False,
48
+ replacement_class: __.typx.Annotated[
49
+ type[ __.types.ModuleType ],
50
+ __.dynadoc.Doc( ''' New class for module. ''' ),
51
+ ] = Module,
48
52
  ) -> None:
49
53
  # TODO? Ensure correct operation with namespace packages.
50
54
  ''' Reclassifies modules to have attributes concealment and immutability.
@@ -71,17 +75,23 @@ def reclassify_modules(
71
75
  for value in attributes.values( ):
72
76
  if not __.inspect.ismodule( value ): continue
73
77
  if not value.__name__.startswith( f"{package_name}." ): continue
74
- if recursive: reclassify_modules( value, recursive = True )
75
- if isinstance( value, Module ): continue
76
- _seal_module( value, attributes_namer )
77
- if module and not isinstance( module, Module ):
78
- _seal_module( module, attributes_namer )
78
+ if recursive:
79
+ reclassify_modules(
80
+ value,
81
+ recursive = True,
82
+ replacement_class = replacement_class )
83
+ if isinstance( value, replacement_class ): continue
84
+ _seal_module( value, attributes_namer, replacement_class )
85
+ if module and not isinstance( module, replacement_class ):
86
+ _seal_module( module, attributes_namer, replacement_class )
79
87
 
80
88
 
81
89
  def _seal_module(
82
- module: __.types.ModuleType, attributes_namer: _nomina.AttributesNamer
90
+ module: __.types.ModuleType,
91
+ attributes_namer: _nomina.AttributesNamer,
92
+ replacement_class: type[ __.types.ModuleType ],
83
93
  ) -> None:
84
94
  behaviors = { _nomina.concealment_label, _nomina.immutability_label }
85
95
  behaviors_name = attributes_namer( 'instance', 'behaviors' )
86
96
  _utilities.setattr0( module, behaviors_name, behaviors )
87
- module.__class__ = Module
97
+ module.__class__ = replacement_class
File without changes
File without changes
File without changes
File without changes