Coverage for sources/classcore/factories.py: 100%
32 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-29 23:23 +0000
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-29 23:23 +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 in_progress = _utilities.getattr0( cls, progress_name, False )
62 if in_progress: return cls
63 setattr( cls, progress_name, True )
64 for postp in postprocessors: postp( cls, decorators_ )
65 cls = _decorators.apply_decorators( cls, decorators_ )
66 setattr( cls, progress_name, False )
67 return cls
69 return construct
72def produce_class_initializer(
73 attributes_namer: _nomina.AttributesNamer,
74 completers: _nomina.ProduceInitializerCompletersArgument = ( ),
75) -> _nomina.ClassInitializer:
76 ''' Produces initializers for classes. '''
78 def initialize(
79 cls: type,
80 superf: _nomina.InitializerLigation,
81 posargs: __.PositionalArguments,
82 nomargs: __.NominativeArguments,
83 ) -> None:
84 ''' Initializes class, applying hooks. '''
85 superf( *posargs, **nomargs )
86 progress_name = attributes_namer( 'class', 'in_progress' )
87 in_progress = _utilities.getattr0( cls, progress_name, False )
88 if in_progress: return # If non-empty, then not top-level.
89 delattr( cls, progress_name )
90 for completer in completers: completer( cls )
92 return initialize