Coverage for sources/accretive/iclasses.py: 100%
80 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-28 21:31 +0000
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-28 21:31 +0000
1# vim: set filetype=python fileencoding=utf-8:
2# -*- coding: utf-8 -*-
4#============================================================================#
5# #
6# Licensed under the Apache License, Version 2.0 (the "License"); #
7# you may not use this file except in compliance with the License. #
8# You may obtain a copy of the License at #
9# #
10# http://www.apache.org/licenses/LICENSE-2.0 #
11# #
12# Unless required by applicable law or agreed to in writing, software #
13# distributed under the License is distributed on an "AS IS" BASIS, #
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
15# See the License for the specific language governing permissions and #
16# limitations under the License. #
17# #
18#============================================================================#
21''' Immutable classes. '''
24from . import __
27dataclass_core = __.dcls.dataclass( kw_only = True, slots = True )
28mutables_default = ( )
29visibles_default = ( __.is_public_identifier, )
32def assign_attribute_if_absent_mutable( # noqa: PLR0913
33 objct: object, /, *,
34 ligation: __.AssignerLigation,
35 attributes_namer: __.AttributesNamer,
36 error_class_provider: __.ErrorClassProvider,
37 level: str,
38 name: str,
39 value: __.typx.Any,
40) -> None:
41 ''' Assigns attribute if it is absent or mutable, else raises error. '''
42 if not hasattr( objct, name ):
43 ligation( name, value )
44 return
45 leveli = 'instance' if level == 'instances' else level
46 behaviors_name = attributes_namer( leveli, 'behaviors' )
47 behaviors = __.ccutils.getattr0( objct, behaviors_name, frozenset( ) )
48 if __.immutability_label not in behaviors:
49 ligation( name, value )
50 return
51 names_name = attributes_namer( level, 'mutables_names' )
52 names: __.BehaviorExclusionNamesOmni = (
53 getattr( objct, names_name, frozenset( ) ) )
54 if names == '*' or name in names:
55 ligation( name, value )
56 return
57 predicates_name = attributes_namer( level, 'mutables_predicates' )
58 predicates: __.BehaviorExclusionPredicates = (
59 getattr( objct, predicates_name, ( ) ) )
60 for predicate in predicates:
61 if predicate( name ):
62 # TODO? Cache predicate hit.
63 ligation( name, value )
64 return
65 regexes_name = attributes_namer( level, 'mutables_regexes' )
66 regexes: __.BehaviorExclusionRegexes = (
67 getattr( objct, regexes_name, ( ) ) )
68 for regex in regexes:
69 if regex.fullmatch( name ):
70 # TODO? Cache regex hit.
71 ligation( name, value )
72 return
73 target = __.ccutils.describe_object( objct )
74 raise error_class_provider( 'AttributeImmutability' )( name, target )
77def provide_error_class( name: str ) -> type[ Exception ]:
78 ''' Provides error class for this package. '''
79 match name:
80 case 'AttributeImmutability':
81 from .exceptions import AttributeImmutability as error
82 case _:
83 from .exceptions import ErrorProvideFailure
84 raise ErrorProvideFailure( name, reason = 'Does not exist.' )
85 return error
88dynadoc_configuration = (
89 __.ccstd.dynadoc.produce_dynadoc_configuration(
90 introspection = __.dynadoc_introspection_control_on_class,
91 table = __.fragments ) )
94_class_factory = __.funct.partial(
95 __.ccstd.class_factory,
96 attributes_namer = __.calculate_attrname,
97 dynadoc_configuration = dynadoc_configuration,
98 error_class_provider = provide_error_class )
101@_class_factory( )
102class Class( type ):
103 ''' Metaclass for immutable classes. '''
105 _dynadoc_fragments_ = (
106 'cfc class conceal', 'cfc class protect', 'cfc dynadoc',
107 'cfc instance conceal', 'cfc instance protect' )
109 def __new__( # Typechecker stub.
110 clscls: type[ __.T ],
111 name: str,
112 bases: tuple[ type, ... ],
113 namespace: dict[ str, __.typx.Any ], *,
114 decorators: __.ClassDecorators[ __.T ] = ( ),
115 **arguments: __.typx.Unpack[ __.ccstd.ClassFactoryExtraArguments ],
116 ) -> __.T:
117 return super( ).__new__( clscls, name, bases, namespace )
120@_class_factory( )
121@__.typx.dataclass_transform( frozen_default = True, kw_only_default = True )
122class Dataclass( type ):
123 ''' Metaclass for immutable dataclasses. '''
125 _dynadoc_fragments_ = (
126 'cfc produce dataclass',
127 'cfc class conceal', 'cfc class protect', 'cfc dynadoc',
128 'cfc instance conceal', 'cfc instance protect' )
130 def __new__( # Typechecker stub.
131 clscls: type[ __.T ],
132 name: str,
133 bases: tuple[ type, ... ],
134 namespace: dict[ str, __.typx.Any ], *,
135 decorators: __.ClassDecorators[ __.T ] = ( ),
136 **arguments: __.typx.Unpack[ __.ccstd.ClassFactoryExtraArguments ],
137 ) -> __.T:
138 return super( ).__new__( clscls, name, bases, namespace )
141@_class_factory( )
142@__.typx.dataclass_transform( kw_only_default = True )
143class DataclassMutable( type ):
144 ''' Metaclass for immutable dataclasses with mutable instances. '''
146 _dynadoc_fragments_ = (
147 'cfc produce dataclass',
148 'cfc class conceal', 'cfc class protect', 'cfc dynadoc',
149 'cfc instance conceal' )
151 def __new__( # Typechecker stub.
152 clscls: type[ __.T ],
153 name: str,
154 bases: tuple[ type, ... ],
155 namespace: dict[ str, __.typx.Any ], *,
156 decorators: __.ClassDecorators[ __.T ] = ( ),
157 **arguments: __.typx.Unpack[ __.ccstd.ClassFactoryExtraArguments ],
158 ) -> __.T:
159 return super( ).__new__( clscls, name, bases, namespace )
162@_class_factory( )
163class AbstractBaseClass( __.abc.ABCMeta ):
164 ''' Metaclass for immutable abstract base classes. '''
166 _dynadoc_fragments_ = (
167 'cfc produce abstract base class',
168 'cfc class conceal', 'cfc class protect', 'cfc dynadoc',
169 'cfc instance conceal', 'cfc instance protect' )
171 def __new__( # Typechecker stub.
172 clscls: type[ __.T ],
173 name: str,
174 bases: tuple[ type, ... ],
175 namespace: dict[ str, __.typx.Any ], *,
176 decorators: __.ClassDecorators[ __.T ] = ( ),
177 **arguments: __.typx.Unpack[ __.ccstd.ClassFactoryExtraArguments ],
178 ) -> __.T: # pragma: no cover
179 return super( ).__new__( clscls, name, bases, namespace )
182@_class_factory( )
183class ProtocolClass( type( __.typx.Protocol ) ):
184 ''' Metaclass for immutable protocol classes. '''
186 _dynadoc_fragments_ = (
187 'cfc produce protocol class',
188 'cfc class conceal', 'cfc class protect', 'cfc dynadoc',
189 'cfc instance conceal', 'cfc instance protect' )
191 def __new__( # Typechecker stub.
192 clscls: type[ __.T ],
193 name: str,
194 bases: tuple[ type, ... ],
195 namespace: dict[ str, __.typx.Any ], *,
196 decorators: __.ClassDecorators[ __.T ] = ( ),
197 **arguments: __.typx.Unpack[ __.ccstd.ClassFactoryExtraArguments ],
198 ) -> __.T:
199 return super( ).__new__( clscls, name, bases, namespace )
202@_class_factory( )
203@__.typx.dataclass_transform( frozen_default = True, kw_only_default = True )
204class ProtocolDataclass( type( __.typx.Protocol ) ):
205 ''' Metaclass for immutable protocol dataclasses. '''
207 _dynadoc_fragments_ = (
208 'cfc produce protocol class', 'cfc produce dataclass',
209 'cfc class conceal', 'cfc class protect', 'cfc dynadoc',
210 'cfc instance conceal', 'cfc instance protect' )
212 def __new__( # Typechecker stub.
213 clscls: type[ __.T ],
214 name: str,
215 bases: tuple[ type, ... ],
216 namespace: dict[ str, __.typx.Any ], *,
217 decorators: __.ClassDecorators[ __.T ] = ( ),
218 **arguments: __.typx.Unpack[ __.ccstd.ClassFactoryExtraArguments ],
219 ) -> __.T:
220 return super( ).__new__( clscls, name, bases, namespace )
223@_class_factory( )
224@__.typx.dataclass_transform( kw_only_default = True )
225class ProtocolDataclassMutable( type( __.typx.Protocol ) ):
226 ''' Metaclass for immutable protocol dataclasses with mutable instances.
227 '''
229 _dynadoc_fragments_ = (
230 'cfc produce protocol class', 'cfc produce dataclass',
231 'cfc class conceal', 'cfc class accrete', 'cfc dynadoc',
232 'cfc instance conceal' )
234 def __new__( # Typechecker stub.
235 clscls: type[ __.T ],
236 name: str,
237 bases: tuple[ type, ... ],
238 namespace: dict[ str, __.typx.Any ], *,
239 decorators: __.ClassDecorators[ __.T ] = ( ),
240 **arguments: __.typx.Unpack[ __.ccstd.ClassFactoryExtraArguments ],
241 ) -> __.T:
242 return super( ).__new__( clscls, name, bases, namespace )