| # Copyright (c) 2009, Giampaolo Rodola. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """Sphinx configuration file. |
| |
| Sphinx doc: |
| https://www.sphinx-doc.org/en/master/usage/configuration.html |
| """ |
| |
| import datetime |
| import importlib.util |
| import locale |
| import os |
| import pathlib |
| import sys |
| import time |
| |
| _HERE = pathlib.Path(__file__).resolve().parent |
| _ROOT_DIR = _HERE.parent |
| sys.path.insert(0, str(_HERE / "_ext")) # needed to load local extensions |
| |
| |
| # Load _bootstrap.py (at the repo root) without putting the repo |
| # root on sys.path. Doing so would expose the uncompiled source |
| # `psutil/` package and shadow any installed psutil, breaking |
| # `import psutil` at build time (needed by sphinx-codeautolink to |
| # resolve things like `p.name()` in code blocks). |
| def _load(path): |
| spec = importlib.util.spec_from_file_location(path.stem, path) |
| mod = importlib.util.module_from_spec(spec) |
| spec.loader.exec_module(mod) |
| return mod |
| |
| |
| get_version = _load(_ROOT_DIR / "_bootstrap.py").get_version |
| |
| PROJECT_NAME = "psutil" |
| AUTHOR = "Giampaolo Rodola" |
| THIS_YEAR = str(datetime.datetime.now().year) |
| VERSION = get_version() |
| |
| # ===================================================================== |
| # Core |
| # ===================================================================== |
| |
| needs_sphinx = "9.1" |
| language = "en" |
| nitpicky = True # always warn on unresolved cross-references |
| |
| # ===================================================================== |
| # Extensions |
| # ===================================================================== |
| |
| _third_party_exts = [ |
| "ablog", |
| "notfound.extension", # custom 404 page |
| "sphinx.ext.extlinks", |
| "sphinx.ext.githubpages", # writes .nojekyll + CNAME from html_baseurl |
| "sphinx.ext.intersphinx", |
| "sphinx.ext.viewcode", |
| "sphinx_codeautolink", |
| "sphinx_copybutton", |
| "sphinx_design", # tabbed code examples on the home page |
| "sphinx_sitemap", |
| "sphinxext.opengraph", |
| ] |
| |
| _local_exts = [ # defined in the _ext/ folder |
| "ablog_extras", |
| "availability", |
| "changelog_anchors", |
| "check_python_syntax", |
| "field_role", |
| "genindex_filter", |
| "giscus", |
| "glossary_toc", |
| "label_role", |
| "notfound_extras", |
| "opengraph_override", |
| "post_banner", |
| "proc_role", |
| "substitutions", |
| ] |
| |
| extensions = _third_party_exts + _local_exts |
| |
| # ===================================================================== |
| # Project metadata |
| # ===================================================================== |
| |
| project = PROJECT_NAME |
| author = AUTHOR |
| version = release = VERSION |
| copyright = f"2009-{THIS_YEAR} {AUTHOR}" # shown in the footer |
| |
| # ===================================================================== |
| # Cross-references and external links |
| # ===================================================================== |
| |
| intersphinx_mapping = { |
| "python": ("https://docs.python.org/3", None), |
| } |
| extlinks = { |
| "gh": ("https://github.com/giampaolo/psutil/issues/%s", "#%s"), |
| "pr": ("https://github.com/giampaolo/psutil/pull/%s", "PR-%s"), |
| "user": ("https://github.com/%s", "@%s"), |
| "commit": ("https://github.com/giampaolo/psutil/commit/%s", "%s"), |
| "pypi": ("https://pypi.org/project/psutil/%s/", "%s"), |
| "bpo": ("https://bugs.python.org/issue%s", "BPO-%s"), |
| "cpy": ("https://github.com/python/cpython/issues/%s", "cpython/#%s"), |
| "cpy-pr": ("https://github.com/python/cpython/pull/%s", "cpython/PR-%s"), |
| "src": ("https://github.com/giampaolo/psutil/blob/master/%s", "%s"), |
| } |
| manpages_url = "https://manpages.debian.org/{path}" |
| |
| # ===================================================================== |
| # Paths |
| # ===================================================================== |
| |
| exclude_patterns = ["_build"] |
| rst_prolog = ".. currentmodule:: psutil\n" # Prepended to every .rst file |
| |
| # ===================================================================== |
| # HTML |
| # ===================================================================== |
| |
| # Canonical site URL. Picked up by Sphinx for <link rel="canonical"> |
| # tags. Reused below by sphinxext-opengraph (og:url), sphinx-sitemap, |
| # and (via blog_baseurl) ablog's atom feed. |
| html_baseurl = "https://psutil.io/" |
| |
| # sphinx-notfound-page: absolute URL prefix for static files and |
| # nav links on 404.html. |
| notfound_urls_prefix = "/" |
| |
| html_title = PROJECT_NAME |
| html_favicon = "_static/images/favicon.svg" |
| html_last_updated_fmt = "%Y-%m-%d" # ISO date shown in the footer |
| html_show_sphinx = False # removes "Created using Sphinx" in the footer |
| html_show_sourcelink = False # removes "View page source" sidebar link |
| |
| # Sidebar shows method() instead of Class.method() |
| toc_object_entries_show_parents = "hide" |
| |
| # ===================================================================== |
| # Plugins |
| # ===================================================================== |
| |
| copybutton_exclude = ".linenos, .gp" |
| |
| # ===================================================================== |
| # Theming |
| # ===================================================================== |
| |
| # Custom psutil-sphinx-theme, built on top of Sphinx's `basic` theme. |
| |
| html_theme = "basic" |
| html_theme_options = { |
| "globaltoc_maxdepth": 1, |
| "globaltoc_collapse": False, |
| "globaltoc_includehidden": True, |
| } |
| html_static_path = ["_static"] |
| html_extra_path = ["_extra"] # robots.txt, copied verbatim to site root |
| templates_path = ["_templates"] |
| pygments_style = "tango" # base palette (overridden by css/code.css) |
| |
| |
| def _css_files(): |
| css_dir = _HERE / "_static" / "css" |
| # giscus.css is loaded inside the giscus iframe (see |
| # _templates/comments.html), never by our own pages. Linking it |
| # here would make every page fetch its @import from giscus.app. |
| files = sorted( |
| p.name for p in css_dir.glob("*.css") if p.name != "giscus.css" |
| ) |
| head = ["base.css", "fonts.css", "fontawesome.css", "typography.css"] |
| tail = ["home.css"] |
| middle = [f for f in files if f not in head + tail] |
| return [f"css/{name}" for name in head + middle + tail if name in files] |
| |
| |
| html_css_files = _css_files() |
| |
| |
| def _js_files(): |
| js_dir = _HERE / "_static" / "js" |
| files = sorted(p.name for p in js_dir.glob("*.js")) |
| return [(f"js/{name}", {"defer": "defer"}) for name in files] |
| |
| |
| html_js_files = _js_files() |
| |
| # ===================================================================== |
| # Blog (ablog package) |
| # ===================================================================== |
| |
| # Force UTC for build-time timestamps so atom feed entries are |
| # the same across build hosts (CI runs UTC; local devs may not). |
| os.environ["TZ"] = "UTC" |
| if hasattr(time, "tzset"): |
| time.tzset() |
| |
| # Fix for ablog, which otherwise formats dates in the local locale. |
| try: |
| locale.setlocale(locale.LC_TIME, "C") |
| except locale.Error: |
| pass |
| |
| # Drives atom feed entry <id>s and <link>s. Same value as html_baseurl |
| # so feed URLs track canonicals URLs. |
| blog_baseurl = html_baseurl |
| |
| # ===================================================================== |
| # Comments (giscus) |
| # ===================================================================== |
| |
| giscus_repo = "giampaolo/psutil-blog-comments" |
| giscus_repo_id = "R_kgDOTfVGLA" |
| giscus_category = "User Comments" |
| giscus_category_id = "DIC_kwDOTfVGLM4DBrKC" |
| |
| # ===================================================================== |
| # sphinxext-opengraph |
| # ===================================================================== |
| |
| # sphinxext-opengraph emits <meta property="og:*"> + Twitter Card tags |
| # in every page's <head>, so that URLs shared on social medias render |
| # as rich preview cards instead of bare links. |
| ogp_site_url = html_baseurl |
| ogp_site_name = PROJECT_NAME |
| ogp_description_length = 160 # Google SERP snippet width |
| |
| # The logo shown in the preview. sphinxext-opengraph requires a .png |
| # file. |
| _logo = "_static/images/logo-psutil.png" |
| ogp_social_cards = {"image": _logo, "image_mini": _logo} |
| |
| # ===================================================================== |
| # sphinx-sitemap |
| # ===================================================================== |
| |
| # sphinx-sitemap emits <build>/sitemap.xml listing every built page, |
| # for search engine discovery. Reads html_baseurl; {link} scheme avoids |
| # the default {lang}{version} prefix (we don't use either in URLs). |
| sitemap_url_scheme = "{link}" |
| sitemap_show_lastmod = True |
| # dirhtml URLs are directories, so match the dir form (e.g. "search/", |
| # not "search.html") or these leak into the sitemap. |
| sitemap_excludes = [ |
| "search/", |
| "genindex/", |
| "py-modindex/", |
| "404/", |
| "_modules/*", |
| "blog/archive/", |
| "blog/drafts/", |
| "blog/tag/", |
| "blog/tag/*", |
| "blog/category/", |
| "blog/category/*", |
| "blog/author/", |
| "blog/author/*", |
| ] |
| # Suppress sphinx-sitemap warning (turned into error by |
| # --fail-on-warning) occurring on CI. |
| suppress_warnings = ["git.too_shallow"] |
| |
| # ===================================================================== |
| # sphinx-codeautolink |
| # ===================================================================== |
| |
| # Treat all code blocks on the same page as one interpreter session: a |
| # variable defined in block 1 stays known in block 2. Without this, |
| # snippets like `>>> p = psutil.Process()` followed by `>>> p.name()` |
| # in a later block lose the type of `p`. |
| codeautolink_concat_default = True |
| |
| # Seed every block with an implicit `import psutil`, so snippets that |
| # start mid-session (no explicit import line) still have `psutil.X` |
| # references resolvable. |
| codeautolink_global_preface = "import psutil" |
| |
| # Print warnings for names it can't resolve. |
| # codeautolink_warn_on_failed_resolve = True |
| |
| # ===================================================================== |
| # Sphinx setup hook |
| # ===================================================================== |
| |
| |
| def setup(app): |
| # sphinx-codeautolink needs `import psutil` to resolve things like |
| # `p.name()` in code blocks. It imports psutil itself internally, |
| # but silently passes if it can't, so we do it here to crash |
| # explicitly. Kept inside setup() (not at module scope) so pytest |
| # collection of docs/test_docs.py doesn't hit it. |
| import psutil # noqa: F401 |
| |
| # ablog and sphinx-codeautolink synthesize pages (blog/tag/*, |
| # blog/2025, _modules/*) with no .rst behind them. The footer's |
| # "Edit on GitHub" / "Updated" links would point at files that |
| # don't exist. |
| def set_has_rst_source(app, pagename, templatename, context, doctree): |
| path = pathlib.Path(app.env.doc2path(pagename)) |
| context["has_rst_source"] = path.is_file() |
| |
| app.connect("html-page-context", set_has_rst_source) |