1111if TYPE_CHECKING :
1212 import ast
1313
14- from griffe .dataclasses import Attribute
15- from typing_extensions import Annotated , Doc # type: ignore[attr-defined]
14+ from griffe .dataclasses import Attribute , Module , Object
15+ from typing_extensions import Annotated , Doc
1616
1717
1818class TypingDocExtension (Extension ):
1919 """Griffe extension that reads documentation from `typing.Doc`."""
2020
21- def on_attribute_instance (
22- self ,
23- * ,
24- node : Annotated [
25- ast .AST | ObjectNode ,
26- Doc ("The object/AST node describing the attribute or its definition." ),
27- ],
28- attr : Annotated [
29- Attribute ,
30- Doc ("The Griffe attribute just instantiated." ),
31- ],
32- ) -> None :
33- """Post-process Griffe attributes to create their docstring."""
34- module = _dynamic if isinstance (node , ObjectNode ) else _static
21+ def __init__ (self ) -> None :
22+ self ._handled : set [str ] = set ()
23+
24+ def _handle_attribute (self , attr : Attribute , / , * , node : ObjectNode | None = None ) -> None :
25+ if attr .path in self ._handled :
26+ return
27+ self ._handled .add (attr .path )
28+
29+ module = _dynamic if node else _static
3530
3631 new_sections = (
37- docstring := module ._attribute_docs (node , attr ),
38- deprecated_section := module ._deprecated_docs (node , attr ),
39- raises_section := module ._raises_docs (node , attr ),
40- warns_section := module ._warns_docs (node , attr ),
32+ docstring := module ._attribute_docs (attr , node = node ),
33+ deprecated_section := module ._deprecated_docs (attr , node = node ),
34+ raises_section := module ._raises_docs (attr , node = node ),
35+ warns_section := module ._warns_docs (attr , node = node ),
4136 )
4237
4338 if not any (new_sections ):
@@ -48,45 +43,31 @@ def on_attribute_instance(
4843
4944 sections = attr .docstring .parsed
5045
51- if deprecated_section := module . _deprecated_docs ( node , attr ) :
46+ if deprecated_section :
5247 sections .insert (0 , deprecated_section )
5348
54- if raises_section := module . _raises_docs ( node , attr ) :
49+ if raises_section :
5550 sections .append (raises_section )
5651
57- if warns_section := module . _warns_docs ( node , attr ) :
52+ if warns_section :
5853 sections .append (warns_section )
5954
60- def on_function_instance (
61- self ,
62- * ,
63- node : Annotated [
64- ast .AST | ObjectNode ,
65- Doc ("The object/AST node describing the function or its definition." ),
66- ],
67- func : Annotated [
68- Function ,
69- Doc (
70- # Multiline docstring to test de-indentation.
71- """
72- The Griffe function just instantiated.
73- """ ,
74- ),
75- ],
76- ) -> None :
77- """Post-process Griffe functions to add a parameters section."""
78- module = _dynamic if isinstance (node , ObjectNode ) else _static
55+ def _handle_function (self , func : Function , / , * , node : ObjectNode | None = None ) -> None :
56+ if func .path in self ._handled :
57+ return
58+ self ._handled .add (func .path )
59+
60+ module = _dynamic if node else _static
7961
80- yields_section , receives_section , returns_section = module ._yrr_docs (node , func )
8162 new_sections = (
82- deprecated_section := module ._deprecated_docs (node , func ),
83- params_section := module ._parameters_docs (node , func ),
84- other_params_section := module ._other_parameters_docs (node , func ),
85- warns_section := module ._warns_docs (node , func ),
86- raises_section := module ._raises_docs (node , func ),
87- yields_section ,
88- receives_section ,
89- returns_section ,
63+ deprecated_section := module ._deprecated_docs (func , node = node ),
64+ params_section := module ._parameters_docs (func , node = node ),
65+ other_params_section := module ._other_parameters_docs (func , node = node ),
66+ warns_section := module ._warns_docs (func , node = node ),
67+ raises_section := module ._raises_docs (func , node = node ),
68+ yields_section := module . _yields_docs ( func , node = node ) ,
69+ receives_section := module . _receives_docs ( func , node = node ) ,
70+ returns_section := module . _returns_docs ( func , node = node ) ,
9071 )
9172
9273 if not any (new_sections ):
@@ -120,3 +101,63 @@ def on_function_instance(
120101
121102 if returns_section :
122103 sections .append (returns_section )
104+
105+ def _handle_object (self , obj : Object ) -> None :
106+ if obj .is_alias :
107+ return
108+ if obj .is_module or obj .is_class :
109+ for member in obj .members .values ():
110+ self ._handle_object (member ) # type: ignore[arg-type]
111+ elif obj .is_function :
112+ self ._handle_function (obj ) # type: ignore[arg-type]
113+ elif obj .is_attribute :
114+ self ._handle_attribute (obj ) # type: ignore[arg-type]
115+
116+ def on_package_loaded (
117+ self ,
118+ * ,
119+ pkg : Annotated [
120+ Module ,
121+ Doc ("The top-level module representing a package." ),
122+ ],
123+ ) -> None :
124+ """Post-process Griffe packages recursively (non-yet handled objects only)."""
125+ self ._handle_object (pkg )
126+
127+ def on_function_instance (
128+ self ,
129+ * ,
130+ node : Annotated [
131+ ast .AST | ObjectNode ,
132+ Doc ("The object/AST node describing the function or its definition." ),
133+ ],
134+ func : Annotated [
135+ Function ,
136+ Doc ("""The Griffe function just instantiated.""" ),
137+ ],
138+ ) -> None :
139+ """Post-process Griffe functions to add a parameters section.
140+
141+ It applies only for dynamic analysis.
142+ """
143+ if isinstance (node , ObjectNode ):
144+ self ._handle_function (func , node = node )
145+
146+ def on_attribute_instance (
147+ self ,
148+ * ,
149+ node : Annotated [
150+ ast .AST | ObjectNode ,
151+ Doc ("The object/AST node describing the attribute or its definition." ),
152+ ],
153+ attr : Annotated [
154+ Attribute ,
155+ Doc ("The Griffe attribute just instantiated." ),
156+ ],
157+ ) -> None :
158+ """Post-process Griffe attributes to create their docstring.
159+
160+ It applies only for dynamic analysis.
161+ """
162+ if isinstance (node , ObjectNode ):
163+ self ._handle_attribute (attr , node = node )
0 commit comments