1- # pyright: reportMissingImports=false
21# Configuration file for the Sphinx documentation builder.
32#
43# For the full list of built-in configuration values, see the documentation:
6766autodoc_typehints_description_target = "documented"
6867
6968
70- # -- Patches ------------------ -----------------------------------------------
69+ # -- Autodocumenter extensions -----------------------------------------------
7170
7271
73- def _patch_autotypeddict_inherited_docstrings () -> None :
74- """Patch autotypeddict to include field docstrings from parent TypedDicts.
72+ def _collect_field_docstrings (cls : type ) -> dict [str , list [str ]]:
73+ """Collect field docstrings from cls and all TypedDict ancestors via __orig_bases__."""
74+ result : dict [str , list [str ]] = {}
75+ # Parents first — child docstrings overwrite via later assignment
76+ for base in getattr (cls , "__orig_bases__" , ()):
77+ origin = getattr (base , "__origin__" , base )
78+ if isinstance (origin , type ) and origin is not cls :
79+ result .update (_collect_field_docstrings (origin ))
80+ try :
81+ attr_docs = ModuleAnalyzer .for_module (cls .__module__ ).find_attr_docs ()
82+ for (_ , attr_name ), doc_lines in attr_docs .items ():
83+ result [attr_name ] = doc_lines
84+ except PycodeError :
85+ pass
86+ return result
7587
76- sphinx_toolbox's sort_members only scans self.object.__module__ for field
77- docstrings (autotypeddict.py:381-384). SDK TypedDicts like SDKDevboxCreateParams
78- inherit fields from types in other modules (e.g. DevboxCreateParams), so those
79- descriptions are lost. This patch collects docstrings from the full
80- __orig_bases__ chain.
8188
89+ class _InheritedDocsTypedDictDocumenter (TypedDictDocumenter ):
90+ """TypedDictDocumenter that collects field docstrings from parent TypedDicts.
91+
92+ Upstream only scans self.object.__module__ for field docstrings, so
93+ inherited descriptions are lost. This subclass traverses __orig_bases__.
8294 Upstream bug: https://github.com/sphinx-doc/sphinx/issues/9290
95+ Patching sphinx_toolbox 4.1.2.
8396 """
8497
85- def _collect_field_docstrings (cls : type ) -> dict [str , list [str ]]:
86- result : dict [str , list [str ]] = {}
87- visited : set [type ] = set ()
88-
89- def _walk (klass : type ) -> None :
90- if klass in visited or not hasattr (klass , "__annotations__" ):
91- return
92- visited .add (klass )
93- try :
94- for (_ , fname ), doc in ModuleAnalyzer .for_module (klass .__module__ ).find_attr_docs ().items ():
95- if fname not in result :
96- result [fname ] = doc
97- except PycodeError :
98- pass
99- for base in getattr (klass , "__orig_bases__" , []):
100- if isinstance (base , type ):
101- _walk (base )
102-
103- _walk (cls )
104- return result
105-
106- def _patched_sort_members (
107- self : TypedDictDocumenter ,
98+ def sort_members (
99+ self ,
108100 documenters : list [tuple [Documenter , bool ]],
109101 order : str ,
110102 ) -> list [tuple [Documenter , bool ]]:
103+ # Skip TypedDictDocumenter.sort_members (returns [] after adding
104+ # lines with wrong docstrings). Call ClassDocumenter.sort_members
105+ # to get the properly sorted documenters list.
111106 documenters = super (TypedDictDocumenter , self ).sort_members (documenters , order )
112107 docstrings = _collect_field_docstrings (self .object )
113-
114108 required_keys : list [str ] = []
115109 optional_keys : list [str ] = []
116110 types = get_type_hints (self .object )
@@ -126,21 +120,16 @@ def _patched_sort_members(
126120 if required_keys :
127121 self .add_line ("" , sourcename )
128122 self .add_line (":Required Keys:" , sourcename )
129- self .document_keys (required_keys , types , docstrings ) # pyright: ignore[reportUnknownMemberType]
123+ self .document_keys (required_keys , types , docstrings )
130124 self .add_line ("" , sourcename )
131125 if optional_keys :
132126 self .add_line ("" , sourcename )
133127 self .add_line (":Optional Keys:" , sourcename )
134- self .document_keys (optional_keys , types , docstrings ) # pyright: ignore[reportUnknownMemberType]
128+ self .document_keys (optional_keys , types , docstrings )
135129 self .add_line ("" , sourcename )
136130
137131 return []
138132
139- TypedDictDocumenter .sort_members = _patched_sort_members # type: ignore[assignment]
140-
141-
142- _patch_autotypeddict_inherited_docstrings ()
143-
144133
145134# -- Dynamic type documentation ----------------------------------------------
146135
@@ -170,7 +159,8 @@ def _inject_type_submodules(_app: Sphinx, docname: str, source: list[str]) -> No
170159
171160
172161def setup (app : Sphinx ) -> None :
173- app .connect ("source-read" , _inject_type_submodules ) # pyright: ignore[reportUnknownMemberType]
162+ app .add_autodocumenter (_InheritedDocsTypedDictDocumenter , override = True )
163+ app .connect ("source-read" , _inject_type_submodules )
174164
175165
176166# Intersphinx mapping
0 commit comments