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

1# vim: set filetype=python fileencoding=utf-8: 

2# -*- coding: utf-8 -*- 

3 

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#============================================================================# 

19 

20 

21''' Immutable classes. ''' 

22 

23 

24from . import __ 

25 

26 

27dataclass_core = __.dcls.dataclass( kw_only = True, slots = True ) 

28mutables_default = ( ) 

29visibles_default = ( __.is_public_identifier, ) 

30 

31 

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 ) 

75 

76 

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 

86 

87 

88dynadoc_configuration = ( 

89 __.ccstd.dynadoc.produce_dynadoc_configuration( 

90 introspection = __.dynadoc_introspection_control_on_class, 

91 table = __.fragments ) ) 

92 

93 

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 ) 

99 

100 

101@_class_factory( ) 

102class Class( type ): 

103 ''' Metaclass for immutable classes. ''' 

104 

105 _dynadoc_fragments_ = ( 

106 'cfc class conceal', 'cfc class protect', 'cfc dynadoc', 

107 'cfc instance conceal', 'cfc instance protect' ) 

108 

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 ) 

118 

119 

120@_class_factory( ) 

121@__.typx.dataclass_transform( frozen_default = True, kw_only_default = True ) 

122class Dataclass( type ): 

123 ''' Metaclass for immutable dataclasses. ''' 

124 

125 _dynadoc_fragments_ = ( 

126 'cfc produce dataclass', 

127 'cfc class conceal', 'cfc class protect', 'cfc dynadoc', 

128 'cfc instance conceal', 'cfc instance protect' ) 

129 

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 ) 

139 

140 

141@_class_factory( ) 

142@__.typx.dataclass_transform( kw_only_default = True ) 

143class DataclassMutable( type ): 

144 ''' Metaclass for immutable dataclasses with mutable instances. ''' 

145 

146 _dynadoc_fragments_ = ( 

147 'cfc produce dataclass', 

148 'cfc class conceal', 'cfc class protect', 'cfc dynadoc', 

149 'cfc instance conceal' ) 

150 

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 ) 

160 

161 

162@_class_factory( ) 

163class AbstractBaseClass( __.abc.ABCMeta ): 

164 ''' Metaclass for immutable abstract base classes. ''' 

165 

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' ) 

170 

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 ) 

180 

181 

182@_class_factory( ) 

183class ProtocolClass( type( __.typx.Protocol ) ): 

184 ''' Metaclass for immutable protocol classes. ''' 

185 

186 _dynadoc_fragments_ = ( 

187 'cfc produce protocol class', 

188 'cfc class conceal', 'cfc class protect', 'cfc dynadoc', 

189 'cfc instance conceal', 'cfc instance protect' ) 

190 

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 ) 

200 

201 

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. ''' 

206 

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' ) 

211 

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 ) 

221 

222 

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 ''' 

228 

229 _dynadoc_fragments_ = ( 

230 'cfc produce protocol class', 'cfc produce dataclass', 

231 'cfc class conceal', 'cfc class accrete', 'cfc dynadoc', 

232 'cfc instance conceal' ) 

233 

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 )