@@ -35,12 +35,21 @@ def __init__(self):
35
35
self .packages : Dict [str , Any ] = {}
36
36
self .module_paths : Dict [str , str ] = {}
37
37
38
+ # Hardcoded exclusions - classes/modules to skip during documentation generation
39
+ self .excluded_classes = [
40
+ # Exclude the deprecated lowercase version since we have the proper cased version
41
+ "plotly.graph_objects.Histogram2dcontour" ,
42
+ ]
43
+ self .excluded_modules = [
44
+ # Add any modules to exclude here if needed
45
+ ]
46
+
38
47
def is_class (self , obj ) -> bool :
39
48
"""Check if an object is a class."""
40
49
return inspect .isclass (obj ) and not obj .__name__ .startswith ('_' )
41
50
42
- def is_deprecated_class (self , full_class_name : str , class_obj : Any ) -> bool :
43
- """Check if a class is deprecated by testing for deprecation warnings ."""
51
+ def get_deprecation_info (self , full_class_name : str , class_obj : Any ) -> tuple [ bool , str ] :
52
+ """Check if a class is deprecated and get the actual deprecation message ."""
44
53
import warnings
45
54
46
55
try :
@@ -53,12 +62,17 @@ def is_deprecated_class(self, full_class_name: str, class_obj: Any) -> bool:
53
62
# Check if any warnings contain "deprecat"
54
63
for warning in w :
55
64
if 'deprecat' in str (warning .message ).lower ():
56
- return True
57
- return False
65
+ return True , str ( warning . message )
66
+ return False , ""
58
67
except Exception :
59
68
# If we can't instantiate it, assume it's not deprecated
60
69
# (it might just require parameters or have other issues)
61
- return False
70
+ return False , ""
71
+
72
+ def is_deprecated_class (self , full_class_name : str , class_obj : Any ) -> bool :
73
+ """Check if a class is deprecated by testing for deprecation warnings."""
74
+ is_deprecated , _ = self .get_deprecation_info (full_class_name , class_obj )
75
+ return is_deprecated
62
76
63
77
def is_package (self , obj ) -> bool :
64
78
"""Check if an object is a package/module."""
@@ -97,6 +111,12 @@ def inspect_module(self, module, prefix: str = "") -> None:
97
111
public_full_name = module_name .replace ("plotly.graph_objs" , "plotly.graph_objects" ) + f".{ attr_name } "
98
112
else :
99
113
public_full_name = f"{ module_name } .{ attr_name } "
114
+
115
+ # Skip excluded classes
116
+ if public_full_name in self .excluded_classes :
117
+ print (f" Skipping excluded class: { public_full_name } " )
118
+ continue
119
+
100
120
self .classes [public_full_name ] = attr
101
121
print (f" Found class: { public_full_name } " )
102
122
@@ -107,6 +127,12 @@ def inspect_module(self, module, prefix: str = "") -> None:
107
127
public_package_name = full_name
108
128
if full_name .startswith ("plotly.graph_objs" ):
109
129
public_package_name = full_name .replace ("plotly.graph_objs" , "plotly.graph_objects" )
130
+
131
+ # Skip excluded modules
132
+ if public_package_name in self .excluded_modules :
133
+ print (f" Skipping excluded module: { public_package_name } " )
134
+ continue
135
+
110
136
self .packages [public_package_name ] = attr
111
137
self .module_paths [public_package_name ] = self .get_module_path (attr )
112
138
print (f" Found package: { public_package_name } " )
@@ -183,11 +209,15 @@ def generate_class_page(self, class_name: str, class_obj: Any) -> Path:
183
209
content = f"# { class_name } \n \n "
184
210
185
211
# Check if this is a deprecated class
186
- if self .inspector .is_deprecated_class (class_name , class_obj ):
187
- content += f"**⚠️ DEPRECATED**: This class is deprecated and may not be available for import.\n \n "
188
- content += f"Please refer to the specific implementation in the appropriate submodule.\n \n "
189
- # Don't use ::: syntax for deprecated classes as they can't be imported
190
- content += f"## Deprecated Class: { class_name } \n \n "
212
+ is_deprecated , deprecation_message = self .inspector .get_deprecation_info (class_name , class_obj )
213
+ if is_deprecated :
214
+ content += f"!!! info \" Deprecated\" \n "
215
+ # Use the actual deprecation message, properly indented
216
+ for line in deprecation_message .split ('\n ' ):
217
+ content += f" { line } \n "
218
+ content += "\n "
219
+ # Still generate the reference documentation for deprecated classes
220
+ content += f"::: { class_name } \n "
191
221
else :
192
222
content += f"::: { class_name } \n "
193
223
@@ -245,29 +275,31 @@ def generate_package_index(self, package_name: str, package_obj: Any) -> Path:
245
275
if package_obj .__doc__ :
246
276
content += f"{ package_obj .__doc__ } \n \n "
247
277
248
- # Add classes section
278
+ # Add classes section with individual headings for TOC
249
279
if package_classes :
250
280
content += "## Classes\n \n "
251
281
for class_name in sorted (package_classes ):
252
282
class_display_name = class_name .split ('.' )[- 1 ]
253
283
class_file_name = f"{ class_display_name } .md"
254
- content += f"- [{ class_display_name } ]({ class_file_name } )\n "
284
+ # Add individual class as H3 heading for TOC
285
+ content += f"### [{ class_display_name } ]({ class_file_name } )\n \n "
255
286
content += "\n "
256
287
257
- # Add subpackages section
288
+ # Add submodules section
258
289
if package_subpackages :
259
- content += "## Packages \n \n "
290
+ content += "## Submodules \n \n "
260
291
for subpackage_name in sorted (package_subpackages ):
261
292
subpackage_display_name = subpackage_name .split ('.' )[- 1 ]
262
293
# Always link to local stub within the -package folder to avoid relative path issues
263
294
subpackage_folder_name = f"{ subpackage_display_name } -package"
264
295
link = f"{ subpackage_folder_name } /index.md"
265
- content += f"- [{ subpackage_display_name } ]({ link } )\n "
296
+ # Add individual submodule as H3 heading for TOC
297
+ content += f"### [{ subpackage_display_name } ]({ link } )\n \n "
266
298
content += "\n "
267
299
268
- # If no classes or packages , add a note
300
+ # If no classes or submodules , add a note
269
301
if not package_classes and not package_subpackages :
270
- content += "This package contains no public classes or subpackages .\n "
302
+ content += "This module contains no public classes or submodules .\n "
271
303
272
304
# Write file
273
305
with open (file_path , 'w' ) as f :
@@ -307,32 +339,42 @@ def generate_main_index(self) -> Path:
307
339
content = "# plotly.graph_objects\n \n "
308
340
content += "The main package containing all Plotly graph objects, traces, and layout components.\n \n "
309
341
310
- if top_level_classes :
342
+ # Separate classes into current and deprecated
343
+ current_classes = []
344
+ deprecated_classes = []
345
+
346
+ for short_name , full_name in top_level_classes :
347
+ class_obj = self .inspector .classes [full_name ]
348
+ if self .inspector .is_deprecated_class (full_name , class_obj ):
349
+ deprecated_classes .append ((short_name , full_name ))
350
+ else :
351
+ current_classes .append ((short_name , full_name ))
352
+
353
+ # Add current classes section
354
+ if current_classes :
311
355
content += "## Classes\n \n "
312
- for short_name , full_name in top_level_classes :
313
- # Check if deprecated - get the class object
314
- class_obj = self .inspector .classes [full_name ]
315
- if self .inspector .is_deprecated_class (full_name , class_obj ):
316
- content += f"- [{ short_name } ]({ short_name } .md) ⚠️ *Deprecated*\n "
317
- else :
318
- content += f"- [{ short_name } ]({ short_name } .md)\n "
356
+ for short_name , full_name in current_classes :
357
+ # Add individual class as H3 heading for TOC
358
+ content += f"### [{ short_name } ]({ short_name } .md)\n \n "
319
359
content += "\n "
320
360
321
361
if top_level_packages :
322
- content += "## Packages \n \n "
362
+ content += "## Modules \n \n "
323
363
for short_name , full_name in top_level_packages :
324
364
package_folder_name = f"{ short_name } -package"
325
- content += f"- [{ short_name } ]({ package_folder_name } /index.md)\n "
365
+ # Add individual module as H3 heading for TOC
366
+ content += f"### [{ short_name } ]({ package_folder_name } /index.md)\n \n "
326
367
content += "\n "
327
368
328
- # Check if any deprecated classes exist by testing a known deprecated class
329
- try :
330
- angular_axis_obj = self .inspector .classes .get ("plotly.graph_objects.AngularAxis" )
331
- if angular_axis_obj and self .inspector .is_deprecated_class ("plotly.graph_objects.AngularAxis" , angular_axis_obj ):
332
- content += "## Notes\n \n "
333
- content += "⚠️ **Deprecated Classes**: Some classes marked as deprecated are legacy classes that have been replaced with more specific implementations in submodules. Please refer to the specific implementation in the appropriate submodule for current usage.\n "
334
- except Exception :
335
- pass # Skip notes section if we can't check deprecation
369
+ # Add deprecated classes section at the end
370
+ if deprecated_classes :
371
+ content += "## Deprecated Classes\n \n "
372
+ content += "!!! info \" Deprecated Classes\" \n "
373
+ content += " These classes are deprecated and may not be available for import. Please refer to the specific implementation in the appropriate submodule for current usage.\n \n "
374
+ for short_name , full_name in deprecated_classes :
375
+ # Add individual deprecated class as H3 heading for TOC with clean (Deprecated) format
376
+ content += f"### [{ short_name } ]({ short_name } .md) (Deprecated)\n \n "
377
+ content += "\n "
336
378
337
379
# Write the file
338
380
file_path .write_text (content )
0 commit comments