Source code for conf

# Configuration file for the Sphinx documentation builder.
#
# For the full list of built-in configuration values, see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html

import logging
import os
import shutil
import sys

from utils.file_ops import get_git_repo_name, get_git_root
from utils.generate_rst import EXCLUDED_DIRS, run_generator

_PROJECT_ROOT = get_git_root()
if _PROJECT_ROOT is None:
    _PROJECT_ROOT = os.getcwd()

PROJECT_ROOT: str = _PROJECT_ROOT
PROJECT_NAME: str = get_git_repo_name()
DESTINATION: str = os.path.join(PROJECT_ROOT, "source/reports")
sys.path.insert(0, PROJECT_ROOT)
print(f"Root directory: {PROJECT_ROOT}")


[docs] def add_all_subdirectories_to_path( root_dir: str | None = PROJECT_ROOT, excluded_dirs: list[str] = EXCLUDED_DIRS ) -> None: """Recursively adds all subdirectories within the root directory to sys.path. This is so that the .rst files and Sphinx can see modules in other directories. Args: root_dir (str): The root directory to start searching from. Defaults to PROJECT_ROOT. excluded_dirs (list, optional): A list of directory names to exclude. Defaults to EXCLUDED_DIRS. """ if root_dir is None: return excluded_dirs_set = set(excluded_dirs) for root, dirs, _files in os.walk(root_dir): # Modify dirs in-place to prevent os.walk from descending into excluded directories dirs[:] = [ d for d in dirs if d not in excluded_dirs_set and os.path.relpath(os.path.join(root, d), root_dir) not in excluded_dirs_set ] sys.path.append(root)
INCLUDED_NOTEBOOKS: list[ str ] = [ # Notebooks to include in the source/reports/ directory # "example_notebook.ipynb", ] # --- Setup Logging --- logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s")
[docs] def clear_destination() -> None: """Removes old copies from the destination folder. Raises: Exception: If the destination folder cannot be cleared. """ try: shutil.rmtree(DESTINATION, ignore_errors=True) os.makedirs(DESTINATION, exist_ok=True) logging.info(f"Cleared and recreated directory: {DESTINATION}") except Exception as e: logging.error(f"Failed to clear destination folder: {e}") raise
[docs] def is_included_notebook(filename: str) -> bool: """Checks if a file is a specified Jupyter Notebook. Args: filename (str): The name of the file to check. Returns: bool: True if the file is in INCLUDED_NOTEBOOKS, False otherwise. """ return filename in INCLUDED_NOTEBOOKS
[docs] def should_skip_directory(directory: str) -> bool: """Checks if a directory should be skipped based on EXCLUDED_DIRS. Args: directory (str): The directory name to check. Returns: bool: True if the directory should be skipped, False otherwise. """ return any(excluded in directory for excluded in EXCLUDED_DIRS)
[docs] def copy_notebooks() -> None: """Walks through project directories and copies specified .ipynb files. Raises: Exception: If a file copy operation fails. """ try: for root, dirs, files in os.walk(PROJECT_ROOT): # Convert root to absolute path for reliable comparison abs_root = os.path.abspath(root) # Skip processing files within the destination directory if abs_root.startswith(os.path.abspath(DESTINATION)): continue # Exclude directories that should be skipped dirs[:] = [ d for d in dirs if not should_skip_directory(d) and os.path.abspath(os.path.join(root, d)) != os.path.abspath(DESTINATION) ] for file in files: if is_included_notebook(file): # Get source path and relative path src = os.path.join(root, file) relative_path = os.path.relpath(root, PROJECT_ROOT) # Create destination directory in source/ dest_dir = os.path.join(DESTINATION, relative_path) os.makedirs(dest_dir, exist_ok=True) shutil.copy(src, dest_dir) # Copy the file logging.info(f"Copied {src} to {dest_dir}") else: src = os.path.join(root, file) # logging.info(f"Skipped {src} (not in the included list)") except Exception as e: logging.error(f"Failed during notebook copy: {e}") raise
[docs] def import_notebooks() -> None: """Executes the clear and copy process for Jupyter Notebooks to be included. Clears the destination directory and then copies the specified notebooks. """ clear_destination() copy_notebooks() logging.info("All notebooks successfully copied.")
[docs] def main() -> None: """Sets up working directories and imports notebooks. This is the main entry point for the custom configuration logic in conf.py. """ add_all_subdirectories_to_path() run_generator(PROJECT_ROOT, EXCLUDED_DIRS) import_notebooks()
# if __name__ == "__main__": # Unfortunately the guard does means it won't run using the make file (terminal `make html`) main() # -- Project information ----------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information project = PROJECT_NAME copyright = "2026, Michael Evans" author = "Michael Evans" release = "0.1.0" # -- General configuration --------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration extensions = [ "sphinx.ext.autodoc", "sphinx.ext.todo", "sphinx.ext.napoleon", # To support NumPy and Google style docstrings, REMOVE if using reST format "sphinx.ext.intersphinx", "sphinx.ext.viewcode", "sphinx.ext.doctest", "sphinx_copybutton", # Adds a copy button for code blocks "myst_parser", # Allows Sphinx to read markdown files (README.md) # 'myst_nb', # Use Myst for notebooks (doesn't seem to work properly, use pandoc instead) "nbsphinx", # Allows Sphinx to document Jupyter Notebook files "pydata_sphinx_theme", # Pydata theme (used by pandas and XlsxWriter) # 'sphinx_rtd_theme', # Readthedocs theme ] nbsphinx_execute = ( "never" # 'never' if you don't want to execute notebooks during build ('auto') ) intersphinx_mapping = { "python": ("https://docs.python.org/3", None), "numpy": ("https://numpy.org/doc/stable/", None), "pandas": ("https://pandas.pydata.org/docs/", None), "matplotlib": ("https://matplotlib.org/stable/", None), "scipy": ("https://docs.scipy.org/doc/scipy/", None), "jinja2": ("https://jinja.palletsprojects.com/en/stable/", None), # 'plotly': ('https://plotly.com/python/all-about-plotly/', None), # No .inv found # 'looker_sdk': ('https://looker-open-source.github.io/looker-sdk-py/', None), # No .inv found # Add other libraries as needed } templates_path = ["_templates"] exclude_patterns: list[str] = [] todo_include_todos = True # -- Options for HTML output ------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output html_theme = "pydata_sphinx_theme" # html_theme = 'sphinx_rtd_theme' # Readthedocs theme html_static_path = ["_static"] for path in html_static_path: if not os.path.exists(path): os.makedirs(path)