Coverage for sources/dynadoc/interfaces.py: 100%
99 statements
« prev ^ index » next coverage.py v7.10.1, created at 2025-07-29 05:16 +0000
« prev ^ index » next coverage.py v7.10.1, created at 2025-07-29 05:16 +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''' Rich annotations, public interfaces for cutomization functions, etc....
23 .. note::
25 By default, this module exports ``typing_extensions.Doc``, which is
26 based on the withdrawn :pep:`727`. A ``typing_extensions`` maintainer,
27 who was also the sponsor of this PEP, has indicated `in the PEP 727
28 Discourse thread
29 <https://discuss.python.org/t/pep-727-documentation-metadata-in-typing/32566/183>`_
30 that ``typing_extensions`` will support ``Doc`` indefinitely. However,
31 if it should disappear from ``typing_extensions``, we provide a
32 compatible fallback. Unless you are using ``typing_extensions.Doc`` for
33 other purposes, it is recommended that you import it from this package
34 instead, to ensure future availability.
35'''
38from . import __
39from . import nomina as _nomina
42try: from typing_extensions import Doc # pyright: ignore[reportAssignmentType]
43except ImportError: # pragma: no cover
45 @__.dcls.dataclass( frozen = True, slots = True )
46 class Doc:
47 ''' Description of argument or attribute.
49 Compatible with :pep:`727` ``Doc`` objects.
50 '''
52 documentation: str
55Fragment: __.typx.TypeAlias = str | Doc
56Fragments: __.typx.TypeAlias = __.cabc.Sequence[ Fragment ]
59@__.dcls.dataclass( frozen = True, slots = True )
60class Fname:
61 ''' Name of documentation fragment in table. '''
63 name: __.typx.Annotated[
64 str, Doc( ''' Index to look up content in fragments table. ''' ) ]
67@__.dcls.dataclass( frozen = True, slots = True )
68class Raises:
69 ''' Class and description of exception which can be raised.
71 Should appear in the return annotations for a function.
72 '''
74 classes: __.typx.Annotated[
75 type[ BaseException ] | __.cabc.Sequence[ type[ BaseException ] ],
76 Doc( ''' Exception class or classes which can be raised. ''' ),
77 ]
78 description: __.typx.Annotated[
79 __.typx.Optional[ str ],
80 Doc( ''' When and why the exception is raised. ''' ),
81 ] = None
84AnnotationsArgument: __.typx.TypeAlias = __.typx.Annotated[
85 _nomina.Annotations,
86 Doc( ''' Annotations mapping for documentable object. ''' ),
87]
88FragmentsTableArgument: __.typx.TypeAlias = __.typx.Annotated[
89 _nomina.FragmentsTable,
90 Doc( ''' Table from which to copy docstring fragments. ''' ),
91]
92GlobalsLevelArgument: __.typx.TypeAlias = __.typx.Annotated[
93 int,
94 Doc(
95 ''' Stack frame level from which to obtain globals.
97 Default is 2, which is the caller of the caller.
98 ''' ),
99]
100NotifierLevelArgument: __.typx.TypeAlias = __.typx.Annotated[
101 _nomina.NotificationLevels,
102 Doc( ''' Severity level of the notification. ''' ),
103]
104NotifierMessageArgument: __.typx.TypeAlias = __.typx.Annotated[
105 str,
106 Doc( ''' Message content to notify about. ''' ),
107]
108PossessorArgument: __.typx.TypeAlias = __.typx.Annotated[
109 _nomina.Documentable,
110 Doc(
111 ''' Object being documented.
113 May be a module, class, or function.
114 ''' ),
115]
116PossessorClassArgument: __.typx.TypeAlias = __.typx.Annotated[
117 type, Doc( ''' Class being documented. ''' ) ]
118PossessorFunctionArgument: __.typx.TypeAlias = __.typx.Annotated[
119 __.cabc.Callable[ ..., __.typx.Any ],
120 Doc( ''' Function being documented. ''' ),
121]
122PossessorModuleArgument: __.typx.TypeAlias = __.typx.Annotated[
123 __.types.ModuleType, Doc( ''' Module being documented. ''' ) ]
124VisibilityAnnotationArgument: __.typx.TypeAlias = __.typx.Annotated[
125 __.typx.Any, Doc( ''' Type annotation of the attribute. ''' ) ]
126VisibilityDescriptionArgument: __.typx.TypeAlias = __.typx.Annotated[
127 __.typx.Optional[ str ],
128 Doc( ''' Optional description text for the attribute. ''' ),
129]
130VisibilityNameArgument: __.typx.TypeAlias = __.typx.Annotated[
131 str, Doc( ''' Name of the attribute being evaluated. ''' ) ]
134class Sentinels( __.enum.Enum ):
135 ''' Sentinel values used in various parts of the package. '''
137 Absent = __.enum.auto( )
138 Incomplete = __.enum.auto( )
141absent: __.typx.Annotated[
142 Sentinels, Doc( ''' Indicates annotation or other data is missing. ''' )
143] = Sentinels.Absent
144incomplete: __.typx.Annotated[
145 Sentinels, Doc( ''' Indicates annotation reduction is incomplete. ''' ),
146] = Sentinels.Incomplete
149@__.dcls.dataclass( frozen = True, kw_only = True, slots = True )
150class AdjunctsData:
151 ''' Data about type-adjacent entities. '''
153 extras: __.typx.Annotated[
154 __.cabc.MutableSequence[ __.typx.Any ],
155 Doc( ''' Additional annotations. ''' ),
156 ] = __.dcls.field( default_factory = list[ __.typx.Any ] )
157 traits: __.typx.Annotated[
158 __.cabc.MutableSet[ str ],
159 Doc( ''' Trait names collected during annotation processing. ''' ),
160 ] = __.dcls.field( default_factory = set[ str ] )
162 def copy( self ) -> __.typx.Self:
163 ''' Creates a shallow copy of the adjuncts data. '''
164 return type( self )(
165 extras = list( self.extras ),
166 traits = set( self.traits ) )
169@__.dcls.dataclass( frozen = True, kw_only = True, slots = True )
170class AnnotationsCache:
171 ''' Lookup table for reduced annotations from original annotations.
173 Has special values for absent and incomplete entries.
174 '''
176 entries: __.typx.Annotated[
177 dict[ __.typx.Any, __.typx.Any ],
178 Doc( ''' Mapping from original annotations to reduced forms. ''' ),
179 ] = __.dcls.field( default_factory = dict[ __.typx.Any, __.typx.Any ] )
181 def access(
182 self, original: __.typx.Annotated[
183 __.typx.Any,
184 Doc( ''' Original annotation to look up in cache. ''' ),
185 ]
186 ) -> __.typx.Annotated[
187 __.typx.Any,
188 Doc(
189 ''' Reduced annotation from cache.
191 Absence sentinel if not found.
192 ''' ),
193 ]:
194 ''' Accesses entry value, if it exists. '''
195 try: return self.entries.get( original, absent )
196 except TypeError: return self.entries.get( id( original ), absent )
198 def enter(
199 self,
200 original: __.typx.Annotated[
201 __.typx.Any,
202 Doc( ''' Original annotation to use as cache key. ''' ),
203 ],
204 reduction: __.typx.Annotated[
205 __.typx.Any,
206 Doc( ''' Reduced form of annotation to store as value. ''' ),
207 ] = incomplete,
208 ) -> __.typx.Any:
209 ''' Adds reduced annotation to cache, returning it.
211 Cache key is original annotation.
212 If reduction is not specified, then an incompletion sentinel is
213 added as the value for the entry.
214 '''
215 try: self.entries[ original ] = reduction
216 except TypeError: self.entries[ id( original ) ] = reduction
217 return reduction
220class AttributeAssociations( __.enum.Enum ):
221 ''' Association level of an attribute with its containing entity. '''
223 Module = __.enum.auto( )
224 Class = __.enum.auto( )
225 Instance = __.enum.auto( )
228class ValuationModes( __.enum.Enum ):
229 ''' Annotation for how default value is determined.
231 Accept means to use assigned value.
232 Suppress means to use no value.
233 Surrogate means to use surrogate value.
234 '''
236 Accept = __.enum.auto( )
237 Suppress = __.enum.auto( )
238 Surrogate = __.enum.auto( )
241@__.dcls.dataclass( frozen = True, kw_only = True, slots = True )
242class Default:
243 ''' How to process default value. '''
245 mode: __.typx.Annotated[
246 ValuationModes,
247 Doc( ''' Method for handling default value processing. ''' ),
248 ] = ValuationModes.Accept
249 surrogate: __.typx.Annotated[
250 __.typx.Any,
251 Doc(
252 ''' Alternative value to use when surrogate mode.
254 Usually a description string.
255 ''' ),
256 ] = absent
259class FragmentSources( __.enum.Enum ):
260 ''' Possible sources for documentation fragments. '''
262 Annotation = __.enum.auto( )
263 Argument = __.enum.auto( ) # *fragments
264 Attribute = __.enum.auto( ) # _dynadoc_fragments_
265 Docstring = __.enum.auto( )
266 Renderer = __.enum.auto( )
269class FragmentRectifier( __.typx.Protocol ):
270 ''' Cleans and normalizes documentation fragment. '''
272 @staticmethod
273 def __call__(
274 fragment: __.typx.Annotated[
275 str,
276 Doc( ''' Raw fragment text to be cleaned and normalized. ''' ),
277 ],
278 source: __.typx.Annotated[
279 FragmentSources,
280 Doc(
281 ''' Source type of fragment for context-aware processing.
282 ''' ),
283 ],
284 ) -> str:
285 ''' (Signature for fragment rectifier.) '''
286 raise NotImplementedError # pragma: no cover
289@__.dcls.dataclass( frozen = True, kw_only = True, slots = True )
290class InformationBase:
291 ''' Base for information on various kinds of entities. '''
293 annotation: __.typx.Annotated[
294 __.typx.Any,
295 Doc( ''' Type annotation associated with this entity. ''' ),
296 ]
297 description: __.typx.Annotated[
298 __.typx.Optional[ str ],
299 Doc( ''' Human-readable description of the entity. ''' ),
300 ]
303@__.dcls.dataclass( frozen = True, kw_only = True, slots = True )
304class ArgumentInformation( InformationBase ):
305 ''' Information about a function argument. '''
307 name: __.typx.Annotated[
308 str,
309 Doc( ''' Name of the function parameter. ''' ),
310 ]
311 paramspec: __.typx.Annotated[
312 __.inspect.Parameter,
313 Doc( ''' Inspection parameter object with various details. ''' ),
314 ]
315 default: __.typx.Annotated[
316 Default,
317 Doc( ''' Configuration for how to handle default value. ''' ),
318 ]
321@__.dcls.dataclass( frozen = True, kw_only = True, slots = True )
322class AttributeInformation( InformationBase ):
323 ''' Information about a class or module attribute. '''
325 name: __.typx.Annotated[
326 str,
327 Doc( ''' Name of the attribute. ''' ),
328 ]
329 association: __.typx.Annotated[
330 AttributeAssociations,
331 Doc( ''' Attribute associated with module, class, or instance? ''' ),
332 ]
333 default: __.typx.Annotated[
334 Default, Doc( ''' How to handle default value. ''' ) ]
337@__.dcls.dataclass( frozen = True, kw_only = True, slots = True )
338class ExceptionInformation( InformationBase ):
339 ''' Information about an exception that can be raised. '''
340 pass
343@__.dcls.dataclass( frozen = True, kw_only = True, slots = True )
344class ReturnInformation( InformationBase ):
345 ''' Information about a function's return value. '''
346 pass
349Informations: __.typx.TypeAlias = __.cabc.Sequence[ InformationBase ]
352class Notifier( __.typx.Protocol ):
353 ''' Notifies of warnings and errors. '''
355 @staticmethod
356 def __call__(
357 level: NotifierLevelArgument,
358 message: NotifierMessageArgument,
359 ) -> None:
360 ''' (Signature for notifier callback.) '''
361 raise NotImplementedError # pragma: no cover
364class Visibilities( __.enum.Enum ):
365 ''' Annotation to determine visibility of attribute.
367 Default means to defer to visibility predicate in use.
368 Conceal means to hide regardless of visibility predicate.
369 Reveal means to show regardless of visibility predicate.
370 '''
372 Default = __.enum.auto( )
373 Conceal = __.enum.auto( )
374 Reveal = __.enum.auto( )
377class VisibilityDecider( __.typx.Protocol ):
378 ''' Decides if attribute should have visible documentation. '''
380 @staticmethod
381 def __call__(
382 possessor: PossessorArgument,
383 name: VisibilityNameArgument,
384 annotation: VisibilityAnnotationArgument,
385 description: VisibilityDescriptionArgument,
386 ) -> bool:
387 ''' (Signature for visibility decider.) '''
388 raise NotImplementedError # pragma: no cover
391AnnotationsCacheArgument: __.typx.TypeAlias = __.typx.Annotated[
392 AnnotationsCache,
393 Doc(
394 ''' Cache for storing reduced annotation forms.
396 Also used for cycle detection.
397 ''' ),
398]
399InformationsArgument: __.typx.TypeAlias = __.typx.Annotated[
400 Informations,
401 Doc(
402 ''' Sequence of information blocks from object introspection.
404 Information may be about arguments to a function, attributes on a
405 class or module, exceptions raised by a function, or returns from a
406 function.
407 ''' ),
408]