classcore 1.3.1__tar.gz → 1.4__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.
- {classcore-1.3.1 → classcore-1.4}/PKG-INFO +1 -1
- {classcore-1.3.1 → classcore-1.4}/sources/classcore/__init__.py +1 -1
- {classcore-1.3.1 → classcore-1.4}/sources/classcore/decorators.py +66 -33
- {classcore-1.3.1 → classcore-1.4}/sources/classcore/exceptions.py +5 -5
- {classcore-1.3.1 → classcore-1.4}/sources/classcore/standard/behaviors.py +26 -1
- {classcore-1.3.1 → classcore-1.4}/sources/classcore/standard/classes.py +11 -7
- {classcore-1.3.1 → classcore-1.4}/sources/classcore/standard/decorators.py +156 -66
- {classcore-1.3.1 → classcore-1.4}/sources/classcore/utilities.py +53 -23
- {classcore-1.3.1 → classcore-1.4}/.gitignore +0 -0
- {classcore-1.3.1 → classcore-1.4}/LICENSE.txt +0 -0
- {classcore-1.3.1 → classcore-1.4}/README.rst +0 -0
- {classcore-1.3.1 → classcore-1.4}/pyproject.toml +0 -0
- {classcore-1.3.1 → classcore-1.4}/sources/classcore/__/__init__.py +0 -0
- {classcore-1.3.1 → classcore-1.4}/sources/classcore/__/doctab.py +0 -0
- {classcore-1.3.1 → classcore-1.4}/sources/classcore/__/imports.py +0 -0
- {classcore-1.3.1 → classcore-1.4}/sources/classcore/__/nomina.py +0 -0
- {classcore-1.3.1 → classcore-1.4}/sources/classcore/factories.py +0 -0
- {classcore-1.3.1 → classcore-1.4}/sources/classcore/nomina.py +0 -0
- {classcore-1.3.1 → classcore-1.4}/sources/classcore/py.typed +0 -0
- {classcore-1.3.1 → classcore-1.4}/sources/classcore/standard/__.py +0 -0
- {classcore-1.3.1 → classcore-1.4}/sources/classcore/standard/__init__.py +0 -0
- {classcore-1.3.1 → classcore-1.4}/sources/classcore/standard/dynadoc.py +0 -0
- {classcore-1.3.1 → classcore-1.4}/sources/classcore/standard/modules.py +0 -0
- {classcore-1.3.1 → classcore-1.4}/sources/classcore/standard/nomina.py +0 -0
|
@@ -75,25 +75,45 @@ def produce_class_construction_decorator(
|
|
|
75
75
|
Decorator overrides ``__new__`` on metaclass.
|
|
76
76
|
'''
|
|
77
77
|
def decorate( clscls: type[ __.T ] ) -> type[ __.T ]:
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
78
|
+
original = __.typx.cast(
|
|
79
|
+
_nomina.ClassConstructorLigation | None,
|
|
80
|
+
clscls.__dict__.get( '__new__' ) ) # pyright: ignore
|
|
81
|
+
|
|
82
|
+
if original is None:
|
|
83
|
+
|
|
84
|
+
def construct_with_super(
|
|
85
|
+
clscls_: type[ __.T ],
|
|
86
|
+
name: str,
|
|
87
|
+
bases: tuple[ type, ... ],
|
|
88
|
+
namespace: dict[ str, __.typx.Any ], *,
|
|
89
|
+
decorators: _nomina.Decorators[ __.T ] = ( ),
|
|
90
|
+
**arguments: __.typx.Any,
|
|
91
|
+
) -> type[ object ]:
|
|
92
|
+
superf = super( clscls, clscls_ ).__new__
|
|
93
|
+
# TODO? Short-circuit if not at start of MRO.
|
|
94
|
+
return constructor(
|
|
95
|
+
clscls_, superf,
|
|
96
|
+
name, bases, namespace, arguments, decorators )
|
|
97
|
+
|
|
98
|
+
setattr( clscls, '__new__', construct_with_super )
|
|
99
|
+
|
|
100
|
+
else:
|
|
101
|
+
|
|
102
|
+
def construct_with_original(
|
|
103
|
+
clscls_: type[ __.T ],
|
|
104
|
+
name: str,
|
|
105
|
+
bases: tuple[ type, ... ],
|
|
106
|
+
namespace: dict[ str, __.typx.Any ], *,
|
|
107
|
+
decorators: _nomina.Decorators[ __.T ] = ( ),
|
|
108
|
+
**arguments: __.typx.Any,
|
|
109
|
+
) -> type[ object ]:
|
|
110
|
+
# TODO? Short-circuit if not at start of MRO.
|
|
111
|
+
return constructor(
|
|
112
|
+
clscls_, original,
|
|
113
|
+
name, bases, namespace, arguments, decorators )
|
|
114
|
+
|
|
115
|
+
setattr( clscls, '__new__', construct_with_original )
|
|
116
|
+
|
|
97
117
|
return clscls
|
|
98
118
|
|
|
99
119
|
return decorate
|
|
@@ -108,20 +128,33 @@ def produce_class_initialization_decorator(
|
|
|
108
128
|
Decorator overrides ``__init__`` on metaclass.
|
|
109
129
|
'''
|
|
110
130
|
def decorate( clscls: type[ __.T ] ) -> type[ __.T ]:
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
131
|
+
original = __.typx.cast(
|
|
132
|
+
_nomina.InitializerLigation | None,
|
|
133
|
+
clscls.__dict__.get( '__init__' ) ) # pyright: ignore
|
|
134
|
+
|
|
135
|
+
if original is None:
|
|
136
|
+
|
|
137
|
+
def initialize_with_super(
|
|
138
|
+
cls: type, *posargs: __.typx.Any, **nomargs: __.typx.Any
|
|
139
|
+
) -> None:
|
|
140
|
+
ligation = super( clscls, cls ).__init__
|
|
141
|
+
# TODO? Short-circuit if not at start of MRO.
|
|
142
|
+
initializer( cls, ligation, posargs, nomargs )
|
|
143
|
+
|
|
144
|
+
clscls.__init__ = initialize_with_super
|
|
145
|
+
|
|
146
|
+
else:
|
|
147
|
+
|
|
148
|
+
@__.funct.wraps( original )
|
|
149
|
+
def initialize_with_original(
|
|
150
|
+
cls: type, *posargs: __.typx.Any, **nomargs: __.typx.Any
|
|
151
|
+
) -> None:
|
|
152
|
+
ligation = __.funct.partial( original, cls )
|
|
153
|
+
# TODO? Short-circuit if not at start of MRO.
|
|
154
|
+
initializer( cls, ligation, posargs, nomargs )
|
|
155
|
+
|
|
156
|
+
clscls.__init__ = initialize_with_original
|
|
157
|
+
|
|
125
158
|
return clscls
|
|
126
159
|
|
|
127
160
|
return decorate
|
|
@@ -26,31 +26,31 @@ from . import standard as _standard
|
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
class Omniexception(
|
|
29
|
-
|
|
29
|
+
_standard.Object, BaseException,
|
|
30
30
|
instances_visibles = ( '__cause__', '__context__' ),
|
|
31
31
|
):
|
|
32
32
|
''' Base exception for package. '''
|
|
33
33
|
|
|
34
34
|
|
|
35
|
-
class Omnierror(
|
|
35
|
+
class Omnierror( Omniexception, Exception ):
|
|
36
36
|
''' Base error for package. '''
|
|
37
37
|
|
|
38
38
|
|
|
39
|
-
class AttributeImmutability(
|
|
39
|
+
class AttributeImmutability( Omnierror, AttributeError ):
|
|
40
40
|
|
|
41
41
|
def __init__( self, name: str, target: str ):
|
|
42
42
|
super( ).__init__(
|
|
43
43
|
f"Could not assign or delete attribute {name!r} on {target}." )
|
|
44
44
|
|
|
45
45
|
|
|
46
|
-
class BehaviorExclusionInvalidity( TypeError, ValueError
|
|
46
|
+
class BehaviorExclusionInvalidity( Omnierror, TypeError, ValueError ):
|
|
47
47
|
|
|
48
48
|
def __init__( self, verifier: __.typx.Any ):
|
|
49
49
|
super( ).__init__(
|
|
50
50
|
f"Invalid behavior exclusion verifier: {verifier!r}" )
|
|
51
51
|
|
|
52
52
|
|
|
53
|
-
class ErrorProvideFailure(
|
|
53
|
+
class ErrorProvideFailure( Omnierror, RuntimeError ):
|
|
54
54
|
|
|
55
55
|
def __init__( self, name: str, reason: str ):
|
|
56
56
|
super( ).__init__(
|
|
@@ -151,6 +151,29 @@ def survey_visible_attributes(
|
|
|
151
151
|
return names_
|
|
152
152
|
|
|
153
153
|
|
|
154
|
+
def augment_class_attributes_allocations(
|
|
155
|
+
attributes_namer: _nomina.AttributesNamer,
|
|
156
|
+
namespace: dict[ str, __.typx.Any ],
|
|
157
|
+
) -> None:
|
|
158
|
+
''' Adds necessary slots for record-keeping attributes. '''
|
|
159
|
+
behaviors_name = attributes_namer( 'instance', 'behaviors' )
|
|
160
|
+
slots: __.typx.Union[
|
|
161
|
+
__.cabc.Mapping[ str, __.typx.Any ],
|
|
162
|
+
__.cabc.Sequence[ str ],
|
|
163
|
+
None
|
|
164
|
+
] = namespace.get( '__slots__' )
|
|
165
|
+
if isinstance( slots, __.cabc.Mapping ):
|
|
166
|
+
slots_ = dict( slots )
|
|
167
|
+
slots_[ behaviors_name ] = 'Active behaviors.'
|
|
168
|
+
slots_ = __.types.MappingProxyType( slots_ )
|
|
169
|
+
elif isinstance( slots, __.cabc.Sequence ):
|
|
170
|
+
slots_ = list( slots )
|
|
171
|
+
slots_.append( behaviors_name )
|
|
172
|
+
slots_ = tuple( slots_ )
|
|
173
|
+
else: return # pragma: no cover
|
|
174
|
+
namespace[ '__slots__' ] = slots_
|
|
175
|
+
|
|
176
|
+
|
|
154
177
|
def classify_behavior_exclusion_verifiers(
|
|
155
178
|
verifiers: _nomina.BehaviorExclusionVerifiers
|
|
156
179
|
) -> tuple[
|
|
@@ -190,6 +213,8 @@ def produce_class_construction_preprocessor(
|
|
|
190
213
|
) -> None:
|
|
191
214
|
record_class_construction_arguments(
|
|
192
215
|
attributes_namer, namespace, arguments )
|
|
216
|
+
if '__slots__' in namespace:
|
|
217
|
+
augment_class_attributes_allocations( attributes_namer, namespace )
|
|
193
218
|
|
|
194
219
|
return preprocess
|
|
195
220
|
|
|
@@ -329,11 +354,11 @@ def record_class_construction_arguments(
|
|
|
329
354
|
arguments_ = { }
|
|
330
355
|
for name in (
|
|
331
356
|
'class_mutables', 'class_visibles',
|
|
357
|
+
'dynadoc_configuration',
|
|
332
358
|
'instances_assigner_core',
|
|
333
359
|
'instances_deleter_core',
|
|
334
360
|
'instances_surveyor_core',
|
|
335
361
|
'instances_mutables', 'instances_visibles',
|
|
336
|
-
'dynadoc_configuration',
|
|
337
362
|
):
|
|
338
363
|
if name not in arguments: continue
|
|
339
364
|
arguments_[ name ] = arguments.pop( name )
|
|
@@ -33,11 +33,15 @@ _class_factory = __.funct.partial(
|
|
|
33
33
|
_decorators.class_factory, dynadoc_configuration = _dynadoc_configuration )
|
|
34
34
|
|
|
35
35
|
|
|
36
|
-
class
|
|
36
|
+
class ClassFactoryExtraArguments( __.typx.TypedDict, total = False ):
|
|
37
|
+
''' Extra arguments accepted by standard metaclasses. '''
|
|
37
38
|
|
|
38
39
|
class_mutables: _nomina.BehaviorExclusionVerifiersOmni
|
|
39
40
|
class_visibles: _nomina.BehaviorExclusionVerifiersOmni
|
|
40
41
|
dynadoc_configuration: _nomina.DynadocConfiguration
|
|
42
|
+
instances_assigner_core: _nomina.AssignerCore
|
|
43
|
+
instances_deleter_core: _nomina.DeleterCore
|
|
44
|
+
instances_surveyor_core: _nomina.SurveyorCore
|
|
41
45
|
instances_mutables: _nomina.BehaviorExclusionVerifiersOmni
|
|
42
46
|
instances_visibles: _nomina.BehaviorExclusionVerifiersOmni
|
|
43
47
|
|
|
@@ -56,7 +60,7 @@ class Class( type ):
|
|
|
56
60
|
bases: tuple[ type, ... ],
|
|
57
61
|
namespace: dict[ str, __.typx.Any ], *,
|
|
58
62
|
decorators: _nomina.Decorators[ __.T ] = ( ),
|
|
59
|
-
**arguments: __.typx.Unpack[
|
|
63
|
+
**arguments: __.typx.Unpack[ ClassFactoryExtraArguments ],
|
|
60
64
|
) -> __.T:
|
|
61
65
|
return super( ).__new__( clscls, name, bases, namespace )
|
|
62
66
|
|
|
@@ -77,7 +81,7 @@ class Dataclass( type ):
|
|
|
77
81
|
bases: tuple[ type, ... ],
|
|
78
82
|
namespace: dict[ str, __.typx.Any ], *,
|
|
79
83
|
decorators: _nomina.Decorators[ __.T ] = ( ),
|
|
80
|
-
**arguments: __.typx.Unpack[
|
|
84
|
+
**arguments: __.typx.Unpack[ ClassFactoryExtraArguments ],
|
|
81
85
|
) -> __.T:
|
|
82
86
|
return super( ).__new__( clscls, name, bases, namespace )
|
|
83
87
|
|
|
@@ -98,7 +102,7 @@ class DataclassMutable( type ):
|
|
|
98
102
|
bases: tuple[ type, ... ],
|
|
99
103
|
namespace: dict[ str, __.typx.Any ], *,
|
|
100
104
|
decorators: _nomina.Decorators[ __.T ] = ( ),
|
|
101
|
-
**arguments: __.typx.Unpack[
|
|
105
|
+
**arguments: __.typx.Unpack[ ClassFactoryExtraArguments ],
|
|
102
106
|
) -> __.T:
|
|
103
107
|
return super( ).__new__( clscls, name, bases, namespace )
|
|
104
108
|
|
|
@@ -118,7 +122,7 @@ class ProtocolClass( type( __.typx.Protocol ) ):
|
|
|
118
122
|
bases: tuple[ type, ... ],
|
|
119
123
|
namespace: dict[ str, __.typx.Any ], *,
|
|
120
124
|
decorators: _nomina.Decorators[ __.T ] = ( ),
|
|
121
|
-
**arguments: __.typx.Unpack[
|
|
125
|
+
**arguments: __.typx.Unpack[ ClassFactoryExtraArguments ],
|
|
122
126
|
) -> __.T:
|
|
123
127
|
return super( ).__new__( clscls, name, bases, namespace )
|
|
124
128
|
|
|
@@ -139,7 +143,7 @@ class ProtocolDataclass( type( __.typx.Protocol ) ):
|
|
|
139
143
|
bases: tuple[ type, ... ],
|
|
140
144
|
namespace: dict[ str, __.typx.Any ], *,
|
|
141
145
|
decorators: _nomina.Decorators[ __.T ] = ( ),
|
|
142
|
-
**arguments: __.typx.Unpack[
|
|
146
|
+
**arguments: __.typx.Unpack[ ClassFactoryExtraArguments ],
|
|
143
147
|
) -> __.T:
|
|
144
148
|
return super( ).__new__( clscls, name, bases, namespace )
|
|
145
149
|
|
|
@@ -161,7 +165,7 @@ class ProtocolDataclassMutable( type( __.typx.Protocol ) ):
|
|
|
161
165
|
bases: tuple[ type, ... ],
|
|
162
166
|
namespace: dict[ str, __.typx.Any ], *,
|
|
163
167
|
decorators: _nomina.Decorators[ __.T ] = ( ),
|
|
164
|
-
**arguments: __.typx.Unpack[
|
|
168
|
+
**arguments: __.typx.Unpack[ ClassFactoryExtraArguments ],
|
|
165
169
|
) -> __.T:
|
|
166
170
|
return super( ).__new__( clscls, name, bases, namespace )
|
|
167
171
|
|
|
@@ -49,6 +49,7 @@ def prepare_dataclass_for_instances(
|
|
|
49
49
|
''' Annotates dataclass in support of instantiation machinery. '''
|
|
50
50
|
annotations = __.inspect.get_annotations( cls )
|
|
51
51
|
behaviors_name = attributes_namer( 'instance', 'behaviors' )
|
|
52
|
+
# TODO? Only use mangling if not slotted.
|
|
52
53
|
behaviors_name_m = _utilities.mangle_name( cls, behaviors_name )
|
|
53
54
|
annotations[ behaviors_name_m ] = set[ str ]
|
|
54
55
|
setattr( cls, '__annotations__', annotations ) # in case of absence
|
|
@@ -89,7 +90,7 @@ def apply_cfc_constructor(
|
|
|
89
90
|
|
|
90
91
|
|
|
91
92
|
def apply_cfc_initializer(
|
|
92
|
-
clscls: type[ __.T ], attributes_namer: _nomina.AttributesNamer
|
|
93
|
+
clscls: type[ __.T ], /, attributes_namer: _nomina.AttributesNamer
|
|
93
94
|
) -> None:
|
|
94
95
|
''' Injects '__init__' method into metaclass. '''
|
|
95
96
|
completers = (
|
|
@@ -112,7 +113,7 @@ def apply_cfc_attributes_assigner(
|
|
|
112
113
|
) -> None:
|
|
113
114
|
''' Injects '__setattr__' method into metaclass. '''
|
|
114
115
|
decorator = produce_attributes_assignment_decorator(
|
|
115
|
-
level = '
|
|
116
|
+
level = 'classes',
|
|
116
117
|
attributes_namer = attributes_namer,
|
|
117
118
|
error_class_provider = error_class_provider,
|
|
118
119
|
implementation_core = implementation_core )
|
|
@@ -127,7 +128,7 @@ def apply_cfc_attributes_deleter(
|
|
|
127
128
|
) -> None:
|
|
128
129
|
''' Injects '__delattr__' method into metaclass. '''
|
|
129
130
|
decorator = produce_attributes_deletion_decorator(
|
|
130
|
-
level = '
|
|
131
|
+
level = 'classes',
|
|
131
132
|
attributes_namer = attributes_namer,
|
|
132
133
|
error_class_provider = error_class_provider,
|
|
133
134
|
implementation_core = implementation_core )
|
|
@@ -141,7 +142,7 @@ def apply_cfc_attributes_surveyor(
|
|
|
141
142
|
) -> None:
|
|
142
143
|
''' Injects '__dir__' method into metaclass. '''
|
|
143
144
|
decorator = produce_attributes_surveillance_decorator(
|
|
144
|
-
level = '
|
|
145
|
+
level = 'classes',
|
|
145
146
|
attributes_namer = attributes_namer,
|
|
146
147
|
implementation_core = implementation_core )
|
|
147
148
|
decorator( clscls )
|
|
@@ -196,13 +197,8 @@ def produce_instances_initialization_decorator(
|
|
|
196
197
|
) -> _nomina.Decorator[ __.U ]:
|
|
197
198
|
''' Produces decorator to inject '__init__' method into class. '''
|
|
198
199
|
def decorate( cls: type[ __.U ] ) -> type[ __.U ]:
|
|
199
|
-
initializer_name = attributes_namer( 'instances', 'initializer' )
|
|
200
|
-
extant = getattr( cls, initializer_name, None )
|
|
201
|
-
original = getattr( cls, '__init__' )
|
|
202
|
-
if extant is original: return cls
|
|
203
200
|
behaviors: set[ str ] = set( )
|
|
204
201
|
behaviors_name = attributes_namer( 'instance', 'behaviors' )
|
|
205
|
-
behaviors_name_m = _utilities.mangle_name( cls, behaviors_name )
|
|
206
202
|
_behaviors.record_behavior(
|
|
207
203
|
cls, attributes_namer = attributes_namer,
|
|
208
204
|
level = 'instances', basename = 'mutables',
|
|
@@ -213,18 +209,41 @@ def produce_instances_initialization_decorator(
|
|
|
213
209
|
level = 'instances', basename = 'visibles',
|
|
214
210
|
label = _nomina.concealment_label, behaviors = behaviors,
|
|
215
211
|
verifiers = visibles )
|
|
212
|
+
original = cls.__dict__.get( '__init__' )
|
|
213
|
+
|
|
214
|
+
if original is None:
|
|
215
|
+
|
|
216
|
+
def initialize_with_super(
|
|
217
|
+
self: object, *posargs: __.typx.Any, **nomargs: __.typx.Any
|
|
218
|
+
) -> None:
|
|
219
|
+
super( cls, self ).__init__( *posargs, **nomargs )
|
|
220
|
+
# Only record behaviors at start of MRO.
|
|
221
|
+
if cls is not type( self ): return
|
|
222
|
+
behaviors_: set[ str ] = (
|
|
223
|
+
_utilities.getattr0( self, behaviors_name, set( ) ) )
|
|
224
|
+
behaviors_.update( behaviors )
|
|
225
|
+
_utilities.setattr0(
|
|
226
|
+
self, behaviors_name, frozenset( behaviors_ ) )
|
|
227
|
+
|
|
228
|
+
cls.__init__ = initialize_with_super
|
|
229
|
+
|
|
230
|
+
else:
|
|
231
|
+
|
|
232
|
+
@__.funct.wraps( original )
|
|
233
|
+
def initialize_with_original(
|
|
234
|
+
self: object, *posargs: __.typx.Any, **nomargs: __.typx.Any
|
|
235
|
+
) -> None:
|
|
236
|
+
original( self, *posargs, **nomargs )
|
|
237
|
+
# Only record behaviors at start of MRO.
|
|
238
|
+
if cls is not type( self ): return
|
|
239
|
+
behaviors_: set[ str ] = (
|
|
240
|
+
_utilities.getattr0( self, behaviors_name, set( ) ) )
|
|
241
|
+
behaviors_.update( behaviors )
|
|
242
|
+
_utilities.setattr0(
|
|
243
|
+
self, behaviors_name, frozenset( behaviors_ ) )
|
|
244
|
+
|
|
245
|
+
cls.__init__ = initialize_with_original
|
|
216
246
|
|
|
217
|
-
@__.funct.wraps( original )
|
|
218
|
-
def initialize(
|
|
219
|
-
self: object, *posargs: __.typx.Any, **nomargs: __.typx.Any
|
|
220
|
-
) -> None:
|
|
221
|
-
original( self, *posargs, **nomargs )
|
|
222
|
-
behaviors_: set[ str ] = getattr( self, behaviors_name_m, set( ) )
|
|
223
|
-
behaviors_.update( behaviors )
|
|
224
|
-
setattr( self, behaviors_name_m, frozenset( behaviors_ ) )
|
|
225
|
-
|
|
226
|
-
setattr( cls, initializer_name, initialize )
|
|
227
|
-
cls.__init__ = initialize
|
|
228
247
|
return cls
|
|
229
248
|
|
|
230
249
|
return decorate
|
|
@@ -238,23 +257,50 @@ def produce_attributes_assignment_decorator(
|
|
|
238
257
|
) -> _nomina.Decorator[ __.U ]:
|
|
239
258
|
''' Produces decorator to inject '__setattr__' method into class. '''
|
|
240
259
|
def decorate( cls: type[ __.U ] ) -> type[ __.U ]:
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
if
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
self
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
260
|
+
leveli = 'class' if level == 'classes' else level
|
|
261
|
+
original = cls.__dict__.get( '__setattr__' )
|
|
262
|
+
|
|
263
|
+
if original is None:
|
|
264
|
+
|
|
265
|
+
def assign_with_super(
|
|
266
|
+
self: object, name: str, value: __.typx.Any
|
|
267
|
+
) -> None:
|
|
268
|
+
ligation = super( cls, self ).__setattr__
|
|
269
|
+
# Only enforce behaviors at start of MRO.
|
|
270
|
+
if cls is not type( self ):
|
|
271
|
+
ligation( name, value )
|
|
272
|
+
return
|
|
273
|
+
implementation_core(
|
|
274
|
+
self,
|
|
275
|
+
ligation = ligation,
|
|
276
|
+
attributes_namer = attributes_namer,
|
|
277
|
+
error_class_provider = error_class_provider,
|
|
278
|
+
level = leveli,
|
|
279
|
+
name = name, value = value )
|
|
280
|
+
|
|
281
|
+
cls.__setattr__ = assign_with_super
|
|
282
|
+
|
|
283
|
+
else:
|
|
284
|
+
|
|
285
|
+
@__.funct.wraps( original )
|
|
286
|
+
def assign_with_original(
|
|
287
|
+
self: object, name: str, value: __.typx.Any
|
|
288
|
+
) -> None:
|
|
289
|
+
ligation = __.funct.partial( original, self )
|
|
290
|
+
# Only enforce behaviors at start of MRO.
|
|
291
|
+
if cls is not type( self ):
|
|
292
|
+
ligation( name, value )
|
|
293
|
+
return
|
|
294
|
+
implementation_core(
|
|
295
|
+
self,
|
|
296
|
+
ligation = ligation,
|
|
297
|
+
attributes_namer = attributes_namer,
|
|
298
|
+
error_class_provider = error_class_provider,
|
|
299
|
+
level = leveli,
|
|
300
|
+
name = name, value = value )
|
|
301
|
+
|
|
302
|
+
cls.__setattr__ = assign_with_original
|
|
255
303
|
|
|
256
|
-
setattr( cls, assigner_name, assign )
|
|
257
|
-
cls.__setattr__ = assign
|
|
258
304
|
return cls
|
|
259
305
|
|
|
260
306
|
return decorate
|
|
@@ -268,23 +314,46 @@ def produce_attributes_deletion_decorator(
|
|
|
268
314
|
) -> _nomina.Decorator[ __.U ]:
|
|
269
315
|
''' Produces decorator to inject '__delattr__' method into class. '''
|
|
270
316
|
def decorate( cls: type[ __.U ] ) -> type[ __.U ]:
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
if
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
self
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
317
|
+
leveli = 'class' if level == 'classes' else level
|
|
318
|
+
original = cls.__dict__.get( '__delattr__' )
|
|
319
|
+
|
|
320
|
+
if original is None:
|
|
321
|
+
|
|
322
|
+
def delete_with_super( self: object, name: str ) -> None:
|
|
323
|
+
ligation = super( cls, self ).__delattr__
|
|
324
|
+
# Only enforce behaviors at start of MRO.
|
|
325
|
+
if cls is not type( self ):
|
|
326
|
+
ligation( name )
|
|
327
|
+
return
|
|
328
|
+
implementation_core(
|
|
329
|
+
self,
|
|
330
|
+
ligation = ligation,
|
|
331
|
+
attributes_namer = attributes_namer,
|
|
332
|
+
error_class_provider = error_class_provider,
|
|
333
|
+
level = leveli,
|
|
334
|
+
name = name )
|
|
335
|
+
|
|
336
|
+
cls.__delattr__ = delete_with_super
|
|
337
|
+
|
|
338
|
+
else:
|
|
339
|
+
|
|
340
|
+
@__.funct.wraps( original )
|
|
341
|
+
def delete_with_original( self: object, name: str ) -> None:
|
|
342
|
+
ligation = __.funct.partial( original, self )
|
|
343
|
+
# Only enforce behaviors at start of MRO.
|
|
344
|
+
if cls is not type( self ):
|
|
345
|
+
ligation( name )
|
|
346
|
+
return
|
|
347
|
+
implementation_core(
|
|
348
|
+
self,
|
|
349
|
+
ligation = ligation,
|
|
350
|
+
attributes_namer = attributes_namer,
|
|
351
|
+
error_class_provider = error_class_provider,
|
|
352
|
+
level = leveli,
|
|
353
|
+
name = name )
|
|
354
|
+
|
|
355
|
+
cls.__delattr__ = delete_with_original
|
|
285
356
|
|
|
286
|
-
setattr( cls, deleter_name, delete )
|
|
287
|
-
cls.__delattr__ = delete
|
|
288
357
|
return cls
|
|
289
358
|
|
|
290
359
|
return decorate
|
|
@@ -297,21 +366,42 @@ def produce_attributes_surveillance_decorator(
|
|
|
297
366
|
) -> _nomina.Decorator[ __.U ]:
|
|
298
367
|
''' Produces decorator to inject '__dir__' method into class. '''
|
|
299
368
|
def decorate( cls: type[ __.U ] ) -> type[ __.U ]:
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
if
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
self
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
369
|
+
leveli = 'class' if level == 'classes' else level
|
|
370
|
+
original = cls.__dict__.get( '__dir__' )
|
|
371
|
+
|
|
372
|
+
if original is None:
|
|
373
|
+
|
|
374
|
+
def survey_with_super(
|
|
375
|
+
self: object
|
|
376
|
+
) -> __.cabc.Iterable[ str ]:
|
|
377
|
+
ligation = super( cls, self ).__dir__
|
|
378
|
+
# Only enforce behaviors at start of MRO.
|
|
379
|
+
if cls is not type( self ): return ligation( )
|
|
380
|
+
return implementation_core(
|
|
381
|
+
self,
|
|
382
|
+
ligation = ligation,
|
|
383
|
+
attributes_namer = attributes_namer,
|
|
384
|
+
level = leveli )
|
|
385
|
+
|
|
386
|
+
cls.__dir__ = survey_with_super
|
|
387
|
+
|
|
388
|
+
else:
|
|
389
|
+
|
|
390
|
+
@__.funct.wraps( original )
|
|
391
|
+
def survey_with_original(
|
|
392
|
+
self: object
|
|
393
|
+
) -> __.cabc.Iterable[ str ]:
|
|
394
|
+
ligation = __.funct.partial( original, self )
|
|
395
|
+
# Only enforce behaviors at start of MRO.
|
|
396
|
+
if cls is not type( self ): return ligation( )
|
|
397
|
+
return implementation_core(
|
|
398
|
+
self,
|
|
399
|
+
ligation = ligation,
|
|
400
|
+
attributes_namer = attributes_namer,
|
|
401
|
+
level = leveli )
|
|
402
|
+
|
|
403
|
+
cls.__dir__ = survey_with_original
|
|
312
404
|
|
|
313
|
-
setattr( cls, surveyor_name, survey )
|
|
314
|
-
cls.__dir__ = survey
|
|
315
405
|
return cls
|
|
316
406
|
|
|
317
407
|
return decorate
|
|
@@ -24,51 +24,81 @@
|
|
|
24
24
|
from . import __
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
def describe_object(
|
|
27
|
+
def describe_object( objct: object, / ) -> str:
|
|
28
28
|
''' Returns object type with fully-qualified name. '''
|
|
29
|
-
if __.inspect.isclass(
|
|
30
|
-
return "class '{}'".format( qualify_class_name(
|
|
29
|
+
if __.inspect.isclass( objct ):
|
|
30
|
+
return "class '{}'".format( qualify_class_name( objct ) )
|
|
31
31
|
# TODO? functions, methods, etc...
|
|
32
|
-
return "instance of {}".format( describe_object( type(
|
|
32
|
+
return "instance of {}".format( describe_object( type( objct ) ) )
|
|
33
33
|
|
|
34
34
|
|
|
35
|
-
def getattr0(
|
|
36
|
-
|
|
35
|
+
def getattr0(
|
|
36
|
+
objct: object, /, name: str, default: __.typx.Any
|
|
37
|
+
) -> __.typx.Any:
|
|
38
|
+
''' Returns special private attribute from object.
|
|
37
39
|
|
|
38
|
-
|
|
40
|
+
This avoids inheritance-related collisions.
|
|
41
|
+
|
|
42
|
+
Uses mangled attribute name which is unique to the class,
|
|
43
|
+
except when attribute is slotted. Slotted attributes are effectively
|
|
44
|
+
isolated from inheritance.
|
|
39
45
|
'''
|
|
40
|
-
|
|
41
|
-
|
|
46
|
+
if not __.inspect.isclass( objct ):
|
|
47
|
+
for base in type( objct ).mro( ):
|
|
48
|
+
slots = getattr( base, '__slots__', ( ) )
|
|
49
|
+
if name in slots: return getattr( objct, name, default )
|
|
50
|
+
name_m = mangle_name( objct, name )
|
|
51
|
+
return getattr( objct, name_m, default )
|
|
52
|
+
|
|
42
53
|
|
|
54
|
+
def delattr0( objct: object, /, name: str ) -> None:
|
|
55
|
+
''' Deletes special private attribute on object.
|
|
43
56
|
|
|
44
|
-
|
|
45
|
-
''' Deletes private attribute on object.
|
|
57
|
+
This avoids inheritance-related collisions.
|
|
46
58
|
|
|
47
|
-
Uses mangled attribute name which is unique to the class
|
|
59
|
+
Uses mangled attribute name which is unique to the class,
|
|
60
|
+
except when attribute is slotted. Slotted attributes are effectively
|
|
61
|
+
isolated from inheritance.
|
|
48
62
|
'''
|
|
49
|
-
|
|
50
|
-
|
|
63
|
+
if not __.inspect.isclass( objct ):
|
|
64
|
+
for base in type( objct ).mro( ):
|
|
65
|
+
slots = getattr( base, '__slots__', ( ) )
|
|
66
|
+
if name in slots:
|
|
67
|
+
delattr( objct, name )
|
|
68
|
+
return
|
|
69
|
+
name_m = mangle_name( objct, name )
|
|
70
|
+
delattr( objct, name_m )
|
|
71
|
+
|
|
51
72
|
|
|
73
|
+
def setattr0( objct: object, /, name: str, value: __.typx.Any ) -> None:
|
|
74
|
+
''' Assigns special private attribute to object.
|
|
52
75
|
|
|
53
|
-
|
|
54
|
-
''' Assigns private attribute to object.
|
|
76
|
+
This avoids inheritance-related collisions.
|
|
55
77
|
|
|
56
|
-
Uses mangled attribute name which is unique to the class
|
|
78
|
+
Uses mangled attribute name which is unique to the class,
|
|
79
|
+
except when attribute is slotted. Slotted attributes are effectively
|
|
80
|
+
isolated from inheritance.
|
|
57
81
|
'''
|
|
58
|
-
|
|
59
|
-
|
|
82
|
+
if not __.inspect.isclass( objct ):
|
|
83
|
+
for base in type( objct ).mro( ):
|
|
84
|
+
slots = getattr( base, '__slots__', ( ) )
|
|
85
|
+
if name in slots:
|
|
86
|
+
setattr( objct, name, value )
|
|
87
|
+
return
|
|
88
|
+
name_m = mangle_name( objct, name )
|
|
89
|
+
setattr( objct, name_m, value )
|
|
60
90
|
|
|
61
91
|
|
|
62
|
-
def mangle_name(
|
|
92
|
+
def mangle_name( objct: object, /, name: str ) -> str:
|
|
63
93
|
''' Mangles attribute name so that it is unique.
|
|
64
94
|
|
|
65
95
|
Effectively provides name of private member attribute,
|
|
66
96
|
which is unique across class inheritance.
|
|
67
97
|
'''
|
|
68
|
-
if not __.inspect.isclass(
|
|
69
|
-
return mangle_name( type(
|
|
98
|
+
if not __.inspect.isclass( objct ):
|
|
99
|
+
return mangle_name( type( objct ), name )
|
|
70
100
|
namehash = __.hashlib.sha256( )
|
|
71
|
-
namehash.update( qualify_class_name(
|
|
101
|
+
namehash.update( qualify_class_name( objct ).encode( ) )
|
|
72
102
|
namehash_hex = namehash.hexdigest( )
|
|
73
103
|
return f"{name}_{namehash_hex}"
|
|
74
104
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|