Coverage for sources/classcore/standard/modules.py: 100%
47 statements
« prev ^ index » next coverage.py v7.10.7, created at 2025-09-25 13:22 +0000
« prev ^ index » next coverage.py v7.10.7, created at 2025-09-25 13:22 +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''' Standard module classes and reclassifers. '''
24from .. import utilities as _utilities
25from . import __
26from . import classes as _classes
27from . import dynadoc as _dynadoc
28from . import nomina as _nomina
31class Module( _classes.Object, __.types.ModuleType ):
32 ''' Modules with attributes immutability and concealment. '''
35def finalize_module( # noqa: PLR0913
36 module: __.typx.Annotated[
37 str | __.types.ModuleType,
38 __.ddoc.Doc( ''' Module or module name to finalize. ''' ),
39 ], /,
40 *fragments: __.ddoc.interfaces.Fragment,
41 attributes_namer: _nomina.AttributesNamer = __.calculate_attrname,
42 dynadoc_introspection: _nomina.DynadocIntrospectionArgument = (
43 _dynadoc.dynadoc_introspection_on_package ),
44 dynadoc_table: _nomina.DynadocTableArgument = __.dictproxy_empty,
45 excludes: __.typx.Annotated[
46 __.typx.Optional[ __.cabc.MutableSet[ __.types.ModuleType ] ],
47 __.ddoc.Doc( ''' Modules to exclude from reclassification. ''' ),
48 ] = None,
49 recursive: __.typx.Annotated[
50 bool, __.ddoc.Doc( ''' Recursively reclassify package modules? ''' )
51 ] = False,
52 replacement_class: __.typx.Annotated[
53 type[ __.types.ModuleType ],
54 __.ddoc.Doc( ''' New class for module. ''' ),
55 ] = Module,
56) -> None:
57 ''' Combines Dynadoc docstring assignment and module reclassification.
59 Applies module docstring generation via Dynadoc introspection,
60 then reclassifies modules for immutability and concealment.
62 When recursive is False, automatically excludes module targets from
63 dynadoc introspection to document only the provided module. When
64 recursive is True, automatically includes module targets so Dynadoc
65 can recursively document all modules.
66 '''
67 module_target = __.ddoc.IntrospectionTargets.Module
68 if recursive:
69 if not ( dynadoc_introspection.targets & module_target ):
70 targets = dynadoc_introspection.targets | module_target
71 introspection = __.ddoc.IntrospectionControl(
72 enable = dynadoc_introspection.enable,
73 class_control = dynadoc_introspection.class_control,
74 module_control = dynadoc_introspection.module_control,
75 limiters = dynadoc_introspection.limiters,
76 targets = targets )
77 else: introspection = dynadoc_introspection
78 elif dynadoc_introspection.targets & module_target:
79 limit = __.ddoc.IntrospectionLimit(
80 targets_exclusions = module_target )
81 introspection = dynadoc_introspection.with_limit( limit )
82 else: introspection = dynadoc_introspection
83 _dynadoc.assign_module_docstring(
84 module,
85 *fragments,
86 introspection = introspection,
87 table = dynadoc_table )
88 _reclassify_module(
89 module,
90 attributes_namer = attributes_namer,
91 excludes = excludes, recursive = recursive,
92 replacement_class = replacement_class )
95@__.typx.deprecated( "Use 'finalize_module' instead." )
96def reclassify_modules(
97 attributes: __.typx.Annotated[
98 __.cabc.Mapping[ str, __.typx.Any ] | __.types.ModuleType | str,
99 __.ddoc.Doc(
100 ''' Module, module name, or dictionary of object attributes. ''' ),
101 ], /, *,
102 attributes_namer: __.typx.Annotated[
103 _nomina.AttributesNamer,
104 __.ddoc.Doc(
105 ''' Attributes namer function with which to seal class. ''' ),
106 ] = __.calculate_attrname,
107 excludes: __.typx.Annotated[
108 __.typx.Optional[ __.cabc.MutableSet[ __.types.ModuleType ] ],
109 __.ddoc.Doc( ''' Modules to exclude from reclassification. ''' ),
110 ] = None,
111 recursive: __.typx.Annotated[
112 bool, __.ddoc.Doc( ''' Recursively reclassify package modules? ''' )
113 ] = False,
114 replacement_class: __.typx.Annotated[
115 type[ __.types.ModuleType ],
116 __.ddoc.Doc( ''' New class for module. ''' ),
117 ] = Module,
118) -> None:
119 ''' Reclassifies modules to have attributes concealment and immutability.
121 Can operate on individual modules or entire package hierarchies.
123 Only converts modules within the same package to prevent unintended
124 modifications to external modules.
126 When used with a dictionary, converts any module objects found as
127 values if they belong to the same package.
129 Has no effect on already-reclassified modules.
130 '''
131 _reclassify_module(
132 attributes,
133 attributes_namer = attributes_namer,
134 excludes = excludes, recursive = recursive,
135 replacement_class = replacement_class )
138def _reclassify_module( # noqa: C901,PLR0912
139 attributes: __.typx.Annotated[
140 __.cabc.Mapping[ str, __.typx.Any ] | __.types.ModuleType | str,
141 __.ddoc.Doc(
142 ''' Module, module name, or dictionary of object attributes. ''' ),
143 ], /, *,
144 attributes_namer: __.typx.Annotated[
145 _nomina.AttributesNamer,
146 __.ddoc.Doc(
147 ''' Attributes namer function with which to seal class. ''' ),
148 ] = __.calculate_attrname,
149 excludes: __.typx.Annotated[
150 __.typx.Optional[ __.cabc.MutableSet[ __.types.ModuleType ] ],
151 __.ddoc.Doc( ''' Modules to exclude from reclassification. ''' ),
152 ] = None,
153 recursive: __.typx.Annotated[
154 bool, __.ddoc.Doc( ''' Recursively reclassify package modules? ''' )
155 ] = False,
156 replacement_class: __.typx.Annotated[
157 type[ __.types.ModuleType ],
158 __.ddoc.Doc( ''' New class for module. ''' ),
159 ] = Module,
160) -> None:
161 # TODO? Ensure correct operation with namespace packages.
162 ''' Core implementation for module reclassification.
164 Reclassifies modules to have attributes concealment and immutability.
165 Can operate on individual modules or entire package hierarchies.
167 Only converts modules within the same package to prevent unintended
168 modifications to external modules.
170 When used with a dictionary, converts any module objects found as
171 values if they belong to the same package.
173 Has no effect on already-reclassified modules.
174 '''
175 if isinstance( attributes, str ):
176 attributes = __.sys.modules[ attributes ]
177 if isinstance( attributes, __.types.ModuleType ):
178 module = attributes
179 if excludes and module in excludes: return
180 attributes = module.__dict__
181 else: module = None
182 if excludes is None: excludes = set( )
183 if module: excludes.add( module )
184 package_name = (
185 attributes.get( '__package__' ) or attributes.get( '__name__' ) )
186 if not package_name: return
187 for value in attributes.values( ):
188 if not __.inspect.ismodule( value ): continue
189 if not value.__name__.startswith( f"{package_name}." ): continue
190 if isinstance( value, replacement_class ): continue
191 if recursive:
192 _reclassify_module(
193 value,
194 attributes_namer = attributes_namer,
195 excludes = excludes, recursive = True,
196 replacement_class = replacement_class )
197 if module and not isinstance( module, replacement_class ):
198 _seal_module( module, attributes_namer, replacement_class )
201def _seal_module(
202 module: __.types.ModuleType,
203 attributes_namer: _nomina.AttributesNamer,
204 replacement_class: type[ __.types.ModuleType ],
205) -> None:
206 behaviors = { _nomina.concealment_label, _nomina.immutability_label }
207 behaviors_name = attributes_namer( 'instance', 'behaviors' )
208 module.__class__ = replacement_class
209 _utilities.setattr0( module, behaviors_name, behaviors )