Repository: deepchecks/deepchecks

Issue:
Fix API reference to load components recursively



Discussion:

Resolving patch:
diff --git a/deepchecks/base/suite.py b/deepchecks/base/suite.py
--- a/deepchecks/base/suite.py
+++ b/deepchecks/base/suite.py
@@ -22,7 +22,7 @@
 from deepchecks.utils.ipython import is_ipython_display
 
 
-__all__ = ['Suite', 'ModelComparisonSuite', 'SuiteResult']
+__all__ = ['BaseSuite', 'Suite', 'ModelComparisonSuite', 'SuiteResult']
 
 
 class SuiteResult:
@@ -62,6 +62,7 @@ class BaseSuite:
     @classmethod
     @abc.abstractmethod
     def supported_checks(cls) -> Tuple:
+        """Return list of of supported check types."""
         pass
 
     checks: OrderedDict
diff --git a/deepchecks/utils/strings.py b/deepchecks/utils/strings.py
--- a/deepchecks/utils/strings.py
+++ b/deepchecks/utils/strings.py
@@ -35,7 +35,8 @@
     'format_number',
     'format_list',
     'get_random_string',
-    'format_datetime'
+    'format_datetime',
+    'to_snake_case'
 ]
 
 
@@ -87,6 +88,18 @@ def split_camel_case(string: str) -> str:
     return ' '.join(re.findall('[A-Z][^A-Z]*', string))
 
 
+def to_snake_case(value: str) -> str:
+    """Transform camel case indentifier into snake case.
+
+    Args:
+        value (str): string to transform
+
+    Returns:
+        str: transformed value
+    """
+    return split_camel_case(value).strip().replace(' ', '_')
+
+
 def get_base_form_to_variants_dict(uniques: t.Iterable[str]) -> t.Dict[str, t.Set[str]]:
     """Create dict of base-form of the uniques to their values.
 
diff --git a/docs/source/conf.py b/docs/source/conf.py
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -3,9 +3,6 @@
 # This file only contains a selection of the most common options. For a full
 # list see the documentation:
 # https://www.sphinx-doc.org/en/master/usage/configuration.html
-
-# -- Path setup --------------------------------------------------------------
-
 import typing as t
 import inspect
 import os
@@ -14,13 +11,17 @@
 import functools
 from subprocess import check_output
 
+# -- Path setup --------------------------------------------------------------
+
 CURRENT_DIR = pathlib.Path(__file__).parent
 PROJECT_DIR = CURRENT_DIR.parent.parent
 
 sys.path.insert(0, str(PROJECT_DIR.absolute()))
 
+from deepchecks.utils.strings import to_snake_case
+
 with open(os.path.join(PROJECT_DIR, 'VERSION')) as version_file:
-    VER = version_file.read().strip()
+    VERSION = version_file.read().strip()
 
 # -- Project information -----------------------------------------------------
 
@@ -29,7 +30,7 @@
 copyright = '2021, Deepchecks'
 author = 'Deepchecks'
 is_readthedocs = os.environ.get("READTHEDOCS")
-version = os.environ.get("READTHEDOCS_VERSION") or VER
+version = os.environ.get("READTHEDOCS_VERSION") or VERSION
 language = os.environ.get("READTHEDOCS_LANGUAGE")
 
 GIT = {
@@ -45,16 +46,6 @@
 
 # -- General configuration ---------------------------------------------------
 
-# If true, Sphinx will warn about all references where the target cannot be found.
-# Default is False. You can activate this mode temporarily using the -n command-line switch.
-#
-nitpicky = True
-
-# Path to logo and favicon
-#
-html_logo = "./_static/deepchecks_logo.svg"
-html_favicon = "./_static/favicons/favicon.ico"
-
 # Add any Sphinx extension module names here, as strings. They can be
 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
 # ones.
@@ -78,14 +69,20 @@
     'sphinx_search.extension',
 ]
 
-# If true, the reST sources are included in the HTML build as _sources/name. The default is True.
+# Add any paths that contain templates here, relative to this directory.
 #
-html_copy_source = True
+templates_path = ['_templates']
 
-# The base URL which points to the root of the HTML documentation. Default ''
-# TODO: Do we need this
-# html_baseurl = ''
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This pattern also affects html_static_path and html_extra_path.
+#
+exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
 
+# If true, Sphinx will warn about all references where the target cannot be found.
+# Default is False. You can activate this mode temporarily using the -n command-line switch.
+#
+nitpicky = True
 
 # A boolean that decides whether module names are prepended to all object names.
 # Default is True.
@@ -97,6 +94,27 @@
 #
 python_use_unqualified_type_names = True
 
+
+# -- autosummary settings --------------------------------------------------
+
+# A boolean flag indicating whether to document classes and 
+# functions imported in modules. Default is False
+#
+autosummary_imported_members = True
+
+# If False and a module has the __all__ attribute set, autosummary 
+# documents every member listed in __all__ and no others. Default is True
+#
+autosummary_ignore_module_all = False
+
+# A dictionary of values to pass into the template engine’s context 
+# for autosummary stubs files.
+#
+autosummary_context = {'to_snake_case': to_snake_case}
+
+
+# -- autodoc settings --------------------------------------------------
+
 # Autodoc settings.
 # This value selects how the signature will be displayed for the class defined by autoclass directive.
 # The possible values are:
@@ -105,8 +123,17 @@
 #
 autodoc_class_signature = 'separated'
 
-# Napoleon settings
+# This value controls how to represent typehints. The setting takes the following values:
+#    'signature' – Show typehints in the signature (default)
+#    'description' – Show typehints as content of the function or method The typehints of overloaded functions or methods will still be represented in the signature.
+#    'none' – Do not show typehints
+#    'both' – Show typehints in the signature and as content of the function or method
 #
+autodoc_typehints = 'signature'
+
+
+# -- Napoleon settings --------------------------------------------------
+
 napoleon_google_docstring = True
 napoleon_numpy_docstring = True
 napoleon_include_private_with_doc = False
@@ -118,15 +145,6 @@
 napoleon_use_param = True
 napoleon_use_rtype = True
 
-# Add any paths that contain templates here, relative to this directory.
-#
-templates_path = ['_templates']
-
-# List of patterns, relative to source directory, that match files and
-# directories to ignore when looking for source files.
-# This pattern also affects html_static_path and html_extra_path.
-#
-exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
 
 # -- nbsphinx extension settings --------------------------------------------------
 
@@ -173,7 +191,7 @@
         </span>
     </div>
 
-{% set apipath =  env.config.get_check_example_api_reference(env.docname) %}
+{% set apipath = env.config.get_check_example_api_reference(env.docname) %}
 
 {% if apipath %}
 {{ apipath }}
@@ -187,6 +205,8 @@
     "crossorigin": "anonymous"
 }
 nbsphinx_assume_equations = False
+
+
 # -- Copybutton settings --------------------------------------------------
 
 # Only copy lines starting with the input prompts,
@@ -205,6 +225,7 @@
 
 
 # -- Linkcode ----------------------------------------------------------------
+
 def _import_object_from_name(module_name, fullname):
     obj = sys.modules.get(module_name)
     if obj is None:
@@ -284,7 +305,6 @@ def linkcode_resolve(domain, info):
 
 # -- Options for HTML output -------------------------------------------------
 
-
 # The theme to use for HTML and HTML Help pages.  See the documentation for
 # a list of builtin themes.
 #
@@ -296,21 +316,27 @@ def linkcode_resolve(domain, info):
 #
 html_static_path = ['_static']
 
-html_css_files = [
-    'css/custom.css',
-]
+html_css_files = ['css/custom.css',]
 
 #
 html_sidebars = {
     "**": ["sidebar-nav-bs"]
 }
 
+# Path to logo and favicon
+#
+html_logo = "./_static/deepchecks_logo.svg"
+html_favicon = "./_static/favicons/favicon.ico"
+
+# If true, the reST sources are included in the HTML build as _sources/name. The default is True.
+#
+html_copy_source = True
+
 # Theme specific options.
 # See documentation of the 'pydata_sphinx_theme' theme
 # https://pydata-sphinx-theme.readthedocs.io/en/latest/user_guide/configuring.html#adding-external-links-to-your-nav-bar
 #
 html_theme_options = {
-    "show_nav_level": 4,
     "collapse_navigation": False,
     "navbar_end": ["search-field", "navbar-icon-links", "menu-dropdown", ],
     # "page_sidebar_items": ["page-toc", "create-issue", "show-page-source"],
@@ -360,14 +386,13 @@ def get_report_issue_url(pagename: str) -> str:
     )
 
 
-def generate_colab_url(notebook_path: str) -> str:
+def generate_colab_url(notebook_path: str) -> t.Optional[str]:
     notebook_path = notebook_path.replace(".txt", "")
     notebook_path = notebook_path if notebook_path.endswith(".ipynb") else notebook_path + ".ipynb"
     notebook_name = notebook_path.split("/")[-1]
 
     if not is_example_notebook(notebook_name):
-        return None
-        raise RuntimeError(f"Not a notebook - {notebook_path}")
+        return
 
     template = (
         "https://colab.research.google.com/github/{user}/{repo}/blob/{branch}/{notebook_path}"
@@ -381,14 +406,13 @@ def generate_colab_url(notebook_path: str) -> str:
     )
 
 
-def generate_binder_url(notebook_path: str) -> str:
+def generate_binder_url(notebook_path: str) -> t.Optional[str]:
     notebook_path = notebook_path.replace(".txt", "")
     notebook_path = notebook_path if notebook_path.endswith(".ipynb") else notebook_path + ".ipynb"
     notebook_name = notebook_path.split("/")[-1]
 
     if not is_example_notebook(notebook_name):
-        return None
-        raise RuntimeError(f"Not a notebook - {notebook_path}")
+        return
 
     template = (
         "https://mybinder.org/v2/gh/{user}/{repo}/{branch}?labpath={filepath}"
@@ -409,7 +433,7 @@ def get_example_notebooks() -> t.Tuple[pathlib.Path, ...]:
     if not examples_folder.exists() or not examples_folder.is_dir():
         raise RuntimeError("Did not find the folder with the example notebooks.")
 
-    return tuple(it for it in examples_folder.glob("**/*.ipynb"))
+    return tuple(examples_folder.glob("**/*.ipynb"))
 
 
 @functools.lru_cache(maxsize=None)
@@ -424,7 +448,10 @@ def is_example_notebook(filepath: str) -> bool:
 
 
 def get_check_example_api_reference(filepath: str) -> t.Optional[str]:
-    if not filepath.startswith("docs/source/examples/checks/"):
+    if not (
+        filepath.startswith("docs/source/examples/checks/")
+        or filepath.startswith("examples/checks/")
+    ):
         return
 
     notebook_name = snake_case_to_camel_case(
@@ -440,7 +467,9 @@ def get_check_example_api_reference(filepath: str) -> t.Optional[str]:
     if check_clazz is None or not hasattr(check_clazz, "__module__"):
         return
 
-    apipath = f"/api/checks/generated/{check_clazz.__module__}.{notebook_name}"
+    clazz_module = ".".join(check_clazz.__module__.split(".")[:-1])
+
+    apipath = f"/api/generated/{clazz_module}.{notebook_name}"
     result = f"* :doc:`API Reference - {notebook_name} <{apipath}>`"
     return result
 
@@ -449,7 +478,6 @@ def get_check_example_api_reference(filepath: str) -> t.Optional[str]:
 
 
 def setup(app):
-    # app.add_directive('autoautosummary', AutoAutoSummary)
 
     def add_custom_routines(app, pagename, templatename, context, doctree):
         context["get_report_issue_url"] = get_report_issue_url


Test patch: