Coverage for sources/classcore/standard/modules.py: 100%
43 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-07-01 19:09 +0000
« prev ^ index » next coverage.py v7.9.1, created at 2025-07-01 19:09 +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 recursive: __.typx.Annotated[
46 bool, __.ddoc.Doc( ''' Recursively reclassify package modules? ''' )
47 ] = False,
48 replacement_class: __.typx.Annotated[
49 type[ __.types.ModuleType ],
50 __.ddoc.Doc( ''' New class for module. ''' ),
51 ] = Module,
52) -> None:
53 ''' Combines Dynadoc docstring assignment and module reclassification.
55 Applies module docstring generation via Dynadoc introspection,
56 then reclassifies modules for immutability and concealment.
58 When recursive is False, automatically excludes module targets from
59 dynadoc introspection to document only the provided module. When
60 recursive is True, automatically includes module targets so Dynadoc
61 can recursively document all modules.
62 '''
63 module_target = __.ddoc.IntrospectionTargets.Module
64 if recursive:
65 if not ( dynadoc_introspection.targets & module_target ):
66 targets = dynadoc_introspection.targets | module_target
67 introspection = __.ddoc.IntrospectionControl(
68 enable = dynadoc_introspection.enable,
69 class_control = dynadoc_introspection.class_control,
70 module_control = dynadoc_introspection.module_control,
71 limiters = dynadoc_introspection.limiters,
72 targets = targets )
73 else: introspection = dynadoc_introspection
74 elif dynadoc_introspection.targets & module_target:
75 limit = __.ddoc.IntrospectionLimit(
76 targets_exclusions = module_target )
77 introspection = dynadoc_introspection.with_limit( limit )
78 else: introspection = dynadoc_introspection
79 _dynadoc.assign_module_docstring(
80 module,
81 *fragments,
82 introspection = introspection,
83 table = dynadoc_table )
84 reclassify_modules(
85 module,
86 attributes_namer = attributes_namer,
87 recursive = recursive,
88 replacement_class = replacement_class )
91@__.typx.deprecated( "Use 'finalize_module' instead." )
92def reclassify_modules(
93 attributes: __.typx.Annotated[
94 __.cabc.Mapping[ str, __.typx.Any ] | __.types.ModuleType | str,
95 __.ddoc.Doc(
96 ''' Module, module name, or dictionary of object attributes. ''' ),
97 ], /, *,
98 attributes_namer: __.typx.Annotated[
99 _nomina.AttributesNamer,
100 __.ddoc.Doc(
101 ''' Attributes namer function with which to seal class. ''' ),
102 ] = __.calculate_attrname,
103 recursive: __.typx.Annotated[
104 bool, __.ddoc.Doc( ''' Recursively reclassify package modules? ''' )
105 ] = False,
106 replacement_class: __.typx.Annotated[
107 type[ __.types.ModuleType ],
108 __.ddoc.Doc( ''' New class for module. ''' ),
109 ] = Module,
110) -> None:
111 # TODO? Ensure correct operation with namespace packages.
112 ''' Reclassifies modules to have attributes concealment and immutability.
114 Can operate on individual modules or entire package hierarchies.
116 Only converts modules within the same package to prevent unintended
117 modifications to external modules.
119 When used with a dictionary, converts any module objects found as
120 values if they belong to the same package.
122 Has no effect on already-reclassified modules.
123 '''
124 if isinstance( attributes, str ):
125 attributes = __.sys.modules[ attributes ]
126 if isinstance( attributes, __.types.ModuleType ):
127 module = attributes
128 attributes = attributes.__dict__
129 else: module = None
130 package_name = (
131 attributes.get( '__package__' ) or attributes.get( '__name__' ) )
132 if not package_name: return
133 for value in attributes.values( ):
134 if not __.inspect.ismodule( value ): continue
135 if not value.__name__.startswith( f"{package_name}." ): continue
136 if recursive:
137 reclassify_modules(
138 value,
139 attributes_namer = attributes_namer,
140 recursive = True,
141 replacement_class = replacement_class )
142 if isinstance( value, replacement_class ): continue
143 _seal_module( value, attributes_namer, replacement_class )
144 if module and not isinstance( module, replacement_class ):
145 _seal_module( module, attributes_namer, replacement_class )
148def _seal_module(
149 module: __.types.ModuleType,
150 attributes_namer: _nomina.AttributesNamer,
151 replacement_class: type[ __.types.ModuleType ],
152) -> None:
153 behaviors = { _nomina.concealment_label, _nomina.immutability_label }
154 behaviors_name = attributes_namer( 'instance', 'behaviors' )
155 module.__class__ = replacement_class
156 _utilities.setattr0( module, behaviors_name, behaviors )