22
33import functools
44import pathlib
5+ import sys
6+
7+ if sys .version_info >= (3 , 11 ):
8+ from enum import StrEnum
9+ else :
10+ from backports .strenum import StrEnum
11+ from typing import List
512
613import sphinx
714import sphinx .util
1320
1421LOGGER = sphinx .util .logging .getLogger (__name__ )
1522
23+
1624def _trace_visibility (app , msg : str , verbose = 1 ) -> None :
1725 if app .config .autoapi_verbose_visibility >= verbose :
1826 LOGGER .info (colorize ("bold" , f"[AutoAPI] [Visibility] { msg } " ))
@@ -35,6 +43,21 @@ def _format_args(args_info, include_annotations=True, ignore_self=None):
3543 return ", " .join (result )
3644
3745
46+ class HideReason (StrEnum ):
47+ NOT_HIDDEN = "not hidden"
48+ UNDOC_MEMBER = "undocumented"
49+ PRIVATE_MEMBER = "a private member"
50+ SPECIAL_MEMBER = "a special member"
51+ IMPORTED_MEMBER = "an imported member"
52+ INHERITED_MEMBER = "an inherited member"
53+ IS_NEW_OR_INIT = "__new__ or __init__"
54+ NOT_IN_ALL = "not in __all__ for module"
55+ NOT_PUBLIC = "assumed to not be public API"
56+ PARENT_HIDDEN = "parent is hidden"
57+ STD_LIBRARY = "part of Python standard library"
58+ SKIP_MEMBER = "`autoapi-skip-member` returned false for the object"
59+
60+
3861class PythonObject :
3962 """A class representing an entity from the parsed source code.
4063
@@ -50,7 +73,13 @@ class PythonObject:
5073 type : str
5174
5275 def __init__ (
53- self , obj , jinja_env , app , url_root , options = None , class_content = "class"
76+ self ,
77+ obj ,
78+ jinja_env ,
79+ app ,
80+ url_root ,
81+ options : List [str ] = [],
82+ class_content = "class" ,
5483 ):
5584 self .app = app
5685 self .obj = obj
@@ -84,8 +113,7 @@ def __init__(
84113
85114 # For later
86115 self ._class_content = class_content
87- self ._display_cache : bool | None = None
88- self ._skip_reason = None
116+ self ._display_cache : HideReason | None = None
89117
90118 def __getstate__ (self ):
91119 """Obtains serialisable data for pickling."""
@@ -199,22 +227,65 @@ def is_special_member(self) -> bool:
199227 """Whether this object is a special member (True) or not (False)."""
200228 return self .short_name .startswith ("__" ) and self .short_name .endswith ("__" )
201229
230+ @property
231+ def hide_reason (self ) -> HideReason :
232+ skip_undoc_member = self .is_undoc_member and "undoc-members" not in self .options
233+ skip_private_member = (
234+ self .is_private_member and "private-members" not in self .options
235+ )
236+ skip_special_member = (
237+ self .is_special_member and "special-members" not in self .options
238+ )
239+ skip_imported_member = self .imported and "imported-members" not in self .options
240+ skip_inherited_member = (
241+ self .inherited and "inherited-members" not in self .options
242+ )
243+
244+ reason = HideReason .NOT_HIDDEN
245+ if self .obj .get ("hide-reason" ):
246+ reason = self .obj .get ("hide-reason" )
247+ elif skip_undoc_member :
248+ reason = HideReason .UNDOC_MEMBER
249+ elif skip_private_member :
250+ reason = HideReason .UNDOC_MEMBER
251+ elif skip_special_member :
252+ reason = HideReason .SPECIAL_MEMBER
253+ elif skip_imported_member :
254+ reason = HideReason .IMPORTED_MEMBER
255+ elif skip_inherited_member :
256+ reason = HideReason .INHERITED_MEMBER
257+
258+ # Allow user to override
259+ # If we told the api we were skipping already, keep the reason as originally
260+ skip = reason != HideReason .NOT_HIDDEN
261+ api_says_skip = self .app .emit_firstresult (
262+ "autoapi-skip-member" , self .type , self .id , self , skip , self .options
263+ )
264+ if not skip and api_says_skip :
265+ reason = HideReason .SKIP_MEMBER
266+
267+ return reason
268+
202269 @property
203270 def display (self ) -> bool :
204271 """Whether this object should be displayed in documentation.
205272
206273 This attribute depends on the configuration options given in
207274 :confval:`autoapi_options` and the result of :event:`autoapi-skip-member`.
208275 """
209- skip = self . _should_skip ()
276+
210277 if self ._display_cache is None :
211- self ._display_cache = not self ._ask_ignore (skip )
212- if self ._display_cache is False :
213- _trace_visibility (self .app , self ._skip_reason )
278+ self ._display_cache = self .hide_reason
279+ if self ._display_cache != HideReason .NOT_HIDDEN :
280+ _trace_visibility (
281+ self .app , f"Skipping { self .id } due to { self .hide_reason } "
282+ )
214283 else :
215- _trace_visibility (self .app , f"Skipping { self .id } due to cache" , verbose = 2 )
284+ _trace_visibility (
285+ self .app , f"Skipping { self .id } due to { self .hide_reason } " , verbose = 2
286+ )
216287
217- return self ._display_cache
288+ return self ._display_cache == HideReason . NOT_HIDDEN
218289
219290 @property
220291 def summary (self ) -> str :
@@ -230,57 +301,6 @@ def summary(self) -> str:
230301
231302 return ""
232303
233- def _should_skip (self ) -> bool :
234- skip_undoc_member = self .is_undoc_member and "undoc-members" not in self .options
235- skip_private_member = (
236- self .is_private_member and "private-members" not in self .options
237- )
238- skip_special_member = (
239- self .is_special_member and "special-members" not in self .options
240- )
241- skip_imported_member = self .imported and "imported-members" not in self .options
242- skip_inherited_member = (
243- self .inherited and "inherited-members" not in self .options
244- )
245-
246- reason = ""
247- if self .obj .get ("hide" , False ):
248- reason = "marked hidden by mapper"
249- elif skip_undoc_member :
250- reason = "is undocumented"
251- elif skip_private_member :
252- reason = "is a private member"
253- elif skip_special_member :
254- reason = "is a special member"
255- elif skip_imported_member :
256- reason = "is an imported member"
257- elif skip_inherited_member :
258- reason = "is an inherited member"
259-
260- self ._skip_reason = f"Skipping { self .id } as { reason } "
261-
262- return (
263- self .obj .get ("hide" , False )
264- or skip_undoc_member
265- or skip_private_member
266- or skip_special_member
267- or skip_imported_member
268- or skip_inherited_member
269- )
270-
271- def _ask_ignore (self , skip : bool ) -> bool :
272-
273- ask_result = self .app .emit_firstresult (
274- "autoapi-skip-member" , self .type , self .id , self , skip , self .options
275- )
276-
277- if ask_result is not None :
278- reason = f"Skipping as 'autoapi-skip-member' returned { ask_result } "
279- if self ._skip_reason :
280- reason += f"Passed skip={ skip } to 'autoapi-skip-member' as { self ._skip_reason } "
281- self ._skip_reason = reason
282- return ask_result if ask_result is not None else skip
283-
284304 def _children_of_type (self , type_ : str ) -> list [PythonObject ]:
285305 return [child for child in self .children if child .type == type_ ]
286306
@@ -339,14 +359,17 @@ def __init__(self, *args, **kwargs):
339359 Can be any of: abstractmethod, async, classmethod, property, staticmethod.
340360 """
341361
342- def _should_skip (self ) -> bool :
362+ @property
363+ def hide_reason (self ) -> HideReason :
343364 is_new_or_init = self .name in (
344365 "__new__" ,
345366 "__init__" ,
346367 )
347- if not super ()._should_skip and is_new_or_init :
348- self ._skip_reason = f"Skipping method { self .id } as is __new__ or __init__"
349- return super ()._should_skip () or is_new_or_init
368+ hide_reason = super ().hide_reason
369+ if hide_reason != HideReason .NOT_HIDDEN and is_new_or_init :
370+ return HideReason .IS_NEW_OR_INIT
371+ return hide_reason
372+
350373
351374class PythonProperty (PythonObject ):
352375 """The representation of a property on a class."""
0 commit comments