classcore 1.11__tar.gz → 1.12__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.11 → classcore-1.12}/PKG-INFO +2 -2
- {classcore-1.11 → classcore-1.12}/pyproject.toml +1 -0
- {classcore-1.11 → classcore-1.12}/sources/classcore/README.md +12 -7
- {classcore-1.11 → classcore-1.12}/sources/classcore/__/imports.py +1 -0
- {classcore-1.11 → classcore-1.12}/sources/classcore/__init__.py +1 -1
- {classcore-1.11 → classcore-1.12}/sources/classcore/decorators.py +23 -5
- {classcore-1.11 → classcore-1.12}/sources/classcore/factories.py +1 -1
- {classcore-1.11 → classcore-1.12}/sources/classcore/nomina.py +36 -13
- {classcore-1.11 → classcore-1.12}/sources/classcore/standard/README.md +31 -17
- {classcore-1.11 → classcore-1.12}/sources/classcore/standard/behaviors.py +1 -1
- {classcore-1.11 → classcore-1.12}/sources/classcore/standard/classes.py +178 -6
- {classcore-1.11 → classcore-1.12}/sources/classcore/standard/decorators.py +5 -5
- {classcore-1.11 → classcore-1.12}/.gitignore +0 -0
- {classcore-1.11 → classcore-1.12}/LICENSE.txt +0 -0
- {classcore-1.11 → classcore-1.12}/README.rst +0 -0
- {classcore-1.11 → classcore-1.12}/sources/classcore/__/__init__.py +0 -0
- {classcore-1.11 → classcore-1.12}/sources/classcore/__/doctab.py +0 -0
- {classcore-1.11 → classcore-1.12}/sources/classcore/__/nomina.py +0 -0
- {classcore-1.11 → classcore-1.12}/sources/classcore/exceptions.py +0 -0
- {classcore-1.11 → classcore-1.12}/sources/classcore/py.typed +0 -0
- {classcore-1.11 → classcore-1.12}/sources/classcore/standard/__.py +0 -0
- {classcore-1.11 → classcore-1.12}/sources/classcore/standard/__init__.py +0 -0
- {classcore-1.11 → classcore-1.12}/sources/classcore/standard/dynadoc.py +0 -0
- {classcore-1.11 → classcore-1.12}/sources/classcore/standard/modules.py +0 -0
- {classcore-1.11 → classcore-1.12}/sources/classcore/standard/nomina.py +0 -0
- {classcore-1.11 → classcore-1.12}/sources/classcore/utilities.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: classcore
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.12
|
|
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
|
|
@@ -83,19 +83,20 @@ Pre-configured implementations for common use cases:
|
|
|
83
83
|
**Base Classes:**
|
|
84
84
|
- `Object`: Standard class with immutability and concealment
|
|
85
85
|
- `DataclassObject`: Automatic dataclass conversion with standard behaviors
|
|
86
|
-
- `
|
|
86
|
+
- `Protocol`: Protocol base class with immutability and concealment
|
|
87
|
+
- `AbstractObject`: Abstract class with ABC machinery and behaviors
|
|
87
88
|
- Variants for selective mutability (`ObjectMutable`, etc.)
|
|
88
89
|
|
|
89
90
|
**Metaclasses:**
|
|
90
91
|
- `Class`: Metaclass for standard classes
|
|
91
92
|
- `Dataclass`: Metaclass that auto-applies dataclass decorator
|
|
92
|
-
- `
|
|
93
|
+
- `AbstractClass`: Metaclass combining `Class` with `abc.ABCMeta`
|
|
94
|
+
- `ProtocolClass`: Metaclass for protocol classes
|
|
93
95
|
- Mutable variants of each
|
|
94
96
|
|
|
95
97
|
**Decorators:**
|
|
96
|
-
- `
|
|
98
|
+
- `with_standard_behaviors`: Add behaviors to existing classes
|
|
97
99
|
- `dataclass_with_standard_behaviors`: Dataclass creation with behaviors
|
|
98
|
-
- `protocol_with_standard_behaviors`: Protocol creation with behaviors
|
|
99
100
|
|
|
100
101
|
**Module Utilities:**
|
|
101
102
|
- `reclassify_module`: Apply immutability and concealment to module objects
|
|
@@ -381,16 +382,20 @@ sources/
|
|
|
381
382
|
: Standard metaclasses and base classes:
|
|
382
383
|
|
|
383
384
|
- `Class` / `Object`: Standard class with full behaviors
|
|
385
|
+
- `AbstractClass` / `AbstractObject`: Abstract class with ABC machinery
|
|
386
|
+
(abstract method enforcement, virtual subclass registration); mixes
|
|
387
|
+
with external `abc.ABCMeta`-based classes
|
|
384
388
|
- `Dataclass` / `DataclassObject`: Auto-dataclass with behaviors
|
|
385
|
-
- `
|
|
389
|
+
- `ProtocolClass` / `Protocol`, `ProtocolMutable`,
|
|
390
|
+
`DataclassProtocol`, `DataclassProtocolMutable`: Protocol classes
|
|
391
|
+
with behaviors
|
|
386
392
|
- Mutable variants for each
|
|
387
393
|
|
|
388
394
|
`decorators.py`
|
|
389
395
|
: Standard class decorators:
|
|
390
396
|
|
|
391
|
-
- `
|
|
397
|
+
- `with_standard_behaviors`: Apply behaviors to existing class
|
|
392
398
|
- `dataclass_with_standard_behaviors`: Create dataclass with behaviors
|
|
393
|
-
- `protocol_with_standard_behaviors`: Create protocol with behaviors
|
|
394
399
|
- `class_factory`: Generic factory for creating custom metaclasses
|
|
395
400
|
|
|
396
401
|
`dynadoc.py`
|
|
@@ -89,8 +89,14 @@ def produce_class_construction_decorator(
|
|
|
89
89
|
decorators: _nomina.Decorators[ __.T ] = ( ),
|
|
90
90
|
**arguments: __.typx.Any,
|
|
91
91
|
) -> type[ object ]:
|
|
92
|
-
superf =
|
|
93
|
-
|
|
92
|
+
superf = __.typx.cast(
|
|
93
|
+
_nomina.ClassConstructorLigation,
|
|
94
|
+
super( clscls, clscls_ ).__new__ )
|
|
95
|
+
if clscls is not clscls_:
|
|
96
|
+
# Parent metaclass within a hierarchy: delegate without
|
|
97
|
+
# duplicating preprocessing or decoration.
|
|
98
|
+
return superf(
|
|
99
|
+
clscls_, name, bases, namespace, **arguments )
|
|
94
100
|
return constructor(
|
|
95
101
|
clscls_, superf,
|
|
96
102
|
name, bases, namespace, arguments, decorators )
|
|
@@ -107,7 +113,11 @@ def produce_class_construction_decorator(
|
|
|
107
113
|
decorators: _nomina.Decorators[ __.T ] = ( ),
|
|
108
114
|
**arguments: __.typx.Any,
|
|
109
115
|
) -> type[ object ]:
|
|
110
|
-
|
|
116
|
+
if clscls is not clscls_:
|
|
117
|
+
# Parent metaclass within a hierarchy: delegate without
|
|
118
|
+
# duplicating preprocessing or decoration.
|
|
119
|
+
return original(
|
|
120
|
+
clscls_, name, bases, namespace, **arguments )
|
|
111
121
|
return constructor(
|
|
112
122
|
clscls_, original,
|
|
113
123
|
name, bases, namespace, arguments, decorators )
|
|
@@ -138,7 +148,11 @@ def produce_class_initialization_decorator(
|
|
|
138
148
|
cls: type, *posargs: __.typx.Any, **nomargs: __.typx.Any
|
|
139
149
|
) -> None:
|
|
140
150
|
ligation = super( clscls, cls ).__init__
|
|
141
|
-
|
|
151
|
+
if clscls is not type( cls ):
|
|
152
|
+
# Parent metaclass within a hierarchy: delegate without
|
|
153
|
+
# duplicating completion logic.
|
|
154
|
+
ligation( *posargs, **nomargs )
|
|
155
|
+
return
|
|
142
156
|
initializer( cls, ligation, posargs, nomargs )
|
|
143
157
|
|
|
144
158
|
clscls.__init__ = initialize_with_super
|
|
@@ -149,8 +163,12 @@ def produce_class_initialization_decorator(
|
|
|
149
163
|
def initialize_with_original(
|
|
150
164
|
cls: type, *posargs: __.typx.Any, **nomargs: __.typx.Any
|
|
151
165
|
) -> None:
|
|
166
|
+
if clscls is not type( cls ):
|
|
167
|
+
# Parent metaclass within a hierarchy: delegate without
|
|
168
|
+
# duplicating completion logic.
|
|
169
|
+
original( cls, *posargs, **nomargs )
|
|
170
|
+
return
|
|
152
171
|
ligation = __.funct.partial( original, cls )
|
|
153
|
-
# TODO? Short-circuit if not at start of MRO.
|
|
154
172
|
initializer( cls, ligation, posargs, nomargs )
|
|
155
173
|
|
|
156
174
|
clscls.__init__ = initialize_with_original
|
|
@@ -34,7 +34,7 @@ def produce_class_constructor(
|
|
|
34
34
|
) -> _nomina.ClassConstructor[ __.T ]:
|
|
35
35
|
''' Produces constructors for classes. '''
|
|
36
36
|
|
|
37
|
-
def construct( # noqa: PLR0913
|
|
37
|
+
def construct( # noqa: PLR0913, PLR0917
|
|
38
38
|
clscls: type[ __.T ],
|
|
39
39
|
superf: _nomina.ClassConstructorLigation,
|
|
40
40
|
name: str,
|
|
@@ -214,29 +214,52 @@ ClassInitializationCompleters: __.typx.TypeAlias = __.typx.Annotated[
|
|
|
214
214
|
ClassConstructor: __.typx.TypeAlias = __.typx.Annotated[
|
|
215
215
|
__.cabc.Callable[
|
|
216
216
|
[
|
|
217
|
-
type,
|
|
218
|
-
ClassConstructorLigation,
|
|
219
|
-
str,
|
|
220
|
-
tuple[ type, ... ],
|
|
221
|
-
dict[ str, __.typx.Any ],
|
|
222
|
-
__.NominativeArguments,
|
|
223
|
-
Decorators[ __.U ],
|
|
217
|
+
type, # metaclass
|
|
218
|
+
ClassConstructorLigation, # next constructor in metaclass MRO
|
|
219
|
+
str, # class name
|
|
220
|
+
tuple[ type, ... ], # bases
|
|
221
|
+
dict[ str, __.typx.Any ], # namespace
|
|
222
|
+
__.NominativeArguments, # metaclass arguments
|
|
223
|
+
Decorators[ __.U ], # decorators to apply after
|
|
224
224
|
],
|
|
225
225
|
type
|
|
226
226
|
],
|
|
227
|
-
__.ddoc.Doc(
|
|
227
|
+
__.ddoc.Doc(
|
|
228
|
+
''' Constructs class, then applies hooks.
|
|
229
|
+
|
|
230
|
+
Receives the metaclass ('clscls'), the next constructor in
|
|
231
|
+
the metaclass MRO ('superf'), the class name, bases,
|
|
232
|
+
namespace, metaclass arguments, and decorators to apply
|
|
233
|
+
after construction. Calls 'superf' to create the class,
|
|
234
|
+
then applies postprocessors and decorators.
|
|
235
|
+
|
|
236
|
+
Invoked only at the most-derived metaclass of a class.
|
|
237
|
+
Class factory wrappers on parent metaclasses delegate
|
|
238
|
+
directly, so construction hooks execute exactly once per
|
|
239
|
+
class.
|
|
240
|
+
''' ),
|
|
228
241
|
]
|
|
229
242
|
ClassInitializer: __.typx.TypeAlias = __.typx.Annotated[
|
|
230
243
|
__.cabc.Callable[
|
|
231
244
|
[
|
|
232
|
-
type,
|
|
233
|
-
InitializerLigation,
|
|
234
|
-
__.PositionalArguments,
|
|
235
|
-
__.NominativeArguments,
|
|
245
|
+
type, # class
|
|
246
|
+
InitializerLigation, # next initializer in metaclass MRO
|
|
247
|
+
__.PositionalArguments, # positional arguments
|
|
248
|
+
__.NominativeArguments, # nominative arguments
|
|
236
249
|
],
|
|
237
250
|
None
|
|
238
251
|
],
|
|
239
|
-
__.ddoc.Doc(
|
|
252
|
+
__.ddoc.Doc(
|
|
253
|
+
''' Initializes class, then applies hooks.
|
|
254
|
+
|
|
255
|
+
Receives the class ('cls'), the next initializer in the
|
|
256
|
+
metaclass MRO ('superf'), positional arguments, and
|
|
257
|
+
nominative arguments. Calls 'superf' first, then applies
|
|
258
|
+
completers, which finalize class behaviors (e.g., enable
|
|
259
|
+
immutability once all other initialization has occurred).
|
|
260
|
+
|
|
261
|
+
Invoked only at the most-derived metaclass of a class.
|
|
262
|
+
''' ),
|
|
240
263
|
]
|
|
241
264
|
|
|
242
265
|
|
|
@@ -40,17 +40,27 @@ class Point2d(DataclassObject):
|
|
|
40
40
|
self.hypotenuse = sqrt(x*x + y*y)
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
### `
|
|
43
|
+
### `Protocol`
|
|
44
|
+
|
|
45
|
+
Protocol base class with immutability and concealment. Combines
|
|
46
|
+
`typing.Protocol` with standard behaviors. Immutability and concealment
|
|
47
|
+
are inherited by subclassed implementations. Dataclass protocol bases
|
|
48
|
+
(`DataclassProtocol`, `DataclassProtocolMutable`) additionally provide
|
|
49
|
+
automatic dataclass conversion.
|
|
44
50
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
51
|
+
### `AbstractObject`
|
|
52
|
+
|
|
53
|
+
Abstract base class with immutability and concealment. Combines standard
|
|
54
|
+
behaviors with `abc.ABCMeta` machinery: abstract method enforcement and
|
|
55
|
+
virtual subclass registration. Mixes with external ABC-based classes
|
|
56
|
+
without metaclass conflicts.
|
|
48
57
|
|
|
49
58
|
### Mutable Variants
|
|
50
59
|
|
|
51
60
|
- `ObjectMutable`: Object with concealment only (no immutability)
|
|
52
61
|
- `DataclassObjectMutable`: DataclassObject with concealment only
|
|
53
|
-
- `
|
|
62
|
+
- `ProtocolMutable`: Protocol with concealment only
|
|
63
|
+
- `DataclassProtocolMutable`: DataclassProtocol with concealment only
|
|
54
64
|
|
|
55
65
|
## Metaclasses
|
|
56
66
|
|
|
@@ -64,27 +74,35 @@ any class that uses this metaclass.
|
|
|
64
74
|
Metaclass that automatically applies `dataclasses.dataclass` during class
|
|
65
75
|
construction. Configurable for `frozen`, `slots`, etc.
|
|
66
76
|
|
|
67
|
-
### `
|
|
77
|
+
### `AbstractClass`
|
|
78
|
+
|
|
79
|
+
Metaclass combining `Class` with `abc.ABCMeta`. Supports abstract method
|
|
80
|
+
enforcement and virtual subclass registration for classes that must mix
|
|
81
|
+
with external ABC-based classes.
|
|
82
|
+
|
|
83
|
+
### `ProtocolClass`
|
|
68
84
|
|
|
69
85
|
Metaclass for protocol classes. Combines `typing.Protocol` with standard
|
|
70
|
-
behaviors.
|
|
86
|
+
behaviors. Descends from `AbstractClass`, unifying the standard metaclass
|
|
87
|
+
taxonomy under `Class`. Dataclass protocol metaclasses
|
|
88
|
+
(`ProtocolDataclass`, `ProtocolDataclassMutable`) additionally apply
|
|
89
|
+
dataclass conversion.
|
|
71
90
|
|
|
72
91
|
### Mutable Variants
|
|
73
92
|
|
|
74
|
-
- `
|
|
75
|
-
|
|
76
|
-
- `ProtocolMutable`: Protocol metaclass with concealment only
|
|
93
|
+
- `DataclassMutable`: Dataclass metaclass whose instances have mutable
|
|
94
|
+
attributes (concealment only)
|
|
77
95
|
|
|
78
96
|
## Decorators
|
|
79
97
|
|
|
80
|
-
### `
|
|
98
|
+
### `with_standard_behaviors`
|
|
81
99
|
|
|
82
100
|
Apply standard behaviors to an existing class.
|
|
83
101
|
|
|
84
102
|
```python
|
|
85
|
-
from classcore.standard import
|
|
103
|
+
from classcore.standard import with_standard_behaviors
|
|
86
104
|
|
|
87
|
-
@
|
|
105
|
+
@with_standard_behaviors()
|
|
88
106
|
class ExistingClass:
|
|
89
107
|
x: int = 10
|
|
90
108
|
```
|
|
@@ -102,10 +120,6 @@ class Point:
|
|
|
102
120
|
y: float
|
|
103
121
|
```
|
|
104
122
|
|
|
105
|
-
### `protocol_with_standard_behaviors`
|
|
106
|
-
|
|
107
|
-
Create a protocol with standard behaviors applied.
|
|
108
|
-
|
|
109
123
|
### `class_factory`
|
|
110
124
|
|
|
111
125
|
Generic factory for creating custom metaclasses with standard behaviors.
|
|
@@ -224,7 +224,7 @@ def produce_class_construction_preprocessor(
|
|
|
224
224
|
) -> _nomina.ClassConstructionPreprocessor[ __.U ]:
|
|
225
225
|
''' Produces construction processor which handles metaclass arguments. '''
|
|
226
226
|
|
|
227
|
-
def preprocess( # noqa: PLR0913
|
|
227
|
+
def preprocess( # noqa: PLR0913, PLR0917
|
|
228
228
|
clscls: type,
|
|
229
229
|
name: str,
|
|
230
230
|
bases: list[ type ],
|
|
@@ -32,7 +32,56 @@ _abc_class_mutables = (
|
|
|
32
32
|
'_abc_negative_cache',
|
|
33
33
|
'_abc_negative_cache_version',
|
|
34
34
|
'_abc_registry',
|
|
35
|
+
'_is_runtime_protocol',
|
|
36
|
+
'__non_callable_proto_members__',
|
|
35
37
|
)
|
|
38
|
+
_protocol_cls_set = frozenset( { __.typx.Protocol } )
|
|
39
|
+
# Attributes never considered declared protocol members: typing internals,
|
|
40
|
+
# class-creation machinery, and framework attributes declared in classcore
|
|
41
|
+
# base class bodies.
|
|
42
|
+
_protocol_attr_excluded = frozenset( {
|
|
43
|
+
'_is_protocol', '_is_runtime_protocol',
|
|
44
|
+
'__protocol_attrs__', '__subclasshook__',
|
|
45
|
+
'__non_callable_proto_members__',
|
|
46
|
+
'_dynadoc_fragments_',
|
|
47
|
+
# Injected during class creation by ABC, Generic, and typing machinery.
|
|
48
|
+
# '__init__' is '_no_init' on protocol bases; as a structural member it
|
|
49
|
+
# is vacuous since every candidate object has an '__init__'.
|
|
50
|
+
'__abstractmethods__', '__parameters__', '__init__', '__orig_bases__',
|
|
51
|
+
} )
|
|
52
|
+
_protocol_attr_prefixes = ( '_classcore_', '_abc_' )
|
|
53
|
+
# Standard Python attributes present in every pre-decoration namespace.
|
|
54
|
+
_python_class_defaults = frozenset( {
|
|
55
|
+
'__module__', '__qualname__', '__doc__', '__dict__', '__weakref__',
|
|
56
|
+
'__slots__', '__annotations__',
|
|
57
|
+
'__firstlineno__', '__static_attributes__', # Python 3.13+
|
|
58
|
+
} )
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _snapshot_declared_protocol_attrs( cls: type ) -> None:
|
|
62
|
+
''' Records protocol members declared before framework decoration.
|
|
63
|
+
|
|
64
|
+
Called in metaclass '__new__' immediately after class creation,
|
|
65
|
+
before behavior decorators and dataclass machinery inject their
|
|
66
|
+
attributes. The pre-decoration namespace contains exactly the
|
|
67
|
+
members declared by the author, so a user-declared dunder (e.g.,
|
|
68
|
+
'__repr__') is preserved while framework-generated ones are absent.
|
|
69
|
+
'''
|
|
70
|
+
# Dataclass slot machinery reproduces classes, copying '__dict__'.
|
|
71
|
+
# Retain the original snapshot; the reproduction's namespace already
|
|
72
|
+
# contains decorated attributes.
|
|
73
|
+
if '_classcore_protocol_declared_' in cls.__dict__: return
|
|
74
|
+
declared = (
|
|
75
|
+
set( cls.__dict__ )
|
|
76
|
+
| set( __.inspect.get_annotations( cls ) ) )
|
|
77
|
+
declared -= _python_class_defaults
|
|
78
|
+
declared = {
|
|
79
|
+
attr for attr in declared
|
|
80
|
+
if attr not in _protocol_attr_excluded
|
|
81
|
+
and not any( attr.startswith( p ) for p in _protocol_attr_prefixes )
|
|
82
|
+
}
|
|
83
|
+
setattr( cls, '_classcore_protocol_declared_', frozenset( declared ) )
|
|
84
|
+
|
|
36
85
|
_dynadoc_configuration = (
|
|
37
86
|
_dynadoc.produce_dynadoc_configuration( table = __.fragments ) )
|
|
38
87
|
_class_factory = __.funct.partial(
|
|
@@ -72,9 +121,35 @@ class Class( type ):
|
|
|
72
121
|
return super( ).__new__( clscls, name, bases, namespace )
|
|
73
122
|
|
|
74
123
|
|
|
124
|
+
@_class_factory( )
|
|
125
|
+
class AbstractClass( Class, __.abc.ABCMeta ):
|
|
126
|
+
''' Metaclass for abstract classes with standard behaviors.
|
|
127
|
+
|
|
128
|
+
Combines the standard behaviors of `Class` with the machinery of
|
|
129
|
+
`abc.ABCMeta` (abstract method enforcement, virtual subclass
|
|
130
|
+
registration) via a diamond hierarchy. `Class` itself remains
|
|
131
|
+
backed by plain `type`, so ABC machinery applies only where this
|
|
132
|
+
metaclass is used.
|
|
133
|
+
'''
|
|
134
|
+
|
|
135
|
+
_dynadoc_fragments_ = (
|
|
136
|
+
'cfc class conceal', 'cfc class protect', 'cfc dynadoc',
|
|
137
|
+
'cfc instance conceal', 'cfc instance protect' )
|
|
138
|
+
|
|
139
|
+
def __new__( # Typechecker stub.
|
|
140
|
+
clscls: type[ __.T ],
|
|
141
|
+
name: str,
|
|
142
|
+
bases: tuple[ type, ... ],
|
|
143
|
+
namespace: dict[ str, __.typx.Any ], *,
|
|
144
|
+
decorators: _nomina.Decorators[ __.T ] = ( ),
|
|
145
|
+
**arguments: __.typx.Unpack[ ClassFactoryExtraArguments ],
|
|
146
|
+
) -> __.T:
|
|
147
|
+
return super( ).__new__( clscls, name, bases, namespace )
|
|
148
|
+
|
|
149
|
+
|
|
75
150
|
@_class_factory( )
|
|
76
151
|
@__.typx.dataclass_transform( frozen_default = True, kw_only_default = True )
|
|
77
|
-
class Dataclass(
|
|
152
|
+
class Dataclass( Class ):
|
|
78
153
|
''' Metaclass for standard dataclasses. '''
|
|
79
154
|
|
|
80
155
|
_dynadoc_fragments_ = (
|
|
@@ -95,7 +170,7 @@ class Dataclass( type ):
|
|
|
95
170
|
|
|
96
171
|
@_class_factory( )
|
|
97
172
|
@__.typx.dataclass_transform( kw_only_default = True )
|
|
98
|
-
class DataclassMutable(
|
|
173
|
+
class DataclassMutable( Dataclass ):
|
|
99
174
|
''' Metaclass for dataclasses with mutable instance attributes. '''
|
|
100
175
|
|
|
101
176
|
_dynadoc_fragments_ = (
|
|
@@ -115,7 +190,7 @@ class DataclassMutable( type ):
|
|
|
115
190
|
|
|
116
191
|
|
|
117
192
|
@_class_factory( )
|
|
118
|
-
class ProtocolClass( type( __.typx.Protocol ) ):
|
|
193
|
+
class ProtocolClass( AbstractClass, type( __.typx.Protocol ) ):
|
|
119
194
|
''' Metaclass for standard protocol classes. '''
|
|
120
195
|
|
|
121
196
|
_dynadoc_fragments_ = (
|
|
@@ -131,12 +206,55 @@ class ProtocolClass( type( __.typx.Protocol ) ):
|
|
|
131
206
|
decorators: _nomina.Decorators[ __.T ] = ( ),
|
|
132
207
|
**arguments: __.typx.Unpack[ ClassFactoryExtraArguments ],
|
|
133
208
|
) -> __.T:
|
|
134
|
-
|
|
209
|
+
cls = super( ).__new__( clscls, name, bases, namespace )
|
|
210
|
+
# typing_extensions.Protocol.__init_subclass__ uses identity comparison
|
|
211
|
+
# (b is Protocol) to set _is_protocol on subclasses. Classcore protocol
|
|
212
|
+
# base classes are not typing.Protocol, so subclasses incorrectly get
|
|
213
|
+
# _is_protocol = False. Detect protocol base classes structurally and
|
|
214
|
+
# fix _is_protocol before decorators are applied
|
|
215
|
+
# (e.g., runtime_checkable).
|
|
216
|
+
if not cls.__dict__.get( '_is_protocol', False ):
|
|
217
|
+
for base in cls.__bases__:
|
|
218
|
+
if ( base.__dict__.get( '_is_protocol', False )
|
|
219
|
+
and bool( _protocol_cls_set & set( base.__bases__ ) ) ):
|
|
220
|
+
setattr( cls, '_is_protocol', True )
|
|
221
|
+
break
|
|
222
|
+
if cls.__dict__.get( '_is_protocol', False ):
|
|
223
|
+
_snapshot_declared_protocol_attrs( cls )
|
|
224
|
+
return cls
|
|
225
|
+
|
|
226
|
+
def __init__(
|
|
227
|
+
cls,
|
|
228
|
+
name: str,
|
|
229
|
+
bases: tuple[ type, ... ],
|
|
230
|
+
namespace: dict[ str, __.typx.Any ],
|
|
231
|
+
**kwargs: __.typx.Any,
|
|
232
|
+
) -> None:
|
|
233
|
+
super( ).__init__( name, bases, namespace, **kwargs )
|
|
234
|
+
# Replace _ProtocolMeta's scan of the decorated namespace with the
|
|
235
|
+
# pre-decoration snapshot, so isinstance() only checks declared
|
|
236
|
+
# protocol members. Snapshot persists because metaclass __init__ can
|
|
237
|
+
# run more than once when dataclass machinery reproduces classes.
|
|
238
|
+
if getattr( cls, '_is_protocol', False ):
|
|
239
|
+
declared: frozenset[ str ] = cls.__dict__.get(
|
|
240
|
+
'_classcore_protocol_declared_', frozenset( ) )
|
|
241
|
+
inherited: set[ str ] = set( )
|
|
242
|
+
for base in cls.__mro__[ 1: ]:
|
|
243
|
+
if not isinstance( base, ProtocolClass ): continue
|
|
244
|
+
inherited.update( base.__dict__.get(
|
|
245
|
+
'__protocol_attrs__', ( ) ) )
|
|
246
|
+
attrs = {
|
|
247
|
+
attr for attr in declared | inherited
|
|
248
|
+
if attr not in _protocol_attr_excluded
|
|
249
|
+
and not any(
|
|
250
|
+
attr.startswith( p ) for p in _protocol_attr_prefixes )
|
|
251
|
+
}
|
|
252
|
+
setattr( cls, '__protocol_attrs__', attrs )
|
|
135
253
|
|
|
136
254
|
|
|
137
255
|
@_class_factory( )
|
|
138
256
|
@__.typx.dataclass_transform( frozen_default = True, kw_only_default = True )
|
|
139
|
-
class ProtocolDataclass(
|
|
257
|
+
class ProtocolDataclass( ProtocolClass ):
|
|
140
258
|
''' Metaclass for standard protocol dataclasses. '''
|
|
141
259
|
|
|
142
260
|
_dynadoc_fragments_ = (
|
|
@@ -157,7 +275,7 @@ class ProtocolDataclass( type( __.typx.Protocol ) ):
|
|
|
157
275
|
|
|
158
276
|
@_class_factory( )
|
|
159
277
|
@__.typx.dataclass_transform( kw_only_default = True )
|
|
160
|
-
class ProtocolDataclassMutable(
|
|
278
|
+
class ProtocolDataclassMutable( ProtocolDataclass ):
|
|
161
279
|
''' Metaclass for protocol dataclasses with mutable instance attributes.
|
|
162
280
|
'''
|
|
163
281
|
|
|
@@ -193,6 +311,22 @@ class ObjectMutable( metaclass = Class, instances_mutables = '*' ):
|
|
|
193
311
|
'class instance conceal' )
|
|
194
312
|
|
|
195
313
|
|
|
314
|
+
class AbstractObject(
|
|
315
|
+
metaclass = AbstractClass,
|
|
316
|
+
class_mutables = _abc_class_mutables,
|
|
317
|
+
):
|
|
318
|
+
''' Base class for abstract classes with standard behaviors.
|
|
319
|
+
|
|
320
|
+
Supports abstract method enforcement and virtual subclass
|
|
321
|
+
registration, and mixes with external classes whose metaclass is
|
|
322
|
+
`abc.ABCMeta`.
|
|
323
|
+
'''
|
|
324
|
+
|
|
325
|
+
_dynadoc_fragments_ = (
|
|
326
|
+
'class concealment', 'class protection', 'class dynadoc',
|
|
327
|
+
'class instance conceal', 'class instance protect' )
|
|
328
|
+
|
|
329
|
+
|
|
196
330
|
class DataclassObject( metaclass = Dataclass ):
|
|
197
331
|
''' Standard base dataclass. '''
|
|
198
332
|
|
|
@@ -262,3 +396,41 @@ class DataclassProtocolMutable(
|
|
|
262
396
|
'dataclass', 'protocol class',
|
|
263
397
|
'class concealment', 'class protection', 'class dynadoc',
|
|
264
398
|
'class instance conceal' )
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
# =========================================================================== #
|
|
402
|
+
# Type checker canaries. Private declarations, excluded from the public API
|
|
403
|
+
# and the test suite. They exist so that Pyright (and other type checkers)
|
|
404
|
+
# evaluates the structures declared above; regressions in checker support
|
|
405
|
+
# surface as diagnostics on these declarations during routine linting.
|
|
406
|
+
# =========================================================================== #
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
class _CanaryAbstractObject( AbstractObject ):
|
|
410
|
+
''' Canary for abstract base classes. '''
|
|
411
|
+
|
|
412
|
+
def provide( self ) -> int:
|
|
413
|
+
return 42
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
class _CanaryProtocolUse( Protocol ):
|
|
417
|
+
''' Canary for protocol definitions. '''
|
|
418
|
+
|
|
419
|
+
value: int
|
|
420
|
+
|
|
421
|
+
def greet( self ) -> str: ...
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
class _CanaryProtocolImpl( _CanaryProtocolUse ):
|
|
425
|
+
''' Canary for concrete protocol implementations. '''
|
|
426
|
+
|
|
427
|
+
def __init__( self ) -> None:
|
|
428
|
+
self.value = 7
|
|
429
|
+
|
|
430
|
+
def greet( self ) -> str:
|
|
431
|
+
return 'canary'
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
_canary_abstract: int = _CanaryAbstractObject( ).provide( )
|
|
435
|
+
_canary_protocol_iface: _CanaryProtocolUse = _CanaryProtocolImpl( )
|
|
436
|
+
_canary_greeting: str = _canary_protocol_iface.greet( )
|
|
@@ -175,7 +175,7 @@ def apply_cfc_attributes_surveyor(
|
|
|
175
175
|
decorator( clscls )
|
|
176
176
|
|
|
177
177
|
|
|
178
|
-
def class_factory( # noqa: PLR0913
|
|
178
|
+
def class_factory( # noqa: PLR0913, PLR0917
|
|
179
179
|
attributes_namer: _nomina.AttributesNamer = __.calculate_attrname,
|
|
180
180
|
error_class_provider: _nomina.ErrorClassProvider = __.provide_error_class,
|
|
181
181
|
assigner_core: __.typx.Optional[ _nomina.AssignerCore ] = None,
|
|
@@ -220,7 +220,7 @@ def class_factory( # noqa: PLR0913
|
|
|
220
220
|
return decorate
|
|
221
221
|
|
|
222
222
|
|
|
223
|
-
def produce_instances_inception_decorator( # noqa: PLR0913
|
|
223
|
+
def produce_instances_inception_decorator( # noqa: PLR0913, PLR0917
|
|
224
224
|
attributes_namer: _nomina.AttributesNamer,
|
|
225
225
|
assigner_core: __.typx.Optional[ _nomina.AssignerCore ],
|
|
226
226
|
deleter_core: __.typx.Optional[ _nomina.DeleterCore ],
|
|
@@ -532,7 +532,7 @@ def produce_attributes_surveillance_decorator(
|
|
|
532
532
|
|
|
533
533
|
|
|
534
534
|
@__.typx.dataclass_transform( frozen_default = True, kw_only_default = True )
|
|
535
|
-
def dataclass_with_standard_behaviors( # noqa: PLR0913
|
|
535
|
+
def dataclass_with_standard_behaviors( # noqa: PLR0913, PLR0917
|
|
536
536
|
attributes_namer: _nomina.AttributesNamer = __.calculate_attrname,
|
|
537
537
|
error_class_provider: _nomina.ErrorClassProvider = __.provide_error_class,
|
|
538
538
|
decorators: _nomina.Decorators[ __.U ] = ( ),
|
|
@@ -564,7 +564,7 @@ def dataclass_with_standard_behaviors( # noqa: PLR0913
|
|
|
564
564
|
*decorators, _dataclass_core, *decorators_, preparers = preparers )
|
|
565
565
|
|
|
566
566
|
|
|
567
|
-
def with_standard_behaviors( # noqa: PLR0913
|
|
567
|
+
def with_standard_behaviors( # noqa: PLR0913, PLR0917
|
|
568
568
|
attributes_namer: _nomina.AttributesNamer = __.calculate_attrname,
|
|
569
569
|
error_class_provider: _nomina.ErrorClassProvider = __.provide_error_class,
|
|
570
570
|
decorators: _nomina.Decorators[ __.U ] = ( ),
|
|
@@ -621,7 +621,7 @@ def _produce_instances_decoration_preparers(
|
|
|
621
621
|
return tuple( preprocessors )
|
|
622
622
|
|
|
623
623
|
|
|
624
|
-
def _produce_instances_decorators( # noqa: PLR0913
|
|
624
|
+
def _produce_instances_decorators( # noqa: PLR0913, PLR0917
|
|
625
625
|
attributes_namer: _nomina.AttributesNamer,
|
|
626
626
|
error_class_provider: _nomina.ErrorClassProvider,
|
|
627
627
|
assigner_core: __.typx.Optional[ _nomina.AssignerCore ],
|
|
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
|