Coverage for sources/accretive/iclasses.py: 100%
80 statements
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-05 00:54 +0000
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-05 00:54 +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( table = __.fragments ) )
90_class_factory = __.funct.partial(
91 __.ccstd.class_factory,
92 attributes_namer = __.calculate_attrname,
93 dynadoc_configuration = dynadoc_configuration,
94 error_class_provider = provide_error_class )
97@_class_factory( )
98class Class( type ):
99 ''' Metaclass for immutable classes. '''
101 _dynadoc_fragments_ = (
102 'cfc class conceal', 'cfc class protect', 'cfc dynadoc',
103 'cfc instance conceal', 'cfc instance protect' )
105 def __new__( # Typechecker stub.
106 clscls: type[ __.T ],
107 name: str,
108 bases: tuple[ type, ... ],
109 namespace: dict[ str, __.typx.Any ], *,
110 decorators: __.ClassDecorators[ __.T ] = ( ),
111 **arguments: __.typx.Unpack[ __.ccstd.ClassFactoryExtraArguments ],
112 ) -> __.T:
113 return super( ).__new__( clscls, name, bases, namespace )
116@_class_factory( )
117@__.typx.dataclass_transform( frozen_default = True, kw_only_default = True )
118class Dataclass( type ):
119 ''' Metaclass for immutable dataclasses. '''
121 _dynadoc_fragments_ = (
122 'cfc produce dataclass',
123 'cfc class conceal', 'cfc class protect', 'cfc dynadoc',
124 'cfc instance conceal', 'cfc instance protect' )
126 def __new__( # Typechecker stub.
127 clscls: type[ __.T ],
128 name: str,
129 bases: tuple[ type, ... ],
130 namespace: dict[ str, __.typx.Any ], *,
131 decorators: __.ClassDecorators[ __.T ] = ( ),
132 **arguments: __.typx.Unpack[ __.ccstd.ClassFactoryExtraArguments ],
133 ) -> __.T:
134 return super( ).__new__( clscls, name, bases, namespace )
137@_class_factory( )
138@__.typx.dataclass_transform( kw_only_default = True )
139class DataclassMutable( type ):
140 ''' Metaclass for immutable dataclasses with mutable instances. '''
142 _dynadoc_fragments_ = (
143 'cfc produce dataclass',
144 'cfc class conceal', 'cfc class protect', 'cfc dynadoc',
145 'cfc instance conceal' )
147 def __new__( # Typechecker stub.
148 clscls: type[ __.T ],
149 name: str,
150 bases: tuple[ type, ... ],
151 namespace: dict[ str, __.typx.Any ], *,
152 decorators: __.ClassDecorators[ __.T ] = ( ),
153 **arguments: __.typx.Unpack[ __.ccstd.ClassFactoryExtraArguments ],
154 ) -> __.T:
155 return super( ).__new__( clscls, name, bases, namespace )
158@_class_factory( )
159class AbstractBaseClass( __.abc.ABCMeta ):
160 ''' Metaclass for immutable abstract base classes. '''
162 _dynadoc_fragments_ = (
163 'cfc produce abstract base class',
164 'cfc class conceal', 'cfc class protect', 'cfc dynadoc',
165 'cfc instance conceal', 'cfc instance protect' )
167 def __new__( # Typechecker stub.
168 clscls: type[ __.T ],
169 name: str,
170 bases: tuple[ type, ... ],
171 namespace: dict[ str, __.typx.Any ], *,
172 decorators: __.ClassDecorators[ __.T ] = ( ),
173 **arguments: __.typx.Unpack[ __.ccstd.ClassFactoryExtraArguments ],
174 ) -> __.T: # pragma: no cover
175 return super( ).__new__( clscls, name, bases, namespace )
178@_class_factory( )
179class ProtocolClass( type( __.typx.Protocol ) ):
180 ''' Metaclass for immutable protocol classes. '''
182 _dynadoc_fragments_ = (
183 'cfc produce protocol class',
184 'cfc class conceal', 'cfc class protect', 'cfc dynadoc',
185 'cfc instance conceal', 'cfc instance protect' )
187 def __new__( # Typechecker stub.
188 clscls: type[ __.T ],
189 name: str,
190 bases: tuple[ type, ... ],
191 namespace: dict[ str, __.typx.Any ], *,
192 decorators: __.ClassDecorators[ __.T ] = ( ),
193 **arguments: __.typx.Unpack[ __.ccstd.ClassFactoryExtraArguments ],
194 ) -> __.T:
195 return super( ).__new__( clscls, name, bases, namespace )
198@_class_factory( )
199@__.typx.dataclass_transform( frozen_default = True, kw_only_default = True )
200class ProtocolDataclass( type( __.typx.Protocol ) ):
201 ''' Metaclass for immutable protocol dataclasses. '''
203 _dynadoc_fragments_ = (
204 'cfc produce protocol class', 'cfc produce dataclass',
205 'cfc class conceal', 'cfc class protect', 'cfc dynadoc',
206 'cfc instance conceal', 'cfc instance protect' )
208 def __new__( # Typechecker stub.
209 clscls: type[ __.T ],
210 name: str,
211 bases: tuple[ type, ... ],
212 namespace: dict[ str, __.typx.Any ], *,
213 decorators: __.ClassDecorators[ __.T ] = ( ),
214 **arguments: __.typx.Unpack[ __.ccstd.ClassFactoryExtraArguments ],
215 ) -> __.T:
216 return super( ).__new__( clscls, name, bases, namespace )
219@_class_factory( )
220@__.typx.dataclass_transform( kw_only_default = True )
221class ProtocolDataclassMutable( type( __.typx.Protocol ) ):
222 ''' Metaclass for immutable protocol dataclasses with mutable instances.
223 '''
225 _dynadoc_fragments_ = (
226 'cfc produce protocol class', 'cfc produce dataclass',
227 'cfc class conceal', 'cfc class accrete', 'cfc dynadoc',
228 'cfc instance conceal' )
230 def __new__( # Typechecker stub.
231 clscls: type[ __.T ],
232 name: str,
233 bases: tuple[ type, ... ],
234 namespace: dict[ str, __.typx.Any ], *,
235 decorators: __.ClassDecorators[ __.T ] = ( ),
236 **arguments: __.typx.Unpack[ __.ccstd.ClassFactoryExtraArguments ],
237 ) -> __.T:
238 return super( ).__new__( clscls, name, bases, namespace )