@@ -34,6 +34,70 @@ def test_cm_stub_matches_runtime_colormaps():
3434 assert runtime_cmaps == stubbed_cmaps
3535
3636
37+ def test_typing_aliases_documented ():
38+ """Every public type in typing.py is documented or intentionally undocumented."""
39+ import ast
40+
41+ typing_py_path = Path (__file__ ).parent .parent / "typing.py"
42+ assert typing_py_path .exists (), f"{ typing_py_path } does not exist"
43+ tree = ast .parse (typing_py_path .read_text (encoding = "utf-8" ))
44+
45+ # Collect all public module-level assignment names (both annotated and plain).
46+ defined_types = set ()
47+ for node in ast .iter_child_nodes (tree ):
48+ if isinstance (node , ast .AnnAssign ) and isinstance (node .target , ast .Name ):
49+ name = node .target .id
50+ elif isinstance (node , ast .Assign ) and len (node .targets ) == 1 :
51+ target = node .targets [0 ]
52+ name = target .id if isinstance (target , ast .Name ) else None
53+ else :
54+ continue
55+ if name is not None and not name .startswith ("_" ):
56+ defined_types .add (name )
57+
58+ assert defined_types , "No type definitions found in typing.py"
59+
60+ rst_path = (
61+ Path (__file__ ).parent .parent .parent .parent / "doc" / "api" / "typing_api.rst"
62+ )
63+ assert rst_path .exists (), f"{ rst_path } does not exist"
64+ rst_content = rst_path .read_text (encoding = "utf-8" )
65+
66+ # Collect documented ``.. autodata::`` entries.
67+ documented = set (
68+ re .findall (
69+ r"^\.\.\s+autodata::\s+matplotlib\.typing\.(\w+)" ,
70+ rst_content ,
71+ re .MULTILINE ,
72+ )
73+ )
74+ assert documented , "No autodata entries found in typing_api.rst"
75+
76+ # Collect types listed under the comment
77+ # ".. intentionally undocumented types (one type per row)".
78+ # Each type must be indented and an empty line ends the section.
79+ intentionally_undocumented = set ()
80+ marker = ".. intentionally undocumented types (one type per row)"
81+ lines_following_marker = rst_content .split (marker , 1 )[1 ].splitlines ()[1 :]
82+ for line in lines_following_marker :
83+ if not line or not line [0 ].isspace ():
84+ break
85+ intentionally_undocumented .add (line .strip ())
86+
87+ accounted_for = documented | intentionally_undocumented
88+
89+ missing = defined_types - accounted_for
90+ assert not missing , (
91+ f"Types defined in typing.py but not in typing_api.rst "
92+ f"(document them or add to 'intentionally undocumented types'): { missing } "
93+ )
94+
95+ extra = accounted_for - defined_types
96+ assert not extra , (
97+ f"Types listed in typing_api.rst but not defined in typing.py: { extra } "
98+ )
99+
100+
37101def test_rcparam_stubs ():
38102 runtime_rc_keys = {
39103 name for name in plt .rcParamsDefault .keys ()
0 commit comments