Coverage for sources/accretive/iclasses.py: 100%

80 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2025-09-25 18:07 +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( 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 ) 

95 

96 

97@_class_factory( ) 

98class Class( type ): 

99 ''' Metaclass for immutable classes. ''' 

100 

101 _dynadoc_fragments_ = ( 

102 'cfc class conceal', 'cfc class protect', 'cfc dynadoc', 

103 'cfc instance conceal', 'cfc instance protect' ) 

104 

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 ) 

114 

115 

116@_class_factory( ) 

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

118class Dataclass( type ): 

119 ''' Metaclass for immutable dataclasses. ''' 

120 

121 _dynadoc_fragments_ = ( 

122 'cfc produce dataclass', 

123 'cfc class conceal', 'cfc class protect', 'cfc dynadoc', 

124 'cfc instance conceal', 'cfc instance protect' ) 

125 

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 ) 

135 

136 

137@_class_factory( ) 

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

139class DataclassMutable( type ): 

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

141 

142 _dynadoc_fragments_ = ( 

143 'cfc produce dataclass', 

144 'cfc class conceal', 'cfc class protect', 'cfc dynadoc', 

145 'cfc instance conceal' ) 

146 

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 ) 

156 

157 

158@_class_factory( ) 

159class AbstractBaseClass( __.abc.ABCMeta ): 

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

161 

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

166 

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 ) 

176 

177 

178@_class_factory( ) 

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

180 ''' Metaclass for immutable protocol classes. ''' 

181 

182 _dynadoc_fragments_ = ( 

183 'cfc produce protocol class', 

184 'cfc class conceal', 'cfc class protect', 'cfc dynadoc', 

185 'cfc instance conceal', 'cfc instance protect' ) 

186 

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 ) 

196 

197 

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

202 

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

207 

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 ) 

217 

218 

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

224 

225 _dynadoc_fragments_ = ( 

226 'cfc produce protocol class', 'cfc produce dataclass', 

227 'cfc class conceal', 'cfc class accrete', 'cfc dynadoc', 

228 'cfc instance conceal' ) 

229 

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 )