Coverage for sources/classcore/factories.py: 100%
34 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-01 21:58 +0000
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-01 21:58 +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''' Factories which produce metaclass implementations. '''
24from __future__ import annotations
26from . import __
27from . import decorators as _decorators
28from . import nomina as _nomina
29from . import utilities as _utilities
32_T = __.typx.TypeVar( '_T', bound = type )
35def produce_class_constructor(
36 attributes_namer: _nomina.AttributesNamer,
37 preprocessors: _nomina.ProduceConstructorPreprocsArgument = ( ),
38 postprocessors: _nomina.ProduceConstructorPostprocsArgument = ( ),
39) -> _nomina.ClassConstructor:
40 ''' Produces constructors for classes. '''
42 def construct( # noqa: PLR0913
43 clscls: type[ _T ],
44 superf: _nomina.ClassConstructorLigation,
45 name: str,
46 bases: tuple[ type, ... ],
47 namespace: dict[ str, __.typx.Any ],
48 arguments: __.NominativeArguments,
49 decorators: _nomina.Decorators,
50 ) -> type:
51 ''' Constructs class, applying decorators and hooks. '''
52 bases_ = list( bases )
53 arguments_ = dict( arguments )
54 decorators_ = list( decorators )
55 for prep in preprocessors:
56 prep( clscls, name, bases_, namespace, arguments_, decorators_ )
57 cls = superf( clscls, name, tuple( bases_ ), namespace, **arguments_ )
58 # Some decorators create new classes, which invokes this method again.
59 # Short-circuit to prevent recursive decoration and other tangles.
60 progress_name = attributes_namer( 'class', 'in_progress' )
61 progress_name_m = _utilities.mangle_name( cls, progress_name )
62 in_progress = getattr( cls, progress_name_m, False )
63 if in_progress: return cls
64 setattr( cls, progress_name_m, True )
65 for postp in postprocessors: postp( cls, decorators_ )
66 cls = _decorators.apply_decorators( cls, decorators_ )
67 setattr( cls, progress_name_m, False )
68 return cls
70 return construct
73def produce_class_initializer(
74 attributes_namer: _nomina.AttributesNamer,
75 completers: _nomina.ProduceInitializerCompletersArgument = ( ),
76) -> _nomina.ClassInitializer:
77 ''' Produces initializers for classes. '''
79 def initialize(
80 cls: type,
81 superf: _nomina.InitializerLigation,
82 posargs: __.PositionalArguments,
83 nomargs: __.NominativeArguments,
84 ) -> None:
85 ''' Initializes class, applying hooks. '''
86 superf( *posargs, **nomargs )
87 progress_name = attributes_namer( 'class', 'in_progress' )
88 progress_name_m = _utilities.mangle_name( cls, progress_name )
89 in_progress = getattr( cls, progress_name_m, False )
90 if in_progress: return # If non-empty, then not top-level.
91 delattr( cls, progress_name_m )
92 for completer in completers: completer( cls )
94 return initialize