The PyData Sphinx Theme#

A clean, Bootstrap-based Sphinx theme by and for the PyData community.

See also

If you are looking for a Sphinx theme that puts all of its sub-pages in the sidebar, the Sphinx Book Theme has a similar look and feel, and Furo is another excellent choice. You can also see the Sphinx Themes Gallery for more ideas.

User Guide#

Information about using, configuration, and customizing this theme.

User Guide#

You can configure the behavior, look, and feel of the theme in many ways. The remaining pages in the user guide cover various ways of doing so.

Danger

This theme is still under active development, and we make no promises about the stability of any specific HTML structure, CSS variables, etc. Make these customizations at your own risk, and pin versions if you’re worried about breaking changes!

There are a number of options for configuring your site’s look and feel. All configuration options are passed with the html_theme_options variable in your conf.py file. This is a dictionary with key: val pairs that you can configure in various ways.

Installation#

Note

Each pydata-sphinx-theme release has a minimum required Sphinx version, which should be automatically handled by your package installer. It is also tested against newer versions of Sphinx that were available prior to that release of the pydata-sphinx-theme package. If you run into issues when trying to use a more recent version of Sphinx, please open an issue here: pydata/pydata-sphinx-theme#issues

The theme is available on PyPI and conda-forge, and can thus be installed with:

$ pip install pydata-sphinx-theme
$ conda install pydata-sphinx-theme --channel conda-forge

Then, in the conf.py of your sphinx docs, you update the html_theme configuration option:

html_theme = "pydata_sphinx_theme"

Note

This theme may not work with the latest major versions of Sphinx, especially if they have only recently been released. Please give us a few months of time to work out any bugs and changes when new releases are made.

Development version#

If you want to track the development version of the theme, you can install it from the git repo:

$ pip install git+https://github.com/pydata/pydata-sphinx-theme.git@main

or in a conda environment yml file, you can add:

- pip:
  - git+https://github.com/pydata/pydata-sphinx-theme.git@main

Theme Structure and Layout#

This section describes some basic ways to control the layout and structure of your documentation. This theme inherits its structure and section terminology from the Sphinx Basic NG theme.

Overview of theme layout#

Below is a brief overview of the major layout of this theme. Take a look at the diagram to understand what the major sections are called. Where you can insert component templates in html_theme_options, we include the variable name in inline code. Click on section titles to learn more about them and some basic layout configurations. For complete reference of the existing option please see the last section of this page.

Logo

navbar_start

Section links

navbar_center

Components

navbar_end

Primary Sidebar

Links between pages in the active section.

sidebars

primary_sidebar_end

Article Header

article_header_start article_header_end

Article Content

Article Footer

article_footer_items prev_next_area

Horizontal spacing#

By default, the theme’s three columns have fixed widths. The primary sidebar will snap to the left, the secondary sidebar will snap to the right, and the article content will be centered in between.

  • If one of the sidebars is not present, then the article content will be centered between the other sidebar and the side of the page.

  • If neither sidebar is present, the article content will be in the middle of the page.

If you’d like the article content to take up more width than its default, use the max-width CSS property with the following selectors:

.bd-main .bd-content .bd-article-container {
  max-width: 100%;  /* default is 60em */
}

The above rule will set the article content max width to the same width as the top navigation bar. To truly use all of the available page width, you also need to set the following CSS rule:

.bd-page-width {
  max-width: 100%;  /* default is 88rem */
}

This will affect both the article content and the top navigation bar.

Note

If you use both of the custom CSS rules above, be sure to keep them as separate rules in your CSS file. If you combine them, the result will be a CSS selector that is less specific than the two default rules in the theme, and your custom CSS will fail to override the theme defaults.

Templates and components#

There are a few major theme sections that you can customize to add/remove built-in components or add your own components. Each section is configured with a list of HTML templates — these are snippets of HTML that are inserted into the section by Sphinx.

You can choose which templates show up in each section, as well as the order in which they appear. This page describes the major areas that you can customize.

Note

When configuring templates in each section, you may omit the .html suffix after each template if you wish.

Header / Navigation Bar#

Located in sections/header.html.

The header is at the top of the page above all other content and contains site-level information.

Header sections#

The header is broken up into three sections. Each section is configured in conf.py with the following configuration:

  • Left section: html_theme_options['navbar_start']

  • Middle menu: html_theme_options['navbar_center']

  • Right section: html_theme_options['navbar_end']

  • Persistent right section: html_theme_options['navbar_persistent']

By default, the following configuration is used:

html_theme_options = {
# ...
"navbar_start": ["navbar-logo"],
"navbar_center": ["navbar-nav"],
"navbar_end": ["navbar-icon-links"],
"navbar_persistent": ["search-button"]
# ...
}

Warning

The Persistent right section is placed next to the navbar_end, but its elements will remain visible in the header even on small screens when all other elements are collapsed. It has been design for the search-button only and we cannot guarantee its compatibility with other components.

Configure the navbar center alignment#

By default, the navigation bar center area will align with the content on your page. This equals the following default configuration:

html_theme_options = {
   # ...
   "navbar_align": "content"
   # ...
}

If instead, you’d like these items to snap to the left (closer to the logo), use this configuration:

html_theme_options = {
   # ...
   "navbar_align": "left"
   # ...
}

If you’d like these items to snap to the right of the page, use this configuration:

html_theme_options = {
   # ...
   "navbar_align": "right"
   # ...
}
Article Header#

Located in sections/header-article.html.

The article header is a narrow bar just above the article’s content. There are two sub-sections that can have component templates added to them:

  • article_header_start is aligned to the beginning (left) of the article header. By default, this section has the breadcrumbs.html component which displays links to parent pages of the current page.

  • article_header_end is aligned to the end (right) of the article header. By default, this section is empty.

Primary sidebar (left)#

Located in sections/sidebar-primary.html.

The primary sidebar is just to the left of a page’s main content. It is primarily used for between-section navigation. By default, it will show links to any siblings/children of the current active top-level section (corresponding to links in your header navigation bar).

Configuring it is a bit different from configuring the other sections because configuring the sidebar is natively supported in Sphinx, via the html_sidebars configuration variable.

For the primary sidebar only, you can configure templates so that they only show up on certain pages. You do so via a configuration like so in conf.py:

html_sidebars = {
    "<page_pattern>": ["list", "of", "templates"]
}

Any pages that match <page_pattern> will have their respective templates inserted. You can also * to do glob-style matching, and may use ** to match all pages.

By default, it has the following configuration:

html_sidebars = {
    "**": ["sidebar-nav-bs", "sidebar-ethical-ads"]
}
  • sidebar-nav-bs.html - a bootstrap-friendly navigation section.

    When there are no pages to show, it will disappear and potentially add extra space for your page’s content.

  • sidebar-ethical-ads.html - a placement for ReadTheDocs’s Ethical Ads (will only show up on ReadTheDocs).

Primary sidebar end sections#

There is a special <div> within the primary sidebar that appears at the bottom of the page, regardless of the content that is above it.

To control the HTML templates that are within this div, use html_theme_options['primary_sidebar_end'] in conf.py.

By default, it has the following templates:

html_theme_options = {
  # ...
  "primary_sidebar_end": ["sidebar-ethical-ads"],
  # ...
}
Remove the primary sidebar from pages#

If you’d like the primary sidebar to be removed from a page, you can use the following configuration in conf.py:

html_sidebars = {
  "pagename": []
}

This works for glob-style patterns as well. For example:

html_sidebars = {
  "folder/*": []
}

If you’d like to remove the primary sidebar from all pages of your documentation, use this pattern:

html_sidebars = {
  "**": []
}
Secondary Sidebar (right)#

Located in sections/sidebar-secondary.html.

The in-page sidebar is just to the right of a page’s article content and is configured in conf.py with html_theme_options['secondary_sidebar_items'].

By default, it has the following templates:

html_theme_options = {
  # ...
  "secondary_sidebar_items": ["page-toc", "edit-this-page", "sourcelink"],
  # ...
}

To learn how to further customize or remove the secondary sidebar, please check Page Table of Contents.

Article Footer#

Located in sections/footer-article.html.

The article footer exists just below your page’s article. By default, It does not contain anything immediately viewable to the reader, but is kept as a placeholder for custom or built-in templates.

html_theme_options = {
  # ...
  "article_footer_items": [],
  # ...
}
Hide the previous and next buttons#

By default, each page of your site will have “previous” and “next” buttons at the bottom displayed in the prev_next_area. You can hide these buttons with the following configuration:

html_theme_options = {
  "show_prev_next": False
}
Built-in components to insert into sections#

Below is a list of built-in templates that you can insert into any section. Note that some of them may have CSS rules that assume a specific section (and will be named accordingly).

Note

When adding/changing/overwritting a component, the “.html” suffix is optional. That’s why all of them are displayed without it in the following list.

  • breadcrumbs: Displays (and links to) the parent section(s) of the currently viewed page.

  • copyright: Displays the copyright information (which is defined in conf.py).

  • edit-this-page: Displays a link to the edit interface of the page source in the specified Version Control System.

  • icon-links: Displays icon-links as list items.

  • indices: Displays links to the Sphinx-generated indices (genindex, modindex, py-modindex).

  • last-updated: Displays the date and time that the documentation was last built.

  • navbar-icon-links: Displays icon-links in the header navbar.

  • navbar-logo: Displays the logo of your documentation site, in the header navbar.

  • navbar-nav: Displays links to the top-level TOCtree elements, in the header navbar.

  • page-toc: Displays the current page’s Table of Contents.

  • prev-next: Displays links to the previous and next page in the TOCtree order.

  • search-button-field: Displays a search field image that opens a search overlay when clicked.

  • search-button: Displays a magnifying glass icon that opens a search overlay when clicked.

  • search-field: Displays an interactive search field directly on the page.

  • searchbox: An empty container that holds the “Hide Search Matches” button when it’s needed.

  • sidebar-ethical-ads: For sites hosted on ReadTheDocs, displays “ethical ads”.

  • sidebar-nav-bs: Displays the TOC-subtree for pages nested under the currently active top-level TOCtree element.

  • sourcelink: Displays a link to the .rst source of the current page.

  • sphinx-version: Display the version of Sphinx used to build your documentation.

  • theme-switcher: Displays an icon to switch between light mode, dark mode, and auto (use browser’s setting).

  • theme-version: Displays the version of pydata-sphinx-theme used to build the documentation.

  • version-switcher: Displays a dropdown box for switching among different versions of your documentation.

Add your own HTML templates to theme sections#

If you’d like to add your own custom template to any of these sections, you could do so with the following steps:

  1. Create an HTML file in a folder called _templates. For example, if you wanted to display the version of your documentation using a Jinja template, you could create a file: _templates/version.html and put the following in it:

    <!-- This will display the version of the docs -->
    {{ version }}
    
  2. Now add the file to your menu items for one of the sections above. For example:

    html_theme_options = {
    # ...
    "navbar_start": ["navbar-logo", "version"],
    # ...
    }
    
Build date#

By default this theme does not display the build date even when Sphinx’s html_last_updated_fmt variable is set. If you want the build date displayed, the theme includes a last-updated template that you can add to one of the page regions in your conf.py. For example:

conf.py#
html_theme_options = {
    "content_footer_items": ["last-updated"],
    # other settings...
}

If you do specify html_last_updated_fmt but don’t include the last-updated template, the theme will still write the build date into a meta tag in the HTML header, which can be inspected by viewing the page source or extracted with an HTML parser. The tag will look like:

<meta name="docbuild:last-update" content="Aug 15, 2023">

The tag’s content attribute will follow the format specified in the html_last_updated_fmt configuration variable.

References#

Please find here the full list of keys you can use in the html_theme_options in conf.py:

[theme]
inherit = basic
# Note that we don't link the CSS file via Sphinx
# instead we manually link it in `webpack-macros.html`
stylesheet = styles/pydata-sphinx-theme.css
pygments_style = tango
sidebars = sidebar-nav-bs.html

[options]
# General configuration
sidebarwidth = 270
sidebar_includehidden = True
use_edit_page_button = False
external_links =
bitbucket_url =
github_url =
gitlab_url =
twitter_url =
icon_links_label = Icon Links
icon_links =
analytics =
show_prev_next = True
search_bar_text = Search the docs ...
navigation_with_keys = False
collapse_navigation = False
navigation_depth = 4
show_nav_level = 1
show_toc_level = 1
navbar_align = content
header_links_before_dropdown = 5
header_dropdown_text = More
switcher =
check_switcher = True
pygment_light_style = a11y-high-contrast-light
pygment_dark_style = a11y-high-contrast-dark
logo =
surface_warnings = True
back_to_top_button = True

# Template placement in theme layouts
navbar_start = navbar-logo
navbar_center = navbar-nav
navbar_end = theme-switcher, navbar-icon-links
navbar_persistent = search-button-field
article_header_start = breadcrumbs
article_header_end =
article_footer_items =
content_footer_items =
primary_sidebar_end = sidebar-ethical-ads
footer_start = copyright, sphinx-version
footer_center =
footer_end = theme-version
secondary_sidebar_items = page-toc, edit-this-page, sourcelink
show_version_warning_banner = False
announcement =

Page Table of Contents#

Show more levels of the in-page TOC by default#

Normally only the 2nd-level headers of a page are shown in the right table of contents and deeper levels are only shown when they are part of an active section (when it is scrolled on screen).

You can show deeper levels by default by using the following configuration, indicating how many levels should be displayed:

html_theme_options = {
  "show_toc_level": 2
}

All headings up to and including the level specified will now be shown regardless of what is displayed on the page.

Remove the Table of Contents#

To remove the Table of Contents, add :html_theme.sidebar_secondary.remove: to the file-wide metadata at the top of a page. This will remove the Table of Contents from that page only.

Per-page secondary-sidebar content#

html_theme_options['secondary_sidebar_items'] accepts either a list of secondary sidebar templates to render on every page:

html_theme_options = {
  "secondary_sidebar_items": ["page-toc", "sourcelink"]
}

or a dict which maps page names to list of secondary sidebar templates:

html_theme_options = {
  "secondary_sidebar_items": {
    "**": ["page-toc", "sourcelink"],
    "index": ["page-toc"],
  }
}

If a dict is specified, the keys can contain glob-style patterns; page names which match the pattern will contain the sidebar templates specified. This closely follows the behavior of the html_sidebars option that is part of Sphinx itself, except that it operates on the secondary sidebar instead of the primary sidebar. For more information, see the Sphinx documentation.

Source Buttons#

Source buttons are links to the source of your page’s content (either on your site, or on hosting sites like GitHub).

Add an edit button#

You can add a button to each page that will allow users to edit the page text directly and submit a pull request to update the documentation. To include this button in the secondary sidebar of each page, add the following configuration to your conf.py file in ‘html_theme_options’:

html_theme_options = {
    "use_edit_page_button": True,
}

A number of providers are available for building Edit this Page links, including GitHub, GitLab, and Bitbucket. For each, the default public instance URL can be replaced with a self-hosted instance.

GitHub#
html_context = {
    # "github_url": "https://github.com", # or your GitHub Enterprise site
    "github_user": "<your-github-org>",
    "github_repo": "<your-github-repo>",
    "github_version": "<your-branch>",
    "doc_path": "<path-from-root-to-your-docs>",
}
GitLab#
html_context = {
    # "gitlab_url": "https://gitlab.com", # or your self-hosted GitLab
    "gitlab_user": "<your-gitlab-org>",
    "gitlab_repo": "<your-gitlab-repo>",
    "gitlab_version": "<your-branch>",
    "doc_path": "<path-from-root-to-your-docs>",
}
Bitbucket#
html_context = {
    # "bitbucket_url": "https://bitbucket.org", # or your self-hosted Bitbucket
    "bitbucket_user": "<your-bitbucket-org>",
    "bitbucket_repo": "<your-bitbucket-repo>",
    "bitbucket_version": "<your-branch>",
    "doc_path": "<path-from-root-to-your-docs>",
}
Custom Edit URL#

For a fully-customized Edit this Page URL, provide edit_page_url_template, a jinja2 template string which must contain {{ file_name }}, and may reference any other context values.

html_context = {
    "edit_page_url_template": "{{ my_vcs_site }}{{ file_name }}{{ some_other_arg }}",
    "my_vcs_site": "https://example.com",
    "some_other_arg": "?some-other-arg"
}

With the predefined providers, the link text reads “Edit on GitHub/GitLab/Bitbucket”. By default, a simple “Edit” is used if you use a custom URL. However, you can set a provider name like this:

html_context = {
    "edit_page_url_template": "...",
    "edit_page_provider_name": "Provider",
}

This will turn the link into “Edit on Provider”.

Sphinx indices#

Sphinx generates indices named genindex, modindex and py-modindex when building a documentation. More information about them can be found in the Sphinx documentation for indices.

Announcement banners#

You can add an announcement banner that draws extra attention from your reader. It will be displayed at the top of the screen but will disappear once they start scrolling.

To add an announcement banner, use the html_theme_options["announcement"] configuration. There are two ways to use this.

Provide local HTML in your theme#

By default, the value of your html_theme_options["announcement"] will be inserted directly into your announcement banner as raw HTML.

For example, the following configuration adds a simple announcement.

conf.py#
html_theme_options = {
   ...
   "announcement": "Here's a <a href='https://pydata.org'>PyData Announcement!</a>",
}
Insert remote HTML with JavaScript#

You can specify an arbitrary URL that will be used as the HTML source for your announcement. When the page is loaded, JavaScript will attempt to fetch this HTML and insert it as-is into the announcement banner. This allows you to define a single HTML announcement that you can pull into multiple documentation sites or versions.

If the value of html_theme_options["announcement"] begins with http it will be treated as a URL to remote HTML.

For example, the following configuration tells the theme to load the custom-template.html example from this documentation’s GitHub repository:

conf.py#
html_theme_options = {
   ...
   "announcement": "https://github.com/pydata/pydata-sphinx-theme/raw/main/docs/_templates/custom-template.html",
}
Update or remove announcement banner#

To update or remove the announcement banner, you can change the value of html_theme_options["announcement"] in your conf.py or you can edit the contents of the custom-template.html file directly. For example, if you have a temporary announcement that you want to remove without rebuilding your documentation pages, you can use an empty custom-template.html file and the banner will be hidden.

Version warning banners#

In addition to the general-purpose announcement banner, the theme includes a built-in banner to warn users when they are viewing versions of your docs other than the latest stable version. To use this feature, add the following to your conf.py:

conf.py#
html_theme_options = {
    ...
    "show_version_warning_banner": True,
}

Important

This functionality relies on the version switcher to determine the version number of the latest stable release. It will only work if your version switcher .json has exactly one entry with property "preferred": true and your entries have version properties that are parsable by the compare-versions node module, for example:

{
    "name": "stable",
    "version": "9.9.9",
    "url": "https://anything",
    "preferred": true
}

If you want similar functionality for older versions of your docs (i.e. those built before the show_version_warning_banner configuration option was available), you can manually add a banner by prepending the following HTML to all pages (be sure to replace URL_OF_STABLE_VERSION_OF_PROJECT with a valid URL, and adjust styling as desired):

<div style="background-color: rgb(248, 215, 218); color: rgb(114, 28, 36); text-align: center;">
  <div>
    <div>This is documentation for <strong>an old version</strong>.
      <a href="{{ URL_OF_STABLE_VERSION_OF_PROJECT }}" style="background-color: rgb(220, 53, 69); color: rgb(255, 255, 255); margin: 1rem; padding: 0.375rem 0.75rem; border-radius: 4px; display: inline-block; text-align: center;">Switch to stable version</a>
    </div>
  </div>
</div>

Version switcher dropdowns#

You can add a button to your site that allows users to switch between versions of your documentation. The links in the version switcher will differ depending on which page of the docs is being viewed. For example, on the page https://mysite.org/en/v2.0/changelog.html, the switcher links will go to changelog.html in the other versions of your docs. When clicked, the switcher will check for the existence of that page, and if it doesn’t exist, will redirect to the homepage instead (in the requested version of the docs).

The switcher requires the following configuration steps:

  1. Add a JSON file containing a list of the documentation versions that the switcher should show on each page.

  2. Add a configuration dictionary called switcher to the html_theme_options dict in conf.py. switcher should have 2 keys:

    • json_url: the persistent location of the JSON file described above.

    • version_match: a string stating the version of the documentation that is currently being browsed.

  3. Specify where to place the switcher in your page layout. For example, add the "version-switcher" template to one of the layout lists in html_theme_options (e.g., navbar_end, footer_start, etc.).

Below is a more in-depth description of each of these configuration steps.

Add a JSON file to define your switcher’s versions#

First, write a JSON file stating which versions of your docs will be listed in the switcher’s dropdown menu. That file should contain a list of entries that each can have the following fields:

  • version: a version string. This is checked against switcher['version_match'] to provide styling to the switcher.

  • url: the URL for this version.

  • name: an optional name to display in the switcher dropdown instead of the version string (e.g., “latest”, “stable”, “dev”, etc.).

  • preferred: an optional field that should occur on at most one entry in the JSON file. It specifies which version is considered “latest stable”, and is used to customize the message used on Version warning banners (if they are enabled).

Here is an example JSON file:

[
    {
        "name": "v2.1 (stable)",
        "version": "2.1",
        "url": "https://mysite.org/en/2.1/"
    },
    {
        "version": "2.1rc1",
        "url": "https://mysite.org/en/2.1rc1/"
    },
    {
        "version": "2.0",
        "url": "https://mysite.org/en/2.0/"
    },
    {
        "version": "1.0",
        "url": "https://mysite.org/en/1.0/"
    }
]

See the discussion of switcher['json_url'] (below) for options of where to save the JSON file.

Configure switcher['json_url']#

The JSON file needs to be at a stable, persistent, fully-resolved URL (i.e., not specified as a path relative to the sphinx root of the current doc build). Each version of your documentation should point to the same URL, so that as new versions are added to the JSON file all the older versions of the docs will gain switcher dropdown entries linking to the new versions. This could be done in a few different ways:

  • The location could be one that is always associated with the most recent documentation build (i.e., if your docs server aliases “latest” to the most recent version, it could point to a location in the build tree of version “latest”). For example:

    html_theme_options = {
        ...,
        "switcher": {
            "json_url": "https://mysite.org/en/latest/_static/switcher.json",
        }
    }
    

    In this case, the JSON is versioned alongside the rest of the docs pages but only the most recent version is ever loaded (even by older versions of the docs).

  • The JSON could be stored outside the doc build trees. This probably means it would be outside the software repo, and would require you to add new version entries to the JSON file manually as part of your release process. Example:

    html_theme_options = {
        ...,
        "switcher": {
            "json_url": "https://mysite.org/switcher.json",
        }
    }
    
  • In theory the JSON could be saved in a folder that is listed under your site’s html_static_path configuration, but this is not recommended. If you want to do it this way, see the Sphinx static path documentation for more information but do so knowing that we do not support this use case.

By default, the theme is testing the .json file provided and outputs warnings in the Sphinx build. If this test breaks the pipeline of your docs, the test can be disabled by configuring the check_switcher parameter in conf.py:

html_theme_options = {
    # ...
    "check_switcher": False
}
Configure switcher['version_match']#

This configuration value tells the switcher what docs version is currently being viewed, and is used to style the switcher (i.e., to highlight the current docs version in the switcher’s dropdown menu, and to change the text displayed on the switcher button).

Typically, you can re-use one of the sphinx variables version or release as the value of switcher['version_match']; which one you use depends on how granular your docs versioning is. See the Sphinx “project info” documentation for more information). Example:

version = my_package_name.__version__.replace("dev0", "")  # may differ
html_theme_options = {
    ...,
    "switcher": {
        "version_match": version,
    }
}
Specify where to display the switcher#

Finally, tell the theme where on your site’s pages you want the switcher to appear. There are many choices here: you can add "version-switcher" to one of the locations in html_theme_options (e.g., navbar_end, footer_start, etc). For example:

html_theme_options = {
   ...,
   "navbar_start": ["navbar-logo", "version-switcher"]
}

Alternatively, you could override one of the other templates to include the version switcher in a sidebar. For example, you could define _templates/sidebar-nav-bs.html as:

{%- include 'version-switcher.html' -%}
{{ super() }}

to insert a version switcher at the top of the primary sidebar, while still keeping the default navigation below it. See Theme Structure and Layout for more information.

Style the switcher buttons#

You may apply styles via CSS to any of the switcher buttons to control their look and feel. Each button has two HTML dataset entries that you can use to apply CSS rules to subsets of buttons. These entries are:

data-version
data-version-name

For example, the link for an entry with version="0.2", and name="My version" would have metadata like so:

<a data-version-name="My version" data-version="0.2" class="<classes...>">

You can create CSS rules that select this metadata like so:

// Style all links with a specific subset of versions
.version-switcher__container a[data-version="0.2"],
.version-switcher__container a[data-version="0.3"] {
   background-color: red;
}
// Style all links with `stable` in the version name
.version-switcher__container a[data-version-name*="stable"] {
   background-color: green;
}

In addition, the parent button of the dropdown list contains similar metadata about the current version. This could be used to style the entire dropdown a certain color based on the active version.

For example, if you wanted to style the dropdown button to use the theme’s secondary color (PyData orange by default) if it was a dev version, you could use the following CSS selector:

// If the active version has the name "dev", style it orange
.version-switcher__button[data-active-version-name*="dev"] {
   background-color: var(--pst-color-secondary);
}

See also

See the MDN documentation on dataset properties for more information on using and styling these properties.

Search bar / search button#

By default, the search input field is hidden, and there is a search button (a magnifying glass icon ) in the top navbar. The search input field will be displayed when a user either:

  • Clicks the search button in the header.

  • Presses the keyboard shortcut Ctrl + K (Linux, Windows) or + K (macOS).

You can also configure some aspects of the search button and search field, described below.

Configure the search field position#

The position of the search button is controlled by search-button and by default is included in html_theme_options["navbar_persistent"]; you may move it elsewhere as befits your site’s layout, or remove it. You can also add an always-visible search field to some/all pages in your site by adding search-field.html to one of the configuration variables (e.g., html_sidebars, html_theme_options["footer_start"], etc.).

For example, if you’d like the search field to be in your sidebar, add it to the sidebar templates like so:

html_sidebars = {
    "**": ["search-field.html", "sidebar-nav-bs.html", "sidebar-ethical-ads.html"]
}

If instead, you’d like to put the search field in the top navbar, use the following configuration:

html_theme_options = {
    "navbar_end": ["navbar-icon-links.html", "search-field.html"]
}

Warning

If a page includes both the search button and an always-visible search field, the keyboard shortcuts will focus on the always-visible field and the hidden search field overlay will not display. This may not be what you want: on small screens (i.e. mobile devices) the sidebars may be hidden in a drawer, and if the persistent search field is there, it may receive focus without actually being made visible. It is strongly recommended that you use either the search button and the hidden/overlaid field that comes with it, or use a persistent search field in a place that makes sense for your layout.

Configure the search bar text#

To modify the text that is in the search bar before people click on it, add the following configuration to your conf.py file:

html_theme_options = {
    "search_bar_text": "Your text here..."
}

Keyboard shortcuts#

Internationalization#

This theme contains translatable strings. There are two kinds of strings in this theme, with different steps to translate each.

Built-in strings are hard-coded in the theme’s templates. They will automatically be translated if the language is supported. To add another language, see Add translations to translateable text.

Configurable strings are user-defined with the html_theme_options variable in your conf.py file (see other sections in the user guide for examples). To translate these strings, see the section below.

Translating configurable strings#

These instructions are for translating configurable strings (those that are customizable in html_theme_options).

These instructions assume that you store your translations in a locale directory under your documentation directory, and that you want to use theme as the name of the message catalog for these strings.

  1. In your conf.py file:

    import os.path
    from sphinx.locale import get_translation
    
    catalog = "theme"
    _ = get_translation(catalog)
    
    html_theme_options = {
        "search_bar_text": _("Search the docs..."),
    
        # You only need to translate the following if you use these features.
        "icon_links_label": _("Quick Links"),
        "icon_links": [
            {
                "name": _("GitHub"),
                "url": "https://github.com/<your-org>/<your-repo>",
                "icon": "fab fa-github-square",
            },
        ],
        "external_links": [
            {
                "name": _("link-one-name"),
                "url": "https://<link-one>",
            },
        ],
    }
    
    def setup(app):
       locale_dir = os.path.join(os.path.abspath(os.path.dirname(__file__), "locale")
    
       app.add_message_catalog(catalog, locale_dir)
    
  2. Extract the strings to translate:

    pybabel extract . -o locale/theme.pot
    
  3. Create a message catalog (changing the --locale option as desired):

    pybabel init --input-file=locale/theme.pot --domain=theme --output-dir=locale --locale=fr
    
  4. Translate the message catalog by editing the file.

  5. Compile the message catalog:

    pybabel compile --directory=locale --domain=theme
    

Theme-specific elements#

There are a few elements that are unique or particularly important to this theme. Some of these are triggered with configuration or Markdown syntax that is unique to the theme, and we cover them below.

Mathematics#

Most Sphinx sites support math, but it is particularly important for scientific computing, so we illustrate support here as well.

Here is an inline equation: \(X_{0:5} = (X_0, X_1, X_2, X_3, X_4)\) and \(another\) and \(x^2 x^3 x^4\) another. And here’s one to test vertical height \(\frac{\partial^2 f}{\partial \phi^2}\). Here is a block-level equation:

(1)#\[\nabla^2 f = \frac{1}{r^2} \frac{\partial}{\partial r} \left( r^2 \frac{\partial f}{\partial r} \right) + \frac{1}{r^2 \sin \theta} \frac{\partial f}{\partial \theta} \left( \sin \theta \, \frac{\partial f}{\partial \theta} \right) + \frac{1}{r^2 \sin^2\theta} \frac{\partial^2 f}{\partial \phi^2}\]

And here is a really long equation with a label!

(2)#\[\nabla^2 f = \frac{1}{r^2} \frac{\partial}{\partial r} \left( r^2 \frac{\partial f}{\partial r} \right) + \frac{1}{r^2 \sin \theta} \frac{\partial f}{\partial \theta} \left( \sin \theta \, \frac{\partial f}{\partial \theta} \right) + \frac{1}{r^2 \sin^2\theta} \frac{\partial^2 f}{\partial \phi^2} \nabla^2 f = \frac{1}{r^2} \frac{\partial}{\partial r} \left( r^2 \frac{\partial f}{\partial r} \right) + \frac{1}{r^2 \sin \theta} \frac{\partial f}{\partial \theta} \left( \sin \theta \, \frac{\partial f}{\partial \theta} \right) + \frac{1}{r^2 \sin^2\theta} \frac{\partial^2 f}{\partial \phi^2}\]

You can add a link to equations like the one above (1) and (2).

Code blocks#

Code block styling is inspired by GitHub’s code block style and also has support for Code Block captions/titles. See the Sphinx documentation on code blocks for more information.

print("A regular code block")
print("A regular code block")
print("A regular code block")

You can also provide captions with code blocks, which will be displayed right above the code. For example, the following code:

.. code-block:: python
    :caption: python.py

    print("A code block with a caption.")
```{code-block} python
:caption: python.py

print("A code block with a caption.")
```

results in:

print("A code block with a caption.")

You can also display line numbers. For example, the following code:

..  code-block:: python
    :caption: python.py
    :linenos:

    print("A code block with a caption and line numbers.")
    print("A code block with a caption and line numbers.")
    print("A code block with a caption and line numbers.")
```{code-block} python
:caption: python.py
:linenos:

print("A code block with a caption and line numbers.")
print("A code block with a caption and line numbers.")
print("A code block with a caption and line numbers.")
```

results in:

1print("A code block with a caption and line numbers.")
2print("A code block with a caption and line numbers.")
3print("A code block with a caption and line numbers.")
Inline code#

When used directly, the code role just displays the text without syntax highlighting, as a literal. As mentioned in the Sphinx documentation you can also enable syntax highlighting by defining a custom role. It will then use the same highlighter as in the code-block directive.

.. role:: python(code)
   :language: python

In Python you can :python:`import sphinx`.
```{role} python(code)
:language: python
```

In Python you can {python}`import sphinx`.

In Python you can import sphinx.

Code execution#

This theme has support for Jupyter execution libraries so that you can programmatically update your documentation with each build. For examples, see PyData Library Styles.

Admonition sidebars#

This theme supports a shorthand way of making admonitions behave like sidebars. This can be a helpful way of highlighting content without interrupting the vertical flow as much.

For example, on the right are an “admonition sidebar” and a traditional Sphinx sidebar.

To make an admonition behave like a sidebar, add the sidebar class to its list of classes. The admonition sidebar in this section was created with the following Markdown:

.. admonition:: A sidebar admonition!
    :class: sidebar note

    Some sidebar content.
```{admonition} A sidebar admonition!
:class: sidebar note
Some sidebar content.
```
Footnotes#

Here’s a numeric footnote[1], another one (preceded by a space) [2], a named footnote[3], and a symbolic one[4]. All will end up as numbers in the rendered HTML, but in the source they look like [^1], [^2], [^named] and [^*].

Blogs with ABlog#

The ABlog extension allows you to tag pages as blog posts and additionally include them in landing pages for your blog. It also has several sidebar templates to show off collections of your posts.

Minimum version ABlog v0.11.0

Make sure you have ABlog>=0.11.0rc2 in your dependencies.

This theme has styling support for ABlog and demonstrates some of its functionality here.

Example blog#

Click below to go to the blog

Go to the blog

Example post list#

Sphinx Design Components#

On this page, you will find user interface components such as badges, buttons, cards, and tabs.

The components on this page are not provided by PyData Theme. They are provided by Sphinx Design <https://sphinx-design.readthedocs.io/en/pydata-theme/index.html>_ (a Sphinx extension). This means that if you wish to use the components on this page, you must install Sphinx Design separately and add it to your conf.py.

See also

To add the Sphinx Design extension to your Sphinx project, refer to Sphinx Design - Getting Started.

Contributors to both projects have worked to ensure compatible styling so that Sphinx Design components look and feel consistent with the PyData Theme.

This page shows you how the Sphinx Design components would look on your site if you were to use them in combination with the PyData Theme. Sphinx Design also provides a PyData-themed version of the Sphinx Design site; however, their site use an older version of this theme.

Any customizations you make to the theme could affect how these components appear on your site. So what you see on this page might not match exactly what you see on your site even if your site uses this theme.

Cards#
Only heading

Only body.

But with multiple text paragraphs.

Heading and body

Content of the third card.

Sample badge

A card with a dropdown menu
Click to expand dropdown

Hidden content

A clickable card

Don’t forget to add the alternative text with link-alt!

Clickable cards - Sphinx Design docs

panel 1 header

panel 1 content more content

panel 2 header

panel 2 content

Tabs#
int main(const int argc, const char **argv) {
    return 0;
}
def main():
    return
class Main {
    public static void main(String[] args) {
    }
}
function main()
end
PROGRAM main
END PROGRAM main
Copybuttons#

sphinx-copybutton adds a copy button to each of your code cells. You can see it in action by hovering over the code cell below:

print("A copybutton in the top-right!")
Toggle buttons#

sphinx-togglebutton allows you to convert admonitions into toggle-able elements.

A standalone toggle button!

Extending the theme#

There are many extensions available for Sphinx that can enhance your site or provide powerful customization abilities. Here we describe a few customizations that are popular with pydata-sphinx-theme users.

Collapsible admonitions#

The sphinx-togglebutton extension provides optional show/hide behavior for admonitions. Follow their installation instructions, then add it to the extentions list in your conf.py:

extensions = [
    # [...]
    "sphinx_togglebutton"
]

Then add the dropdown class to any admonition directive (shown here on a note admonition):

.. note::
    :class: dropdown

    Lorem ipsum dolor sit amet, consectetur adipiscing elit.
```{note}
:class: dropdown

Lorem ipsum dolor sit amet, consectetur adipiscing elit.
```
Custom admonition styles#

A limited set of admonitions are built-in to docutils (the rSTHTML engine that underlies Sphinx). However, it is possible to create custom admonitions with their own default colors, icons, and titles.

Customizing the title#

Although most admonitions have a default title like note or warning, a generic admonition directive is built-in to docutils/Sphinx. In this theme, its color defaults to the same color as note admonitions, and it has a bell icon:

Custom title!

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

The title is specified on the same line as the .. admonition:: directive:

.. admonition:: Custom title!

    Lorem ipsum dolor sit amet, consectetur adipiscing elit.
```{admonition} Custom title!

Lorem ipsum dolor sit amet, consectetur adipiscing elit.
```
Styling with semantic color names#

You can re-style any admonition to match any of the built-in admonition types using any of the theme’s semantic color names as a class (this is most useful for custom-titled admonitions):

Custom title with “warning” style

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Note that it updates both the color and the icon. See Theme variables and CSS for a list of all semantic color names.

.. admonition:: Custom title with "warning" style
    :class: warning

    Lorem ipsum dolor sit amet, consectetur adipiscing elit.
```{admonition} Custom title with "warning" style
:class: warning

Lorem ipsum dolor sit amet, consectetur adipiscing elit.
```

This theme defines classes for the standard docutils admonition types (attention, caution, etc) and additionally supports seealso and todo admonitions (see Admonitions for a demo of all built-in admonition styles).

Customizing the color#

Besides the pre-defined semantic color classes (see previous section) you can also add a bespoke color to any admonition by defining your own CSS class. Example:

Admonition with custom “olive” color

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

To do this, you will need to add a class to your custom.css file, as in the example below. Be sure to use the same color for border-color and color and a different shade for background-color:

.. admonition:: Admonition with custom "olive" color
    :class: admonition-olive

    Lorem ipsum dolor sit amet, consectetur adipiscing elit.
```{admonition} Admonition with custom "olive" color
:class: admonition-olive

Lorem ipsum dolor sit amet, consectetur adipiscing elit.
```

And add the following to your custom.css file:

/* <your static path>/custom.css */

div.admonition.admonition-olive {
  border-color: hsl(60, 100%, 25%);
}
div.admonition.admonition-olive > .admonition-title {
  background-color: hsl(60, 100%, 14%);
  color: white;
}
div.admonition.admonition-olive > .admonition-title:after {
  color: hsl(60, 100%, 25%);
}
Using a custom icon#

Customizing the icon uses a similar process to customizing the color: create a new CSS class in your custom.css file. The theme supports fontawesome v6 icons (“free” and “brands” sets). To use an icon, copy its unicode value into your custom class as shown in the CSS tab below:

Check out my custom icon

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

.. admonition:: Check out my custom icon
    :class: admonition-icon

    Lorem ipsum dolor sit amet, consectetur adipiscing elit.
```{admonition} Check out my custom icon
:class: admonition-icon

Lorem ipsum dolor sit amet, consectetur adipiscing elit.
```

And add the following css to your custom.css file:

/* <your static path>/custom.css */

div.admonition.admonition-icon > .admonition-title:after {
  content: "\f24e"; /* the fa-scale icon */
}
Combining all three customizations#

Here we demonstrate an admonition with a custom icon, color, and title (and also make it collapsible). Note that the multiple admonition class names are space-separated:

.. admonition:: YouTube
    :class: dropdown admonition-youtube

    ..  youtube:: dQw4w9WgXcQ
````{admonition} YouTube
:class: dropdown admonition-youtube

```{youtube} dQw4w9WgXcQ
```

````

And add the following css to your custom.css file:

/* <your static path>/custom.css */

div.admonition.admonition-youtube {
  border-color: hsl(0, 100%, 50%); /* YouTube red */
}
div.admonition.admonition-youtube > .admonition-title {
  background-color: hsl(0, 99%, 18%);
  color: white;
}
div.admonition.admonition-youtube > .admonition-title:after {
  color: hsl(0, 100%, 50%);
  content: "\f26c"; /* fa-solid fa-tv */
}

Theme variables and CSS#

This section covers a few ways that you can control the look and feel of your theme via your own CSS and theme variables.

Custom CSS Stylesheets#

You can customize the theme’s CSS by creating a custom stylesheet. This stylesheet will be used by Sphinx while building your site. Any rules in this style sheet will override the default theme rules.

See also

For a more in-depth guide in linking static CSS and JS assets in your site, see Add custom CSS and JS assets.

To add a custom stylesheet, follow these steps:

  1. Create a CSS stylesheet in _static/css/custom.css, and update the CSS rules as desired.

  2. Attach the stylesheet to your Sphinx build. Add the following to conf.py:

    html_static_path = ['_static']
    
    html_css_files = [
        'css/custom.css',
    ]
    

When you build your documentation, this stylesheet should now be activated.

CSS theme variables#

This theme defines several CSS variables that can be used to quickly control behavior and display across your documentation.

These are based on top of the basic Bootstrap CSS variables extended with some theme-specific variables.

Base variables#

Follow these steps to update the base variables:

  1. Add a custom CSS stylesheet. This is where we’ll configure the variables.

  2. Underneath a html section, add the variables you wish to update. For example, to change the base font size you would add the following to your custom.css file :

    html {
        --pst-font-size-base: 17px;
    }
    

Important

Note that the theme is defined with CSS variables and not SASS variables.

Refer to the managing themes section in this documentation if you desire a different behavior between the light and dark theme.

For a complete list of the theme variables that you may override, see the theme variables defaults CSS file:

html {
  /*****************************************************************************
  * Overall Layout Variables
  */

  // Header height will impact the top offset for many sections
  // Article header is 66% of Header
  --pst-header-height: 4rem;
  --pst-header-article-height: calc(var(--pst-header-height) * 2 / 3);
  --pst-sidebar-secondary: 17rem;
}

/*******************************************************************************
* Breakpoints that trigger UI changes
*
* Note that media-breakpoint-down begins at the next highest level!
* So we should choose a media-breakpoint-down one *lower* than when we want to start
* example: media-breakpoint-up(md) and media-breakpoint-down(sm) trigger at the same time
* ref: https://github.com/twbs/bootstrap/issues/31214
*/
$breakpoint-sidebar-primary: lg; // When we collapse the primary sidebar
$breakpoint-sidebar-secondary: xl; // When we collapse the secondary sidebar
$breakpoint-page-width: 88rem; // taken from sphinx-basic-ng, which we are ultimately going to inherit

/*******************************************************************************
* Define the animation behaviour
*/
$animation-time: 200ms;

/*******************************************************************************
* UI shaping and padding
*/
$admonition-border-radius: 0.25rem;

// In this theme, some focus rings have rounded corners while others do not.
// This variable sets the border radius for the rounded focus rings.
$focus-ring-radius: 0.125rem; // 2px at 100% zoom and 16px base font.
html {
  /*****************************************************************************
  * Font features used in this theme
  */

  // base font size - applied at body/html level
  --pst-font-size-base: 1rem;

  // heading font sizes based on bootstrap sizing
  --pst-font-size-h1: 2.5rem;
  --pst-font-size-h2: 2rem;
  --pst-font-size-h3: 1.75rem;
  --pst-font-size-h4: 1.5rem;
  --pst-font-size-h5: 1.25rem;
  --pst-font-size-h6: 1.1rem;

  // smaller than heading font sizes
  --pst-font-size-milli: 0.9rem;

  // Sidebar styles
  --pst-sidebar-font-size: 0.9rem;
  --pst-sidebar-font-size-mobile: 1.1rem;
  --pst-sidebar-header-font-size: 1.2rem;
  --pst-sidebar-header-font-weight: 600;

  // Admonition styles
  --pst-admonition-font-weight-heading: 600;

  // Font weights
  --pst-font-weight-caption: 300;
  --pst-font-weight-heading: 400;

  // Font family
  // These are adapted from https://systemfontstack.com/ */
  --pst-font-family-base-system: -apple-system, BlinkMacSystemFont, Segoe UI,
    "Helvetica Neue", Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji,
    Segoe UI Symbol;
  --pst-font-family-monospace-system: "SFMono-Regular", Menlo, Consolas, Monaco,
    Liberation Mono, Lucida Console, monospace;

  --pst-font-family-base: var(--pst-font-family-base-system);
  --pst-font-family-heading: var(--pst-font-family-base-system);
  --pst-font-family-monospace: var(--pst-font-family-monospace-system);
}
html {
  /*****************************************************************************
  * Icon
  */

  // Font size across all icons
  --pst-font-size-icon: 1.5rem;

  // Font Awesome default icons
  --pst-icon-check-circle: "\f058"; // fa-solid fa-circle-check
  --pst-icon-info-circle: "\f05a"; // fa-solid fa-circle-info
  --pst-icon-exclamation-triangle: "\f071"; // fa-solid fa-triangle-exclamation
  --pst-icon-exclamation-circle: "\f06a"; // fa-solid fa-circle-exclamation
  --pst-icon-times-circle: "\f057"; // fa-solid fa-circle-xmark
  --pst-icon-lightbulb: "\f0eb"; // fa-solid fa-lightbulb
  --pst-icon-download: "\f019"; // fa-solid fa-download
  --pst-icon-angle-left: "\f104"; // fa-solid fa-angle-left
  --pst-icon-angle-right: "\f105"; // fa-solid fa-angle-right
  --pst-icon-external-link: "\f35d"; // fa-solid fa-up-right-from-square
  --pst-icon-search-minus: "\f010"; // fa-solid fa-magnifying-glass-minus
  --pst-icon-github: "\f09b"; // fa-brands fa-github
  --pst-icon-gitlab: "\f296"; // fa-brands fa-gitlab
  --pst-icon-share: "\f064"; // fa-solid fa-share
  --pst-icon-bell: "\f0f3"; // fa-solid fa-bell
  --pst-icon-pencil: "\f303"; // fa-solid fa-pencil

  // Bootstrap icons
  --pst-breadcrumb-divider: "\f105";
}
html {
  /*****************************************************************************
  * Admonitions
  **/

  --pst-icon-admonition-default: var(--pst-icon-bell);
  --pst-icon-admonition-note: var(--pst-icon-info-circle);
  --pst-icon-admonition-attention: var(--pst-icon-exclamation-circle);
  --pst-icon-admonition-caution: var(--pst-icon-exclamation-triangle);
  --pst-icon-admonition-warning: var(--pst-icon-exclamation-triangle);
  --pst-icon-admonition-danger: var(--pst-icon-exclamation-triangle);
  --pst-icon-admonition-error: var(--pst-icon-times-circle);
  --pst-icon-admonition-hint: var(--pst-icon-lightbulb);
  --pst-icon-admonition-tip: var(--pst-icon-lightbulb);
  --pst-icon-admonition-important: var(--pst-icon-exclamation-circle);
  --pst-icon-admonition-seealso: var(--pst-icon-share);
  --pst-icon-admonition-todo: var(--pst-icon-pencil);
}
html {
  /*****************************************************************************
  * versionmodified
  **/

  --pst-icon-versionmodified-default: var(--pst-icon-exclamation-circle);
  --pst-icon-versionmodified-added: var(--pst-icon-exclamation-circle);
  --pst-icon-versionmodified-changed: var(--pst-icon-exclamation-circle);
  --pst-icon-versionmodified-deprecated: var(--pst-icon-exclamation-circle);
}
Color variables#

This theme specifies color variables for the primary and secondary colors (--pst-color-primary and --pst-color-secondary, respectively). These are meant to complement one another visually across the theme, if you modify these, choose colors that look good when paired with one another. There are also several other color variables that control the color for admonitions, links, menu items, etc.

Each color variable has two values, one corresponding to the “light” and one for the “dark” theme. These are used throughout many of the theme elements to define text color, background color, etc.

Here is an overview of the colors available in the theme (change theme mode to switch from light to dark versions).

primary secondary accent success info warning danger background on-background surface on-surface target

To modify the colors for these variables for light and dark themes, add a custom CSS stylesheet with a structure like so:

html[data-theme="light"] {
    --pst-color-primary: black;
}

html[data-theme="dark"] {
    --pst-color-primary: white;
}

This theme uses shadows to convey depth in the light theme mode and opacity in the dark one. It defines 4 color variables that help build overlays in your documentation.

  • background: color of the back-most surface of the documentation

  • on-background elements that are set on top of this background (e.g. the header navbar on dark mode).

  • surface elements set on the background with a light-grey color in the light theme mode. This color has been kept in the dark theme (e.g. code-block directives).

  • on-surface elements that are on top of surface elements (e.g. sidebar directives).

The following image should help you understand these overlays:

background

on-background

surface

on-surface

For a complete list of the theme colors that you may override, see the PyData theme CSS colors stylesheet.

Configure pygments theme#

As the Sphinx theme supports multiple modes, the code highlighting colors can be modified for each one of them by modifying the pygment_light_style and pygment_dark_style. You can check available Pygments colors on this pygments demo page.

html_theme_options = {
   ...
   "pygment_light_style": "tango",
   "pygment_dark_style": "monokai"
}

Note that the PyData Sphinx theme uses the accessible pygments styles for its default syntax highlighting themes. The accessible pygments themes are designed to meet WCAG AA or AAA standards for color contrast and some included themes are also suitable for colorblind users or low-light conditions. You can check all the available styles at the accessible pygments demo page.

Danger

The native Sphinx option pygments_style will be overwritten by this theme.

Fonts and FontAwesome#

The theme includes the FontAwesome 6 Free icon font (the .fa-solid, .fa-regular, .fa-brands styles, which are used for icon links and admonitions). This is the only vendored font, and otherwise, the theme by default relies on available system fonts for normal body text and headers.

The default body and header fonts can be changed as follows:

  • Using Custom CSS Stylesheets, you can specify which fonts to use for the body, header, and monospaced text. For example, the following can be added to a custom CSS file:

    html {
        --pst-font-family-base: Verdana, var(--pst-font-family-base-system);
        --pst-font-family-heading: Cambria, Georgia, Times, var(--pst-font-family-base-system);
        --pst-font-family-monospace: Courier, var(--pst-font-family-monospace-system);
    }
    

    The *-system variables are available to use as a fallback to the default fonts.

  • If the font you want to specify in the section above is not generally available by default, you will additionally need to ensure the font is loaded. For example, you could download and vendor the font in the _static directory of your Sphinx site, and then update the base template to load the font resources:

    • Configure the template_path in your conf.py

    • Create a custom layout.html Jinja2 template which overloads the fonts block (example for loading the Lato font that is included in the _static/vendor directory):

      {% extends "pydata_sphinx_theme/layout.html" %}
      
      {% block fonts %}
        <!-- add `style` or `link` tags with your CSS `@font-face` declarations here -->
        <!-- ... and optionally preload the `woff2` for snappier page loads -->
        <link rel="stylesheet" href="{{ pathto('_static/vendor/lato_latin-ext/1.44.1/index.css', 1) }}">
      
      {% endblock %}
      

      Your text may quickly show up as “unstyled” before the fonts are loaded. To reduce this, you may wish to explore options for preloading content, specifically the binary font files. This ensures the files will be loaded before the CSS is parsed, but should be used with care.

Light and dark themes#

You can change the major background/foreground colors of this theme using built-in “dark” and “light” modes. These are controlled by a button in the navigation header, with the following options:

  • A light theme with a bright background and dark text / UI elements

  • A dark theme with a dark background and light text / UI elements

  • auto: the documentation theme will follow the system default that you have set

Configure default theme mode#

By default, visitors to your documentation will use the theme mode auto. This will choose a theme based on the user’s system settings, and default to light if no system setting is found.

If you wish to use a different default theme mode, set the default_mode configuration to one of auto, dark, light. For example:

html_context = {
   # ...
   "default_mode": "light"
}

For more information, see Light and dark themes.

Tip

To completely remove the theme management, configure default_mode to the value you want in your documentation (light or dark) and then remove the theme-switcher from the navbar_end section of the header navbar configuration:

html_theme_options {
    ...
    # Note we have omitted `theme-switcher` below
    "navbar_end": ["navbar-icon-links"]
}
Customize the CSS of light and dark themes#

Danger

Theming is still a beta feature, so the variables related to color theming are likely to change in the future. No backward compatibility is guaranteed when customization is done.

To customize the CSS of page elements in a theme-dependent manner, use the html[data-theme='<THEME>'] CSS selector. For example to define a different background color for both the light and dark themes:

/* anything related to the light theme */
html[data-theme="light"] {

    /* whatever you want to change */
    background-color: white;
}

/* anything related to the dark theme */
html[data-theme="dark"] {

    /* whatever you want to change */
    background-color: black;
}

A complete list of the colors used in this theme can be found in the CSS style section.

Theme-dependent images and content#

It is possible to use different content for light and dark modes so that the content only shows up when a particular theme is active. This is useful if your content depends on the theme’s style, such as a PNG image with a light or dark background.

There are two CSS helper classes to specify items on the page as theme-specific. These are:

  • only-dark: Only display an element when the dark theme is active.

  • only-light Only display an element when the light theme is active.

For example, the following page content defines two images, each of which uses a different one of the classes above. Change the theme and a new image should be displayed.

.. image:: https://source.unsplash.com/200x200/daily?cute+cat
    :class: only-dark

.. image:: https://source.unsplash.com/200x200/daily?cute+dog
    :class: only-light
```{image} https://source.unsplash.com/200x200/daily?cute+cat
:class: only-dark
```

```{image} https://source.unsplash.com/200x200/daily?cute+dog
:class: only-light
```
https://source.unsplash.com/200x200/daily?cute+cat https://source.unsplash.com/200x200/daily?cute+dog
Images and content that work in both themes#

When the dark theme is activated, images that do not support dark mode will automatically have a white background added to ensure the image contents are visible, and their brightness will be reduced by a filter.

If your image is suitable for the dark theme, add the CSS class only-dark as noted above. If your image is suitable for both light and dark themes, add the CSS class dark-light to make your image theme-agnostic.

For example, here’s an image without adding this helper class. Change to the dark theme and a grey background will be present.

.. image:: https://source.unsplash.com/200x200/daily?cute+cat
    :class: p-2
```{image} https://source.unsplash.com/200x200/daily?cute+cat
:class: p-2
```
https://source.unsplash.com/200x200/daily?cute+cat

Here’s the same image with this class added:

.. image:: https://source.unsplash.com/200x200/daily?cute+cat
    :class: dark-light
```{image} https://source.unsplash.com/200x200/daily?cute+cat
:class: dark-light p-2
```
https://source.unsplash.com/200x200/daily?cute+cat
Define custom JavaScript to react to theme changes#

You can define a JavaScript event hook that will run your code any time the theme changes. This is useful if you need to change elements of your page that cannot be defined by CSS rules. For example, to change an image source (e.g., logo) whenever the data-theme changes, a snippet like this can be used:

.. raw:: html

    <script type="text/javascript">
    var observer = new MutationObserver(function(mutations) {
        const dark = document.documentElement.dataset.theme == 'dark';
        document.getElementsByClassName('mainlogo')[0].src = dark ? '_static/my_logo_dark.svg' : "_static/my_logo_light.svg";
    })
    observer.observe(document.documentElement, {attributes: true, attributeFilter: ['data-theme']});
    </script>
    <link rel="preload" href="_static/my_logo_dark.svg" as="image">

.. image:: _static/my_logo_light.svg
    :alt: My Logo
    :class: logo, mainlogo
    :align: center
<script type="text/javascript">
var observer = new MutationObserver(function(mutations) {
    const dark = document.documentElement.dataset.theme == 'dark';
    document.getElementsByClassName('mainlogo')[0].src = dark ? '_static/my_logo_dark.svg' : "_static/my_logo_light.svg";
})
observer.observe(document.documentElement, {attributes: true, attributeFilter: ['data-theme']});
</script>
<link rel="preload" href="_static/my_logo_dark.svg" as="image">

```{image} _static/my_logo_light.svg
:alt: My Logo
:class: logo, mainlogo
:align: center
```

The JavaScript reacts to data-theme changes to alter img, and the link is used to preload the dark image. See the MutationObserver documentation for more information.

Accessibility#

Creating and publishing content that does not exclude disabled users is a complex and iterative task.

While there is no one-size-fits-all solution to maintaining accessible content, the PyData Sphinx Theme and this documentation site use some techniques to avoid common content shortcomings.

Note

Issues and pull requests to identify or fix accessibility issues on this theme or site are heartily welcomed!

What We’ve Done#
Metadata#

Several of our documentation pages contain metadata (i.e., .. meta:: directives in reStructuredText) giving summaries of the page contents. If you notice a page that lacks metadata, please open a pull request to add it!

Colors#
  • Our default code highlighting styles are a11y-high-contrast-light and a11y-high-contrast-dark from Quansight-Labs/accessible-pygments. These styles are designed to meet WCAG 2 AA or AAA contrast requirements. If you don’t like the look of our default code highlighting styles, there are several more to choose from at Quansight-Labs/accessible-pygments.

  • We recently revisited the PyData Sphinx theme color palette to ensure that the colors we use meet WCAG 2 AA or AAA contrast requirements.

  • We also re-defined our primary and secondary colors to be more accessible and distinct from semantic colors used to denote success, warning, info, and danger contexts or information.

  • We simplified the color palette and removed some colors that were problematic in meeting WCAG 2 AA or AAA contrast requirements and for certain types of colorblindness.

  • We have improved how we assign text colors to interactive elements such as buttons and dropdowns to ensure that they meet WCAG 2 AA or AAA contrast requirements.

Keyboard Navigation Support#

For all buttons, dropdowns, tabbed panels, hamburger menus, modals, overlays, links and other interactive elements, we have worked to ensure they:

  • Have a visible focus indicator (WCAG 2.4.7)

  • Can be accessed via keyboard navigation (WCAG 2.1.1)

What You Can Do#
Site configuration#

The following sections include recommendations for settings in the conf.py file that can positively impact the accessibility of content generated by this theme and Sphinx in general.

Natural Language#

If not using a more robust internationalization approach, specifying at least the baseline natural language will help assistive technology identify if the content is in a language the reader understands.

Hint

In your conf.py file, specifying the language your docs are written in will propagate to the top-level HTML tag.

  language = "en"
Add a Site Map#

Site maps, usually served from a file called sitemap.xml are a broadly-employed approach to telling programs like search engines and assistive technologies where different content appears on a website.

If using a service like ReadTheDocs, these files will be created for you automatically, but for some other approaches below, it’s handy to generate a sitemap.xml locally or in CI with a tool like sphinx-sitemap.

Hint

For a simple site (no extra languages or versions), ensure sphinx-sitemap is installed in your documentation environment, and modify your conf.py:

    extensions += ["sphinx_sitemap"]

    html_baseurl = os.environ.get("SPHINX_HTML_BASE_URL", "http://127.0.0.1:8000/")
    sitemap_locales = [None]
    sitemap_url_scheme = "{link}"
Logo best practices#

If you use both light and dark themes, it’s best to provide a logo that works well in both or to provide an alternative for the dark theme. If you have a logo, you can add alt-text to it by adding the following to your conf.py:

  "logo": {
      "text": "PyData Theme",
      "image_dark": "_static/logo-dark.svg",
      "alt_text": "PyData Theme home",
  },

Note the use of “home” in the alt text to indicate that the logo is also a link to the home page.

In the Browser#

Several in-browser tools exist for interactively debugging the accessibility of a single page at a time and can be useful during the content development cycle.

Built-in tools#

Most major browsers, including Firefox and Chrome, have accessibility tools built-in as part of their web developer tools. These tools can help to quickly identify accessibility issues and often include links to standards.

tota11y#

tota11y is an open source “bookmarklet” which modifies the currently-loaded page in place and highlights several accessibility issues.

WAVE#

WAVE is a proprietary (but gratis) browser extension which can highlight multiple issues.

Warning

Note that automated testing and extensions such as the ones mentioned above will at best catch 30-40% of accessibility issues. They are not a replacement for manual testing and having a perfect score on any of these tools does not mean that the site can be used by disabled users but instead signals that it follows some accessibility best practices.

In Continuous Integration#

Several automated tools are available for assessing glaring accessibility issues across some pages at once, usually with many configurable options.

Lighthouse#

Lighthouse provides an automated assessment of basic accessibility issues in addition to search engine automation, page performance, and other best practices.

Hint

Specifically, foo-software/lighthouse-check-action is run on selected pages from the generated documentation site.

Analytics and usage services#

The theme supports several web analytics services via the analytics option. It is configured by passing a dictionary with options. See the sections below for relevant options depending on the analytics provider that you want to use.

html_theme_options = {
    # See below for options for each service
    "analytics": analytics_options,
}

Generally speaking, we recommend using Plausible over Google Analytics because it has a better story around user security and privacy. In addition, it is more open-source and transparent. In fact, you can self-host a Plausible server.

Get a self-hosted Plausible server at scientific-python.org

If your documentation is for a package that is part of the SciPy / PyData ecosystem, they might be able to host a Plausible server for you at https://views.scientific-python.org/<your-package>. To ask about this, contact them on the social media platform of your choice and learn more at scientific-python.org.

Plausible Analytics#

plausible.io can be used to gather simple and privacy-friendly analytics for the site. To configure, you will need to provide two things:

  • A URL pointing to the JavaScript analytics script that is served by your Plausible server

  • A domain that reflects where your documentation lives

Plausible’s JavaScript will be included in all HTML pages to gather metrics. The dashboard with analytics results will be accessible at https://<plausible-url>/<my-domain>.

html_theme_options["analytics"] = {
    # The domain you'd like to use for this analytics instance
    "plausible_analytics_domain": "my-domain",
    # The analytics script that is served by Plausible
    "plausible_analytics_url": "https://.../script.js",
}

See also

See the Plausible Documentation for more information about this script.

Google Analytics#

If the google_analytics_id config option is specified (like G-XXXXXXXXXX), Google Analytics’ JavaScript is included in the HTML pages.

html_theme_options["analytics"] = {
    "google_analytics_id": "G-XXXXXXXXXX",
}

Add custom CSS and JS assets#

If you’d like to modify this theme or sections on the page, you’ll need to add custom CSS or JavaScript to your theme. Since this is a common operation we cover a few ways to do this here.

Sample site structure

In all examples below, assume we have a site structure like this:

mysphinxsite/
├── _static
│   ├── mycss.css
│   └── myjs.js
└── conf.py
First: define your html_static_path#

Any folders that are listed in html_static_path will be treated as containing static assets for your build. All files within these folders will be copied to your build’s _static folder at build time. For example, with an HTML builder, files will be copied to _build/html/_static.

These files are flattened when they are copied, so any folder hierarchies will be lost.

Listing folders with your static assets must be done before any of the methods described below. When you define asset names in the methods described below, they generally assume paths that are relative to this _static output folder.

Define a list of assets in conf.py#

The simplest way to add JS and CSS assets is to use html_css_files and html_js_files in your conf.py file. Each can be a list of paths, relative to your html_static_path. They will be added to the end of the <head> of your site.

For example:

conf.py#
html_static_path = ["_static"]
html_css_files = ["mycss.css"]
html_js_files = ["myjs.js"]

This will cause each to be linked in your <head>.

Add assets to your setup function#

Additionally, you may add assets manually, to do so, use the app object in the Sphinx setup() function. The app object has two relevant methods here:

app.add_css_file allows you to add CSS files directly.

app.add_js_file allows you to add JS files directly.

Both of them expect you to add files relative to the html_static_path.

In addition, app.add_js_file allows you to add raw JavaScript in addition to linking files (see example below). For example:

conf.py#
html_static_path = ["_static"]

def setup(app):
  app.add_css_file("mycss.css")
  app.add_js_file("myjs.js")

  # Add raw JavaScript
  rawjs = """
  let a = "foo";
  console.log(a + " bar")
  """
  app.add_js_file(None, body=rawjs)
Use an event to add it to specific pages#

If you’d like to use logic to only add a script to certain pages or to trigger different behavior depending on the page, use a Sphinx event hook. This involves defining a function that runs when a particular event is emitted in the Sphinx build, and using app.connect() to connect it to your build.

The event you’ll likely want to use is html-page-context. This is triggered just before the HTML for an individual page is created. If you run app.add_js_file or app.add_css_file, it will only be added for that page.

For example:

conf.py#
html_static_path = ["_static"]

def add_my_files(app, pagename, templatename, context, doctree):
  if pagename == "dontaddonthispage":
    return

  app.add_css_file("mycss.css")

def setup(app):
  app.connect("html-page-context", add_my_files)
Add it directly to the page content#

Finally, you can add CSS or JS directly to a page’s content. If you’re using reStructuredText you can use the .. raw:: directive; if you’re using MyST Markdown you can simply include the HTML content in-line with your Markdown-formatted content.

some_page_in_my_site.rst#
My title
========

Some text

.. raw:: html

    <style>
      /* Make h2 bigger */
      h2 {
        font-size: 3rem;
      }
    </style>

A bigger title
--------------

Some other text
some_page_in_my_site.md#
# My title

Some text

<style>
  /* Make h2 bigger */
  h2 {
    font-size: 3rem;
  }
</style>

## A bigger title

Some other text

Build performance and size#

By default this theme includes all of your documentation links in a collapsible sidebar. However, this may slow down your documentation builds considerably if you have a lot of documentation pages. This is most common with documentation for projects with a large API, which use the .. autosummary:: directive to generate API documentation.

To improve the performance of your builds in these cases, first try modifying the navigation depth in the sidebar (see Navigation depth and collapsing sidebars). If that doesn’t work, try the fix in the section below.

Selectively remove pages from your sidebar#

You can prevent pages from showing up in the navigation bar using a Sphinx extension called sphinx-remove-toctrees. This is useful if your documentation generates lots of “stub pages” in a folder, which is common with API documentation.

This lets you add a configuration like so:

remove_from_toctrees = ["folder_one/generated/*"]

and any pages that are inside of folder_one/generated/ will not show up in the sidebar.

Check out the sphinx-remove-toctrees documentation for information about how to install and use this extension.

Theme changes, deprecations, and warnings#

Generally speaking, the best source of information about changes to the theme will be the release changelog. We try to avoid raising warnings within theme code, which means sometimes the theme will change (perhaps significantly) without deprecation warnings or other alerts. Still, we occasionally do warn about things like (upcoming) changes to the theme’s default config values. If you prefer not to receive such warnings, there is a config value to suppress them:

conf.py#
html_theme_options = {
    "surface_warnings": False
}

Read the Docs functionality#

This theme comes with support for Read the Docs, a popular service for hosting documentation in the scientific Python community.

Version switcher#

Projects hosted on Read the Docs can use the Read the Docs supplied version switcher instead of the version switcher that this theme provides. Its presence will be automatically detected by this theme, and placed in the rtd-footer-container node inside the primary sidebar.

Warning

The Read the Docs version switcher will be hidden any time the primary sidebar is hidden (see this section for discussion of when the primary sidebar might get hidden automatically and how to hide it purposely). We intend to make Read the Docs switcher placement more flexible; you can track progress toward that in this issue.

Add ethical advertisements to your sidebar#

If you’re hosting your documentation on ReadTheDocs, you should consider adding an explicit placement for their ethical advertisements. These are non-tracking advertisements from ethical companies, and they help ReadTheDocs sustain themselves and their free service.

Ethical advertisements are added to your sidebar by default. To ensure they are there if you manually update your sidebar, ensure that the sidebar-ethical-ads.html template is added to your list. For example:

html_sidebars = {
    "**": ["search-field.html", "sidebar-nav-bs.html", "sidebar-ethical-ads.html"]
}

Community and contribution guide#

Information about the community behind this theme and how you can contribute.

Contributor Guide#

These pages contain information about the community that leads, supports, and develops this theme, including how you can contribute to the project.

Get started with development#

This section covers the simplest way to get started developing this theme locally so that you can contribute. It uses automation and as few steps as possible to get things done. If you’d like to do more operations manually, see Set up a manual development environment.

Workflow for contributing changes#

We follow a typical GitHub workflow of:

  • create a personal fork of this repo

  • create a branch

  • open a pull request

  • fix findings of various linters and checks

  • work through code review

For each pull request, the documentation is built and deployed to make it easier to review the changes in the PR. To access this, click on the Read the Docs preview in the CI/CD jobs.

The sections below cover the steps to take in more detail.

Clone the repository#

First off you’ll need your copy of the pydata-sphinx-theme codebase. You can clone it for local development like so:

  1. Fork the repository, so you have your own copy on GitHub. See the GitHub forking guide for more information.

  2. Clone the repository locally so that you have a local copy to work from:

    $ git clone https://github.com/{{ YOUR USERNAME }}/pydata-sphinx-theme
    $ cd pydata-sphinx-theme
    
Install your tools#

Building a Sphinx site uses a combination of Python and Jinja to manage HTML, SCSS, and JavaScript. To simplify this process, we use a few helper tools:

  • The Sphinx Theme Builder compiles web assets in an automated way.

  • pre-commit for automatically enforcing code standards and quality checks before commits.

  • nox for automating common development tasks.

  • pandoc the universal document converter.

In particular, nox can be used to automatically create isolated local development environments with all the correct packages installed to work on the theme. The rest of this guide focuses on using nox to start with a basic environment.

See also

The information on this page covers the basics to get you started, for information about manually compiling assets, see Set up a manual development environment.

Setup nox#

To start, install nox:

$ pip install nox

You can call nox from the command line to perform common actions that are needed in building the theme. nox operates with isolated environments, so each action has its own packages installed in a local directory (.nox). For common development actions, you’ll only need to use nox and won’t need to set up any other packages.

Setup pre-commit#

pre-commit allows us to run several checks on the codebase every time a new Git commit is made. This ensures standards and basic quality control for our code.

Install pre-commit with the following command:

$ pip install pre-commit

then navigate to this repository’s folder and activate it like so:

$ pre-commit install

This will install the necessary dependencies to run pre-commit every time you make a commit with Git.

Note

Your pre-commit dependencies will be installed in the environment from which you’re calling pre-commit, nox, etc. They will not be installed in the isolated environments used by nox.

Build the documentation#

Now that you have nox installed and cloned the repository, you should be able to build the documentation locally.

To build the documentation with nox, run the following command:

$ nox -s docs

This will install the necessary dependencies and build the documentation located in the docs/ folder. They will be placed in a docs/_build/html folder. If the docs have already been built, it will only build new pages that have been updated. You can open one of the HTML files there to preview the documentation locally.

Alternatively, you can invoke the built-in Python http.server with:

$ python -m http.server -d docs/_build/html/

This will print a local URL that you can open in a browser to explore the HTML files.

Change content and re-build#

Now that you’ve built the documentation, edit one of the source files to see how the documentation updates with new builds.

  1. Make an edit to a page. For example, add a word or fix a typo on any page.

  2. Rebuild the documentation with nox -s docs

It should go much faster this time because nox is re-using the previously created environment, and because Sphinx has cached the pages that you didn’t change.

Compile the CSS/JS assets#

The source files for CSS and JS assets are in src/pydata_sphinx_theme/assets. These are then built and bundled with the theme (e.g., scss is turned into css).

To compile the CSS/JS assets with nox, run the following command:

$ nox -s compile

This will compile all assets and place them in the appropriate folder to be used with documentation builds.

Note

Compiled assets are not committed to git. The sphinx-theme-builder will bundle these assets automatically when we make a new release, but we do not manually commit these compiled assets to git history.

Run a development server#

You can combine the above two actions (build the docs and compile JS/CSS assets) and run a development server so that changes to src/ are automatically bundled with the package, and the documentation is immediately reloaded in a live preview window.

To run the development server with nox, run the following command:

$ nox -s docs-live

When working on the theme, making changes to any of these directories:

  • src/js/index.js

  • src/scss/index.scss

  • docs/**/*.rst

  • docs/**/*.py

will cause the development server to do the following:

  • bundle/copy the CSS, JS, and vendored fonts

  • regenerate the Jinja2 macros

  • re-run Sphinx

Run the tests#

This theme uses pytest for its testing. There is a lightweight fixture defined in the test_build.py script that makes it straightforward to run a Sphinx build using this theme and inspect the results. There are also several automated accessibility checks in test_a11y.py.

Warning

Currently, the automated accessibility tests check the Kitchen Sink page only. We are working on extending coverage to the rest of the theme.

In addition, we use pytest-regressions to ensure that the HTML generated by the theme is what we’d expect. This module provides a file_regression fixture that will check the contents of an object against a reference file on disk. If the structure of the two differs, then the test will fail. If we expect the structure to differ, then delete the file on disk and run the test. A new file will be created, and subsequent tests will pass.

To run the build tests with nox, run the following command:

$ nox -s test

To run the accessibility checks:

$ nox -s a11y

Structure of this theme#

Location and structure of documentation#

The documentation for this theme is in the docs/ folder. It is structured as a Sphinx documentation site. The content is written in a combination of reStructuredText and MyST Markdown.

Location and structure of CSS/JS assets#

The CSS and JS for this theme are built for the browser from src/pydata_sphinx_theme/assets/* with webpack. The main entry points are:

  • CSS: src/pydata_sphinx_theme/assets/styles/pydata-sphinx-theme.scss

    • the main part of the theme assets

    • customizes Bootstrap with Sass

  • JS: src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js

    • provides add-on Bootstrap features, as well as some custom navigation behavior

  • webpack: webpack.config.js

    • captures the techniques for transforming the JS and CSS source files in src/pydata_sphinx_theme/assets/* into the production assets in src/theme/pydata_sphinx_theme/static/

Topic guides#

These guides cover specific topics that are relevant to contributing to this theme.

Accessibility checks#

Note

April-2023: we are currently re-evaluating how we do accessibility checks and reporting, so this may change soon.

In general, accessibility-checking tools can find a limited number of common HTML patterns which assistive technology can’t help users understand.

Accessibility checks as part of our development process#

We run a Lighthouse job in our CI/CD, which generates a “score” for all pages in our Kitchen Sink example documentation. The configuration for Lighthouse can be found in the .github/workflows/lighthouserc.json file.

For more information about configuring Lighthouse, see the Lighthouse documentation. For more information about Accessibility in general, see Accessibility.

We have also recently added automated tests using Playwright and axe-core to improve our accessibility testing and reporting.

Web assets (CSS/JS/Fonts)#

This theme includes several web assets to ease development and design. The configuration for our asset compilation is in webpack.config.js.

Compile and bundle assets#

When assets are compiled, static versions are placed in various places in the theme’s static folder:

src/pydata_sphinx_theme/theme/pydata_sphinx_theme/static

For many assets, a <hash> is generated and appended to the end of its reference in the HTML templates of the theme. This ensures the correct asset versions are served when viewers return to your site after upgrading the theme.

To compile the assets and bundle them with the theme, run this command:

$ nox -s compile
Styles (SCSS) and Scripts (JS)#

There are two relevant places for CSS/JS assets:

  • src/pydata_sphinx_theme/assets/styles has source files for SCSS assets. These will be compiled to CSS.

  • src/pydata_sphinx_theme/assets/scripts has source files for JS assets. These will be compiled to JS and import several vendored libraries (like Bootstrap).

  • src/pydata_sphinx_theme/theme/pydata_sphinx_theme/static has compiled versions of these assets (e.g. CSS files). This folder is not tracked in .git history, but it is bundled with the theme’s distribution.

Vendored scripts#

We vendor several packages in addition to our own CSS and JS. For example, Bootstrap, JQuery, and Popper. This is configured in the webpack.config.js file, and imported in the respective SCSS or JS file in our assets folder.

FontAwesome icons#

Three “styles” of the FontAwesome 6 Free icon font are used for icon links and admonitions and is the only vendored font.

  • It is managed as a dependency in package.json

  • Copied directly into the site statics at compilation, including licenses

  • Partially preloaded to reduce flicker and artifacts of early icon renders

  • Configured in webpack.config.js

Jinja macros#

Our Webpack build generates a collection of Jinja macros in the static/webpack-macros.html file.

These macros are imported in the main layout.html file, and then inserted at various places on the page to link the static assets.

Some assets are “preloaded”, meaning that the browser begins requesting these resources before they’re needed. In particular, our JavaScript assets are preloaded in <head>, and the scripts are loaded at the end of <body>.

Ignore formatting commits with git blame#

When making commits that are strictly formatting/style changes (e.g., after running a new version of black or running pyupgrade after dropping an old Python version), add the commit hash to .git-blame-ignore-revs, so git blame can ignore the change.

For more details, see:

Upgrade to bootstrap 5#

Since v0.13, pydata-sphinx-theme has moved from Bootstrap 4 to Bootstrap 5. This documentation will guide you through the changes we made and how you could follow the same steps in your existing documentation.

Dropping JQuery#

Bootstrap Dropped its JQuery dependency and rewrote plugins to be in regular JavaScript. Sphinx v6 will do the same (sphinx-doc/sphinx#10070). As a consequence, we also rewrote all our javascript to only use vanilla JavaScript. Any documentation relying on JQuery in their custom.js files will need to rewrite or specifically import JQuery.

Breaking changes#

Important

Relevant for those using a custom.css and/or a custom.js file!

Bootstrap changed several CSS classes, so if you wrote custom rules of JS logic that depended on them, it may have changed.

All the changes from v4 to v5 are listed in their documentation. Below list the ones that had consequences on pydata-sphinx-theme components.

Sass#
  • Media query mixins parameters have changed for a more logical approach.

    • media-breakpoint-down() uses the breakpoint itself instead of the next breakpoint (e.g., media-breakpoint-down(lg) instead of media-breakpoint-down(md) targets viewports smaller than lg).

    • Similarly, the second parameter in media-breakpoint-between() also uses the breakpoint itself instead of the next breakpoint (e.g., media-between(sm, lg) instead of media-breakpoint-between(sm, md) targets viewports between sm and lg).

  • box-shadow mixins now allow null values and drop none from multiple arguments.

Content, Reboot, etc#
  • Nested tables do not inherit styles anymore.

  • .thead-light and .thead-dark are dropped in favor of the .table-* variant classes which can be used for all table elements (thead, tbody, tfoot, tr, th and td).

  • Dropped .text-justify class. See twbs/bootstrap#29793

Utilities#
  • Renamed several utilities to use logical property names instead of directional names with the addition of RTL support:

    • Renamed .left-* and .right-* to .start-* and .end-*.

    • Renamed .float-left and .float-right to .float-start and .float-end.

    • Renamed .border-left and .border-right to .border-start and .border-end.

    • Renamed .rounded-left and .rounded-right to .rounded-start and .rounded-end.

    • Renamed .ml-* and .mr-* to .ms-* and .me-*.

    • Renamed .pl-* and .pr-* to .ps-* and .pe-*.

    • Renamed .text-left and .text-right to .text-start and .text-end.

JavaScript#
  • Data attributes for all JavaScript plugins are now namespaced to help distinguish Bootstrap functionality from third parties and your code. For example, we use data-bs-toggle instead of data-toggle.

  • Bootstrap’s Programmatic API, bootstrap, is also available. This API can be useful for initializing opt-in components that are not initialized by default such as Popovers.

Update Sphinx configuration during the build#

Sometimes you want to update configuration values during a build. For example, if you want to set a default if the user hasn’t provided a value, or if you want to move the value from one keyword to another for a deprecation.

Here are some tips to do this the “right” way in Sphinx.

Update config: use app.config#

For example, app.config.foo = "bar". For some reason, when Sphinx sets things it directly uses __dict__, but this doesn’t seem to be different from the pattern described here.

Update theme options: use app.builder.theme_options#

For example, app.builder.theme_options["logo"] = {"text": "Foo"}.

Check if a user has provided a default: app.config._raw_config#

The app.config._raw_config attribute contains all of the user-provided values. Use this if you want to check whether somebody has manually specified something. For example, "somekey" in app.config._raw_config will be False if a user has not provided that option.

You can also check app.config.overrides for any CLI-provided overrides.

We bundle both checks in a helper function called _config_provided_by_user.

Avoid the config-inited event#

This theme is activated after config-inited is triggered, so if you write an event that depends on it in this theme, then it will never occur. The earliest event you can use is builder-inited.

Update JavaScript dependencies and their versions#

There are two kinds of dependency definitions in this theme:

  • package.json contains the base dependencies for this theme. They are broken down into a few categories like dependencies and devDependencies. It is edited by the maintainers.

  • package-lock.json contains the complete frozen dependency chain for this theme, including all sub-dependencies of our base dependencies. It is automatically generated.

To update or add a JS dependency, follow these steps:

  1. Edit package.json by adding or modifying a dependency.

  2. Re-generate package-lock.json in order to create a new set of frozen dependencies for the theme. To do this, run the following command from the Sphinx Theme Builder.

    stb npm install --include=dev
    
  3. Commit both files to the repository. When new people pull in the latest commits, their npm environment will automatically update according to the new lockfile.

Internationalization#

Warning

This theme is still in the process of setting up internationalization. Some of the text below may not yet be correct (for example, we do not yet have a locales/ directory). Follow these issues to track progress:

Internationalization (I18N) and localization (L10N) is performed using Gettext.

Types of files#

Gettext reads a program’s source and extracts text that has been marked as translatable, known as “source strings. Gettext uses three types of files:

PO file (.po)

A Portable Object (PO) file is made up of many entries. Each entry holds the relation between a source string and its translation. msgid contains the source string, and msgstr contains the translation. In a given PO file, all translations are expressed in a single target language. PO files are also known as “message catalogs”.

Entries begin with comments, on lines starting with the character #. Comments are created and maintained by Gettext. Comment lines starting with #: contain references to the program’s source. These references allow a human translator to find the source strings in their original context. Comment lines starting with #, contain flags like python-format, which indicates that the source string contains placeholders like %(copyright)s.

POT file (.pot)

A Portable Object Template (POT) file is the same as a PO file, except the translations are empty, so that it can be used as a template for new languages.

MO file (.mo)

A Machine Object (MO) file is a binary version of a PO file. PO files are compiled to MO files, which are required by Gettext.

Mark natural language text as translateable#

All natural language text must be marked as translatable, so that it can be extracted by Gettext and translated by humans.

Jinja2 provides a trans block and a _() function to mark text as translatable. Please refer to the Jinja2 documentation. Remember to manually escape variables if needed.

Any text that is marked in this way will be discoverable by gettext and used to generate .po files (see below for information). Once you’ve marked text as translateable, complete the steps for Add or change natural language text.

Add or change natural language text#

These steps cover how to add or change text that has been marked as translateable.

  1. Edit the natural language text as desired. Ensure that it is {ref}`marked as translateable <adding-natural-language-text>`.

  2. Generate/update the message catalog template (POT file) with the PyBabel extract command:

    pybabel extract . -F babel.cfg -o src/pydata_sphinx_theme/locale/sphinx.pot -k '_ __ l_ lazy_gettext'
    

    To run this in ``.nox``: nox -s translate -- extract.

  3. Update the message catalogs (PO files) with the PyBabel update command:

    pybabel update -i src/pydata_sphinx_theme/locale/sphinx.pot -d src/pydata_sphinx_theme/locale -D sphinx
    

    To run this in ``.nox``: nox -s translate -- update.

This will update these files with new information about the position and text of the language you have modified.

If you only change non-translatable text (like HTML markup), the extract and update commands will only update the positions (line numbers) of the translatable strings. Updating positions is optional - the line numbers are to inform the human translator, not to perform the translation.

If you change translatable strings, the extract command will extract the new or updated strings to the POT file, and the update command will try to fuzzy match the new or updated strings with existing translations in the PO files. If there is a fuzzy match, a comment like #, fuzzy is added before the matched entry. Otherwise, a new entry is added and needs to be translated.

Add translations to translateable text#

Once text has been marked as translateable, and PO files have been generated for it, we may add translations for new languages for the phrase. This section covers how to do so.

Note

These steps use the Spanish language as an example. To translate the theme to another language, replace es with the language’s two-letter lowercase ISO 639-1 code.

  1. If the language’s code matches no sub-directory of the pydata_sphinx_theme/locale directory, initialize the language’s message catalog (PO file) with PyBabel init:

    pybabel init -i src/pydata_sphinx_theme/locale/sphinx.pot -d src/pydata_sphinx_theme/locale -D sphinx -l es
    

    To run this in ``.nox``: nox -s translate -- init es

  2. Edit the language’s message catalog at pydata_sphinx_theme/locale/es/LC_MESSAGES/sphinx.po. For each source string introduced by the msgid keyword, add its translation after the msgstr keyword.

  3. Compile the message catalogs of every language. This creates or updates the MO files with PyBabel compile:

    pybabel compile -d src/pydata_sphinx_theme/locale -D sphinx
    

    To run this in ``.nox``: nox -s translate -- compile.

Translation tips#
Translate phrases, not words#

Full sentences and clauses must always be a single translatable string. Otherwise, you can get next page translated as suivant page instead of as page suivante, etc.

Deal with variables and markup in translations#

If a variable (like the edit_page_provider_name theme option) is used as part of a phrase, it must be included within the translatable string. Otherwise, the word order in other languages can be incorrect. In a Jinja template, simply surround the translatable string with {% trans variable=variable %} and {% endtrans %}}`. For example: ``{% trans provider=provider %}Edit on {{ provider }}{% endtrans %} The translatable string is extracted as the Python format string Edit on %(provider)s. This is so that the same translatable string can be used in both Python code and Jinja templates. It is the translator’s responsibility to use %(provider)s verbatim in the translation.

If a non-translatable word or token (like HTML markup) is used as part of a phrase, it must also be included within the translatable string. For example: {% trans theme_version=theme_version|e %}Built with the <a href="https://pydata-sphinx-theme.readthedocs.io/en/stable/index.html">PyData Sphinx Theme</a> {{ theme_version }}.{% endtrans %} It is the translator’s responsibility to use the HTML markup verbatim in the translation.

References#

I18N and L10N are deep topics. Here, we only cover the bare minimum needed to fulfill basics technical tasks. You might like:

Update our kitchen sink#

The kitchen sink reference is for demonstrating as much syntax and style for Sphinx builds as possible. It is copied directly from the sphinx-themes.org documentation so that we use standardized reference docs compared with other communities. The source files for these pages are stored in the sphinx-themes.org repository.

To update the kitchen sink source files, there is a helper Python script that will loop through the known kitchen sink files and copy over the latest text. To use it, run the following from the root of the repository:

Set up a manual development environment#

If you prefer not to use automation tools like nox, or want to have more control over the specific version of packages that you’d like installed, you may also manually set up a development environment locally.

To do so, follow the instructions on this page.

Create a new development environment#

This is optional, but it’s best to start with a fresh development environment so that you’ve isolated the packages that you’re using for this repository.

To do so, use a tool like conda, mamba, or virtualenv.

Install dependencies#

You must install sphinx-theme-builder and Pandoc.

We use the sphinx-theme-builder to install nodejs locally and to compile all CSS and JS assets needed for the theme. Install it like so (note the cli option so that we can run it from the command line):

$ pip install "sphinx-theme-builder[cli]"

We use nbsphinx to support notebook (.ipynb) files in the documentation, which requires installing Pandoc at a system level (or within a Conda environment).

Clone the repository locally#

First clone this repository from the pydata organization, or from a fork that you have created:

$ git clone https://github.com/pydata/pydata-sphinx-theme
$ cd pydata-sphinx-theme
Install this theme locally#

Next, install this theme locally so that we have the necessary dependencies to build the documentation and testing suite:

$ pip install -e ".[dev]"

Note that the sphinx-theme-builder will automatically install a local copy of nodejs for building the theme’s assets. This will be placed in a .nodeenv folder.

Build the documentation#

To manually build the documentation, run the following command:

$ sphinx-build docs docs/_build/html
Compile web assets (JS/CSS)#

To compile the JavaScript and CSS assets for the theme, run the following command:

$ stb compile

This will compile everything in the src/pydata_sphinx_theme/assets folder and place them in the appropriate places in our theme’s folder structure.

Start a live server to build and serve your documentation#

To manually open a server to watch your documentation for changes, build them, and display them locally in a browser, run this command:

$ stb serve docs --open-browser
Run the tests#

To manually run the tests for this theme, first set up your environment locally, and then run:

$ pytest
Using nox#

Here are a few extra tips for using nox.

See also

The nox command line documentation has a lot of helpful tips for extra functionality you can enable with the CLI.

Re-install dependencies#

To re-execute the installation commands, use this pattern:

$ nox -s docs -- reinstall

Or to completely remove the environment generated by nox and start from scratch:

$ rm -rf .nox/docs
Use nox with your global environment#

If you’d like to use nox with your global environment (the one from which you are calling nox), you can do so with:

$ nox --force-venv-backend none

# alternatively:
$ nox --no-venv

Using none will re-use your current global environment. See the nox documentation for more details.

Page-level configuration#

In some areas we support page-level configuration to control behavior on a per-page basis. Try to make this configuration follow the html_theme_options structure of our configuration as much as possibl. Begin them with html_theme, and separate “nested” configuration sections with periods (.). This is similar to how the TOML language defines nested configuration.

For example, to remove the secondary sidebar, we use a page metadata key like this:

:html_theme.sidebar_secondary.remove: true
---
html_theme.sidebar_secondary.remove: true
---

Note how the period naturally separates nested sections, and looks very similar to what we’d expect if we put this in a Python dictionary in conf.py:

html_theme_options = {
   "sidebar_secondary": {"remove": "true"}
}
Using pre-commit#

Here are a few tips for using pre-commit:

Skip the pre-commit checks#

Run the following command:

$ git commit --no-verify
Run pre-commit on all files#

By default, pre-commit will run its checks on files that have been modified in a commit. To instead run it on all files, use this command:

$ pre-commit run --all-files

# Alternatively
$ pre-commit run -a
PyData package support#

This theme is designed by and for the PyData community, and so there are a few places where we special-case support for packages in this community.

We define CSS rules that ensure PyData content in Sphinx looks reasonable on both light and dark themes. If we hear reports from maintainers that we could change something in this theme that would make their documentation look better, and if this change is sustainable for us, then we should do so.

We store our PyData-specific SCSS in two relevant files, both in the src/pydata_sphinx_theme/assets/styles/ folder:

  • extensions/_execution.scss - styles for Sphinx libraries that execute and insert code into the documentation. For example, MyST-NB, Jupyter Sphinx, and the Matplotlib plot directive. Most PyData support should go here via generic improvements that all packages benefit from.

  • extensions/_pydata.scss - styles for specific libraries in the PyData ecosystem. In general we should try to keep this minimal because it is mostly special-casing single library quirks.

Expected build warnings#

In our CI workflow, we use a script to check for any warnings raised by Sphinx to assert that the only warnings are expected ones. The list of expected warnings can be found in :code:tests/warning_list.txt. To add a new entry, copy/paste the warning message (the message beginning with :code:WARNING:) to the bottom of the file.

For example if you get:

Unexpected warning: C:\hostedtoolcache\windows\Python\3.9.13\x64\lib\site-packages\pandas\core\frame.py:docstring of pandas.core.frame.DataFrame.groupby:42: WARNING: undefined label: 'groupby.transform'

Add the following to the txt file:

WARNING: undefined label: 'groupby.transform'

Merge and review policy#

Our policy for merging and reviewing describes how we review one another’s work, and when we allow others to merge changes into our main codebase. It tries to balance a few goals:

  • Iterate on PRs and merge them relatively quickly, so that we reduce the debt associated with long-lasting PRs.

  • Give enough time for others to provide their input and guide the PR itself, and to ensure that we aren’t creating a problem with the PR.

  • Value iterative improvement over creating the perfect Pull Request, so that we do not burden contributors with cumbersome discussion and minor revision requests.

  • Recognize that we all have limited time and resources, and so cannot guarantee a full quality assurance process each time.

  • Give general preference to the opinions of maintainers of projects in the PyData ecosystem, as a key stakeholder community of this theme.

We follow these guidelines to achieve these goals:

  • Assume that all maintainers are acting in good faith and will use their best judgment to make decisions in the best interests of the repository.

  • We can and will make mistakes, so encourage best practices in testing and documentation to guard against this.

  • It’s important to share information, so give your best effort at telling others about the work that you’re doing.

  • It’s best to discuss and agree on important decisions at a high level before implementation, so give the best effort at providing time and invitation for others to provide feedback.

Policy for moderate changes#

These are changes that make modest changes to new or existing functionality, but that aren’t going to significantly change the default behavior of the theme, user configuration, etc. This is the majority of changes that we make.

PRs should:

  • Refer to (and ideally close) an issue that describes the problem this change is solving.

  • Have relevant testing and documentation coverage.

They can be merged when the above conditions are met, and one of these things happens:

  • The PR has at least one approval from a core maintainer that isn’t the PR author

  • The PR author has signaled their intent to merge unless there are objections, and 48 hours have passed since that comment.

Policy for major new features and breaking changes#

These are changes that significantly alter the experience of the user, or that add significant complexity to the codebase.

All the above, but PRs must have approval from at least one other core maintainer before merging. In addition, the PR author should put extra effort into ensuring that the relevant stakeholders are notified about a change, so they can gauge its impact and provide feedback.

Policy For minor changes and bugfixes#

These are small changes that might be noticeable to the user, but in a way that is clearly an improvement. They generally shouldn’t touch too many lines of code.

Update the relevant tests and documentation, but PR authors are welcome to self-merge whenever they like without PR approval.

Making releases#

Our goals#

Our release policy describes how we decide when to make a new public release of the theme so that other projects may use new features and improvements. It tries to balance these goals:

  • Release relatively frequently, so that we provide a continuous stream of improvement to projects that use the theme, and minimize the effort needed to upgrade.

  • Do not surprise people (especially with negative surprises) and provide time for projects to provide feedback about upcoming features.

  • Minimize the toil and complexity associated with releases, and reduce information silos and bottlenecks associated with them.

When to make a release#

Anybody is encouraged to make a new release if:

  • It has been more than a month since the last release.

  • OR a significant change has been made to our code that warrants a release.

  • AND there are no open issues with a impact: block-release label.

Release candidates#

If a release includes complex or many changes (especially in JavaScript), make a release candidate and ask for feedback from users. This is important because we do not test much of the CSS and JavaScript-based functionality in our testing infrastructure. After a week or so, if there are no blocking issues that have been opened since the Release Candidate, we can make a full release.

Process for making a release#

This theme uses GitHub tags and releases to automatically push new releases to PyPI. Follow these steps to make a release:

  • (optionally) Create a GitHub milestones to organize the issues that should be resolved as part of a new release.

  • Decide if it’s time to make a release be reading When to make a release and decide if it is time for a release.

  • Copy the release checklist into a new issue.

  • Complete the checklist. That’s it!

Choosing a version increment#

We use semantic versioning to decide whether it’s a major, minor, or patch bump. Before we have released 1.0, treat minor versions as breaking releases, and patch versions as feature / patch releases. If this is a release candidate, tag it like 0.1rc1.

Supported Python and Sphinx versions#

Python and Sphinx are the two primary dependencies of this theme. We have particular practices for deciding which versions of these we support (especially Sphinx, which tends to release breaking changes).

Supported Python versions#

For releases of Python, we aim to follow this approach[1]:

For a new major/minor release of this theme, we support any minor Python versions released in the last 3.5 years (42 months), as defined in the EOL schedule for Python[2].

We define “support” as testing against each of these versions so that users can be assured they will not trigger any bugs.

For example, if we made a minor release tomorrow, we’d look at the EOL schedule for Python and support all the versions that fall within a 3.5-year window.

Supported Sphinx versions#

For supported versions of Sphinx, we aim to follow this approach:

We support the latest released version of Sphinx that is older than 6 months. We unofficially support earlier released versions of Sphinx, but may increase the lower-bound in our dependency pin without warning if needed[2].

When a new pre-release of Sphinx is released, we should follow these steps:

  • Ensure that our tests are passing. We run our tests with any pre-releases of Sphinx, so we can test major errors quickly and make the necessary changes.

  • Look at the Sphinx Changelog and make sure there are no changes that might break things that aren’t captured by our tests.

  • Look at the deprecated API changes and make sure there are no changes that might break things that aren’t captured by our tests.

  • Look at the docutils changelog in case there’s a new docutils version supported that breaks something.

Note

This theme does not pin the upper version of Sphinx that it supports. If a Sphinx release causes major breaking changes for our users, and we do not have the capacity to update our code and release a fix, we may temporarily pin the upper bound of Sphinx we support until this is fixed.


Contributors to this theme#

This theme is supported and developed by various members of the PyData community.

Collaborators on the repository#

Here is a grid of collaborators on our GitHub repository. We don’t yet have formal “team definitions” so this is mostly a reflection of who has commit rights to the repository.

Financial support#

Support and development for this theme has been funded by one NumFocus Small Development Grant on behalf of several communities in the PyData ecosystem.

Inspiration for design and UX#

To build this theme we drew inspiration from other great projects on the web that we would like to acknowledge here. When making new decisions about design and UI/UX, we often consult these themes to see what they’re doing.

Examples#

Several example pages to demonstrate the functionality of this theme when used alongside other Sphinx extensions.

Examples#

These sections show off various features and styles of this theme. They should help you understand how this theme behaves and how others are using it. See the sections in the primary sidebar and below to explore.

Kitchen Sink#

Note

The Kitchen Sink was generated from the Sphinx Themes website, a community-supported showcase of themes for Sphinx. Check it out to see other great themes.

Go to Sphinx Themes

This section exists as a dump of all the things that Sphinx has.

It has exactly one goal: to be a good checklist of things to stylise within Sphinx. This also means that it is a complete showcase of everything that vanilla Sphinx provides and includes all sorts of edge cases.

Admonitions#

Sphinx provides several different types of admonitions.

topic#
admonition#

The one with the custom titles

It’s got a certain charm to it.

attention#

Attention

Climate change is real.

caution#

Caution

Cliff ahead: Don’t drive off it.

danger#

Danger

Mad scientist at work!

error#

Error

Does not compute.

hint#

Hint

Insulators insulate, until they are subject to ______ voltage.

important#

Important

Tech is not neutral, nor is it apolitical.

note#

Note

This is a note.

seealso#

See also

Other relevant information.

tip#

Tip

25% if the service is good.

todo#

Todo

This needs the sphinx.ext.todo extension.

warning#

Warning

Reader discretion is strongly advised.

versionadded#

Added in version v0.1.1: Here’s a version added message.

versionchanged#

Changed in version v0.1.1: Here’s a version changed message.

deprecated#

Deprecated since version v0.1.1: Here’s a deprecation message.

API documentation#

Using Sphinx’s sphinx.ext.autodoc plugin, it is possible to auto-generate documentation of a Python module.

Tip

Avoid having in-function-signature type annotations with autodoc, by setting the following options:

# -- Options for autodoc ----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#configuration

# Automatically extract typehints when specified and place them in
# descriptions of the relevant function/method.
autodoc_typehints = "description"

# Don't show class signature with the class' name.
autodoc_class_signature = "separated"

Parse (absolute and relative) URLs.

urlparse module is based upon the following RFC specifications.

RFC 3986 (STD66): “Uniform Resource Identifiers” by T. Berners-Lee, R. Fielding and L. Masinter, January 2005.

RFC 2732 : “Format for Literal IPv6 Addresses in URL’s by R.Hinden, B.Carpenter and L.Masinter, December 1999.

RFC 2396: “Uniform Resource Identifiers (URI)”: Generic Syntax by T. Berners-Lee, R. Fielding, and L. Masinter, August 1998.

RFC 2368: “The mailto URL scheme”, by P.Hoffman , L Masinter, J. Zawinski, July 1998.

RFC 1808: “Relative Uniform Resource Locators”, by R. Fielding, UC Irvine, June 1995.

RFC 1738: “Uniform Resource Locators (URL)” by T. Berners-Lee, L. Masinter, M. McCahill, December 1994

RFC 3986 is considered the current standard and any future changes to urlparse module should conform with it. The urlparse module is currently not entirely compliant with this RFC due to defacto scenarios for parsing, and for backward compatibility purposes, some parsing quirks from older RFCs are retained. The testcases in test_urlparse.py provides a good indicator of parsing behavior.

The WHATWG URL Parser spec should also be considered. We are not compliant with it either due to existing user code API behavior expectations (Hyrum’s Law). It serves as a useful guide when making changes.

class urllib.parse.DefragResult(url, fragment)[source]#

Methods

count(value, /)

Return number of occurrences of value.

index(value[, start, stop])

Return first index of value.

encode

geturl

class urllib.parse.DefragResultBytes(url, fragment)[source]#

Methods

count(value, /)

Return number of occurrences of value.

index(value[, start, stop])

Return first index of value.

decode

geturl

class urllib.parse.ParseResult(scheme, netloc, path, params, query, fragment)[source]#
Attributes:
hostname
password
port
username

Methods

count(value, /)

Return number of occurrences of value.

index(value[, start, stop])

Return first index of value.

encode

geturl

class urllib.parse.ParseResultBytes(scheme, netloc, path, params, query, fragment)[source]#
Attributes:
hostname
password
port
username

Methods

count(value, /)

Return number of occurrences of value.

index(value[, start, stop])

Return first index of value.

decode

geturl

class urllib.parse.SplitResult(scheme, netloc, path, query, fragment)[source]#
Attributes:
hostname
password
port
username

Methods

count(value, /)

Return number of occurrences of value.

index(value[, start, stop])

Return first index of value.

encode

geturl

class urllib.parse.SplitResultBytes(scheme, netloc, path, query, fragment)[source]#
Attributes:
hostname
password
port
username

Methods

count(value, /)

Return number of occurrences of value.

index(value[, start, stop])

Return first index of value.

decode

geturl

urllib.parse.parse_qs(qs, keep_blank_values=False, strict_parsing=False, encoding='utf-8', errors='replace', max_num_fields=None, separator='&')[source]#

Parse a query given as a string argument.

Arguments:

qs: percent-encoded query string to be parsed

keep_blank_values: flag indicating whether blank values in

percent-encoded queries should be treated as blank strings. A true value indicates that blanks should be retained as blank strings. The default false value indicates that blank values are to be ignored and treated as if they were not included.

strict_parsing: flag indicating what to do with parsing errors.

If false (the default), errors are silently ignored. If true, errors raise a ValueError exception.

encoding and errors: specify how to decode percent-encoded sequences

into Unicode characters, as accepted by the bytes.decode() method.

max_num_fields: int. If set, then throws a ValueError if there

are more than n fields read by parse_qsl().

separator: str. The symbol to use for separating the query arguments.

Defaults to &.

Returns a dictionary.

urllib.parse.parse_qsl(qs, keep_blank_values=False, strict_parsing=False, encoding='utf-8', errors='replace', max_num_fields=None, separator='&')[source]#

Parse a query given as a string argument.

Arguments:

qs: percent-encoded query string to be parsed

keep_blank_values: flag indicating whether blank values in

percent-encoded queries should be treated as blank strings. A true value indicates that blanks should be retained as blank strings. The default false value indicates that blank values are to be ignored and treated as if they were not included.

strict_parsing: flag indicating what to do with parsing errors. If

false (the default), errors are silently ignored. If true, errors raise a ValueError exception.

encoding and errors: specify how to decode percent-encoded sequences

into Unicode characters, as accepted by the bytes.decode() method.

max_num_fields: int. If set, then throws a ValueError

if there are more than n fields read by parse_qsl().

separator: str. The symbol to use for separating the query arguments.

Defaults to &.

Returns a list, as G-d intended.

urllib.parse.quote('abc def') 'abc%20def'[source]#

Each part of a URL, e.g. the path info, the query, etc., has a different set of reserved characters that must be quoted. The quote function offers a cautious (not minimal) way to quote a string for most of these parts.

RFC 3986 Uniform Resource Identifier (URI): Generic Syntax lists the following (un)reserved characters.

unreserved = ALPHA / DIGIT / “-” / “.” / “_” / “~” reserved = gen-delims / sub-delims gen-delims = “:” / “/” / “?” / “#” / “[” / “]” / “@” sub-delims = “!” / “$” / “&” / “’” / “(” / “)”

/ “*” / “+” / “,” / “;” / “=”

Each of the reserved characters is reserved in some component of a URL, but not necessarily in all of them.

The quote function %-escapes all characters that are neither in the unreserved chars (“always safe”) nor the additional chars set via the safe arg.

The default for the safe arg is ‘/’. The character is reserved, but in typical usage the quote function is being called on a path where the existing slash characters are to be preserved.

Python 3.7 updates from using RFC 2396 to RFC 3986 to quote URL strings. Now, “~” is included in the set of unreserved characters.

string and safe may be either str or bytes objects. encoding and errors must not be specified if string is a bytes object.

The optional encoding and errors parameters specify how to deal with non-ASCII characters, as accepted by the str.encode method. By default, encoding=’utf-8’ (characters are encoded with UTF-8), and errors=’strict’ (unsupported characters raise a UnicodeEncodeError).

urllib.parse.quote_from_bytes(bs, safe='/')[source]#

Like quote(), but accepts a bytes object rather than a str, and does not perform string-to-bytes encoding. It always returns an ASCII string. quote_from_bytes(b’abc def?’) -> ‘abc%20def%3f’

urllib.parse.quote_plus(string, safe='', encoding=None, errors=None)[source]#

Like quote(), but also replace ‘ ‘ with ‘+’, as required for quoting HTML form values. Plus signs in the original string are escaped unless they are included in safe. It also does not have safe default to ‘/’.

urllib.parse.unquote(string, encoding='utf-8', errors='replace')[source]#

Replace %xx escapes by their single-character equivalent. The optional encoding and errors parameters specify how to decode percent-encoded sequences into Unicode characters, as accepted by the bytes.decode() method. By default, percent-encoded sequences are decoded with UTF-8, and invalid sequences are replaced by a placeholder character.

unquote(‘abc%20def’) -> ‘abc def’.

urllib.parse.unquote_plus(string, encoding='utf-8', errors='replace')[source]#

Like unquote(), but also replace plus signs by spaces, as required for unquoting HTML form values.

unquote_plus(‘%7e/abc+def’) -> ‘~/abc def’

urllib.parse.unquote_to_bytes('abc%20def') b'abc def'.[source]#
urllib.parse.urldefrag(url)[source]#

Removes any existing fragment from URL.

Returns a tuple of the defragmented URL and the fragment. If the URL contained no fragments, the second element is the empty string.

urllib.parse.urlencode(query, doseq=False, safe='', encoding=None, errors=None, quote_via=<function quote_plus>)[source]#

Encode a dict or sequence of two-element tuples into a URL query string.

If any values in the query arg are sequences and doseq is true, each sequence element is converted to a separate parameter.

If the query arg is a sequence of two-element tuples, the order of the parameters in the output will match the order of parameters in the input.

The components of a query arg may each be either a string or a bytes type.

The safe, encoding, and errors parameters are passed down to the function specified by quote_via (encoding and errors only if a component is a str).

urllib.parse.urljoin(base, url, allow_fragments=True)[source]#

Join a base URL and a possibly relative URL to form an absolute interpretation of the latter.

urllib.parse.urlparse(url, scheme='', allow_fragments=True)[source]#

Parse a URL into 6 components: <scheme>://<netloc>/<path>;<params>?<query>#<fragment>

The result is a named 6-tuple with fields corresponding to the above. It is either a ParseResult or ParseResultBytes object, depending on the type of the url parameter.

The username, password, hostname, and port sub-components of netloc can also be accessed as attributes of the returned object.

The scheme argument provides the default value of the scheme component when no scheme is found in url.

If allow_fragments is False, no attempt is made to separate the fragment component from the previous component, which can be either path or query.

Note that % escapes are not expanded.

urllib.parse.urlsplit(url, scheme='', allow_fragments=True)[source]#

Parse a URL into 5 components: <scheme>://<netloc>/<path>?<query>#<fragment>

The result is a named 5-tuple with fields corresponding to the above. It is either a SplitResult or SplitResultBytes object, depending on the type of the url parameter.

The username, password, hostname, and port sub-components of netloc can also be accessed as attributes of the returned object.

The scheme argument provides the default value of the scheme component when no scheme is found in url.

If allow_fragments is False, no attempt is made to separate the fragment component from the previous component, which can be either path or query.

Note that % escapes are not expanded.

urllib.parse.urlunparse(components)[source]#

Put a parsed URL back together again. This may result in a slightly different, but equivalent URL, if the URL that was parsed originally had redundant delimiters, e.g. a ? with an empty query (the draft states that these are equivalent).

urllib.parse.urlunsplit(components)[source]#

Combine the elements of a tuple as returned by urlsplit() into a complete URL as a string. The data argument can be any five-item iterable. This may result in a slightly different, but equivalent URL, if the URL that was parsed originally had unnecessary delimiters (for example, a ? with an empty query; the RFC states that these are equivalent).

Blocks#
Block Quotes#

Block quotes consist of indented body elements:

My theory by A. Elk. Brackets Miss, brackets. This theory goes as follows and begins now. All brontosauruses are thin at one end, much much thicker in the middle and then thin again at the far end. That is my theory, it is mine, and belongs to me and I own it, and what it is too.

—Anne Elk (Miss)

Epigraph#

https://docutils.sourceforge.io/docs/ref/rst/directives.html#epigraph

My theory by A. Elk. Brackets Miss, brackets. This theory goes as follows and begins now. All brontosauruses are thin at one end, much much thicker in the middle and then thin again at the far end. That is my theory, it is mine, and belongs to me and I own it, and what it is too.

—Anne Elk (Miss)

Pull quotes#

https://docutils.sourceforge.io/docs/ref/rst/directives.html#pull-quote

My theory by A. Elk. Brackets Miss, brackets. This theory goes as follows and begins now. All brontosauruses are thin at one end, much much thicker in the middle and then thin again at the far end. That is my theory, it is mine, and belongs to me and I own it, and what it is too.

—Anne Elk (Miss)

Highlights#

https://docutils.sourceforge.io/docs/ref/rst/directives.html#highlights

My theory by A. Elk. Brackets Miss, brackets. This theory goes as follows and begins now. All brontosauruses are thin at one end, much much thicker in the middle and then thin again at the far end. That is my theory, it is mine, and belongs to me and I own it, and what it is too.

—Anne Elk (Miss)

Line Blocks#

https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#line-blocks

This is a normal text paragraph.

This is a line block. It ends with a blank line.
Each new line begins with a vertical bar (“|”).
Line breaks and initial indents are preserved.
Continuation lines are wrapped portions of long lines; they begin with a space in place of the vertical bar.
The left edge of a continuation line need not be aligned with the left edge of the text above it.
This is a second line block.

Blank lines are permitted internally, but they must begin with a “|”.

This is a normal text paragraph again.

Monospace Blocks#

Sphinx supports many kinds of monospace blocks. This section is meant to showcase all of them that as known to the author of this page, at the time of writing.

Production List#

https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-productionlist

This directive is used to enclose a group of productions. Each production is given on a single line and consists of a name, separated by a colon from the following definition.

This just shows up as a vanilla <pre>, which is… both nice and a bit annoying.

try_stmt  ::=  try1_stmt | try2_stmt
try1_stmt ::=  "try" ":" suite
               ("except" [expression ["," target]] ":" suite)+
               ["else" ":" suite]
               ["finally" ":" suite]
try2_stmt ::=  "try" ":" suite
               "finally" ":" suite
               "this-is-intentionally-very-stupidly-long-to-make-sure-that-this-has-a-proper-scrollbar"
Literal Blocks#

https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#literal-blocks

contains a block of text where line breaks and whitespace are significant and must be preserved

This is a normal text paragraph. The next paragraph is a code sample:

It is not processed in any way, except
that the indentation is removed.

It can span multiple lines.

This is a normal text paragraph again.

They can be quoted without indentation:

>> Great idea!
>
> Why didn't I think of that?
Literal includes can also have captions.#
 1from requests.exceptions import ConnectionError, HTTPError, RetryError
 2from sphinx.application import Sphinx
 3from sphinx.builders.dirhtml import DirectoryHTMLBuilder
 4from sphinx.errors import ExtensionError
 5
 6from . import edit_this_page, logo, pygment, short_link, toctree, translator, utils
 7
 8__version__ = "0.15.3rc1"
 9
10
11def update_config(app):
Doctest Blocks#

https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#doctest-blocks

Doctest blocks are interactive Python sessions cut-and-pasted into docstrings. They are meant to illustrate usage by example, and provide an elegant and powerful testing environment via the doctest module in the Python standard library.

Note

This is fine.

>>> print('Python-specific usage examples; begun with ">>>"')
Python-specific usage examples; begun with ">>>"
>>> print("(cut and pasted from interactive Python sessions)")
(cut and pasted from interactive Python sessions)
>>> print("This is an intentionally very long line because I want to make sure that we are handling scrollable code blocks correctly.")
This is an intentionally very long line because I want to make sure that we are handling scrollable code blocks correctly.
Parsed Literals#

https://docutils.sourceforge.io/docs/ref/rst/directives.html#parsed-literal-block

It is equivalent to a line block with different rendering: typically in a typewriter/monospaced typeface, like an ordinary literal block. Parsed literal blocks are useful for adding hyperlinks to code examples.

# parsed-literal test
curl -O http://someurl/release-0.1.0.tar-gz
echo "This is an intentionally very long line because I want to make sure that we are handling scrollable code blocks correctly."
Code Block#

https://docutils.sourceforge.io/docs/ref/rst/directives.html#code

The “code” directive constructs a literal block [containing code].

This has an alias of code-block.

 1from typing import Iterator
 2
 3# This is an example
 4class Math:
 5    @staticmethod
 6    def fib(n: int) -> Iterator[int]:
 7        """Fibonacci series up to n"""
 8        a, b = 0, 1
 9        while a < n:
10            yield a
11            a, b = b, a + b
12
13
14result = sum(Math.fib(42))
15print("The answer is {}".format(result))
With caption#
Code Blocks can have captions, which also adds a link to it.#
{
  "session_name": "shorthands",
  "windows": [
    {
      "panes": [
        {
          "shell_command": "echo 'This is an intentionally very long line because I want to make sure that we are handling scrollable code blocks correctly.'"
        }
      ],
      "window_name": "long form"
    }
  ]
}
With line numbers#
1def some_function():
2    interesting = False
3    print("This line is highlighted.")
4    print("This one is not...")
5    print("...but this one is.")
6    print(
7        "This is an intentionally very long line because I want to make sure that we are handling scrollable code blocks correctly."
8    )
Without highlighting#
# Taken from https://en.wikipedia.org/wiki/Pseudocode#Example
algorithm ford-fulkerson is
    input: Graph G with flow capacity c,
        source node s,
        sink node t
    output: Flow f such that f is maximal from s to t

    (Note that f(u,v) is the flow from node u to node v, and c(u,v) is the flow capacity from node u to node v)

    for each edge (u, v) in GE do
        f(u, v) ← 0
        f(v, u) ← 0

    while there exists a path p from s to t in the residual network Gf do
        let cf be the flow capacity of the residual network Gf
        cf(p) ← min{cf(u, v) | (u, v) in p}
        for each edge (u, v) in p do
            f(u, v) ←  f(u, v) + cf(p)
            f(v, u) ← −f(u, v)

    return f
Generic items#

These are the things that don’t quite fit into other groupings.

Inline Markup#

One of the nice things about markup languages is the ability to have inline markup. This makes the presentation much nicer. The bold text shouldn’t be too overbearing. It is very common to have inline code as well. It is important to ensure that the inline code doesn’t have a line height that is greater than the regular prose; otherwise the spacing looks weird.

It is also possible to use explicit roles to do things like a subscript, a superscript, emphasis, strong, and literal.

Interpreted text#

The default role for “interpreted text” (AKA single backticks) is Title Reference. There are other reference syntaxes as well: PEP 287 and RFC 2822.

If the --pep-references option was supplied, there should be a live link to PEP 258 here.

GUI labels#

According to the RST demo, GUI labels (like this label) are a way to indicate that some action is to be taken by the user. Like inline code literals, GUI labels should not run over line height.

Keys / Menu labels#

Key-bindings indicate that the read is to press a button on the keyboard or mouse, for example MMB, ++M and Shift-MMB. Another useful way is menuselection to show menus: My ‣ Software ‣ Some menu ‣ Some sub menu 1 ‣ Some sub menu 2 ‣ Some sub menu 3

For example, menuselection should break when it is too long to fit on a single line.

Long inline code wrapping#

Let’s test wrapping and whitespace significance in inline literals: This is an example of --inline-literal --text, --including some-- strangely--hyphenated-words.  Adjust-the-width-of-your-browser-window to see how the text is wrapped.  -- ---- --------  Now note    the spacing    between the    words of    this sentence    (words should    be grouped    in pairs).

Math#

This is a test. Here is an equation: \(X_{0:5} = (X_0, X_1, X_2, X_3, X_4)\). Here is another:

(1)#\[\nabla^2 f = \frac{1}{r^2} \frac{\partial}{\partial r} \left( r^2 \frac{\partial f}{\partial r} \right) + \frac{1}{r^2 \sin \theta} \frac{\partial f}{\partial \theta} \left( \sin \theta \, \frac{\partial f}{\partial \theta} \right) + \frac{1}{r^2 \sin^2\theta} \frac{\partial^2 f}{\partial \phi^2}\]

You can add a link to equations like the one above (1) by using :eq:.

References#
Footnotes#
Citations#

Here’s a reference to the above, [12] citation.

Here is another type of citation: citation

Targets#

This paragraph is pointed to by the explicit “example” target. A reference can be found under Inline Markup, above. Inline hyperlink targets are also possible.

Section headers are implicit targets, referred to by name. See Targets.

Explicit external targets are interpolated into references such as “Python [4]”.

Targets may be indirect and anonymous. Thus this phrase may also refer to the Targets section.

Target Footnotes#
Centered text#

You can create a statement with centered text with .. centered::

This is centered text!

Rubric#

A rubric is like an informal heading that doesn’t correspond to the document’s structure.

https://docutils.sourceforge.io/docs/ref/rst/directives.html#rubric

Wikipedia says it is something different:

A rubric is a word or section of text that is traditionally written or printed in red ink for emphasis.

https://en.wikipedia.org/wiki/Rubric

This is stylized as docutils tells us to stylize it, since it is used for footnote headers (see end of https://docs.python.org/3/reference/lexical_analysis.html)

This is a rubric

Images & Figures#
Images#

An image:

https://source.unsplash.com/200x200/daily?cute+puppy

A clickable image:

https://source.unsplash.com/200x200/daily?cute+puppy https://source.unsplash.com/200x200/daily?cute+puppy

This is a lot of text to go along with a right-aligned image, that is helping make this content feel less linear. It is important to have such a body of text, since the image is meant to be “floated” to the right, which would interfere with the rest of the document otherwise.

Lorem ipsum dolor sit amet consectetur adipisicing elit. Blanditiis sapiente veritatis doloribus accusantium molestiae modi recusandae excepturi facere, corrupti expedita sit nihil temporibus eius sequi animi, illo libero labore fuga.

Lorem ipsum dolor sit amet consectetur adipisicing elit. Blanditiis sapiente veritatis doloribus accusantium molestiae modi recusandae excepturi facere, corrupti expedita sit nihil temporibus eius sequi animi, illo libero labore fuga.

https://source.unsplash.com/200x200/daily?cute+puppy

This is a lot of text to go along with a left-aligned image, that is helping make this content feel less linear. It is important to have such a body of text, since the image is meant to be “floated” to the right, which would interfere with the rest of the document otherwise.

Lorem ipsum dolor sit amet consectetur adipisicing elit. Blanditiis sapiente veritatis doloribus accusantium molestiae modi recusandae excepturi facere, corrupti expedita sit nihil temporibus eius sequi animi, illo libero labore fuga.

Lorem ipsum dolor sit amet consectetur adipisicing elit. Blanditiis sapiente veritatis doloribus accusantium molestiae modi recusandae excepturi facere, corrupti expedita sit nihil temporibus eius sequi animi, illo libero labore fuga.

Figures#
reStructuredText, the markup syntax

A figure is an image with a caption and/or a legend:#

re

Revised, revisited, based on ‘re’ module.

Structured

Structure-enhanced text, structuredtext.

Text

Well it is, isn’t it?

This paragraph is also part of the legend.

A figure directive with center alignment

https://source.unsplash.com/200x200/daily?cute+puppy

This caption should be centered.#

Lists#
Enumerated Lists#
  1. Arabic numerals.

    1. lower alpha)

      1. (lower roman)

        1. upper alpha.

          1. upper roman)

  2. Lists that don’t start at 1:

    1. Three

    2. Four

    1. C

    2. D

    1. iii

    2. iv

  3. List items may also be auto-enumerated.

Definition Lists#
Term

Definition

Termclassifier

Definition paragraph 1.

Definition paragraph 2.

Term

Definition

I have no clue why the definition list below is classified as a different style of definition list than the one above.

Is it the spaces in the term?

Maybe it was the multiple line paragraph in the line below that caused this?

Is it the paragraph above the list maybe?

I guess a lot of these lists don’t have leading paragraphs?

Is it everything all at once?

Who knows?!

Option Lists#

For listing command-line options:

-a

command-line option “a”

-b file

options can have arguments and long descriptions

--long

options can be long also

--input=file

long options can also have arguments

--very-long-option

The description can also start on the next line.

The description may contain multiple body elements, regardless of where it starts.

-x, -y, -z

Multiple options are an “option group”.

-v, --verbose

Commonly-seen: short & long options.

-1 file, --one=file, --two file

Multiple options with arguments.

/V

DOS/VMS-style options too

There must be at least two spaces between the option and the description.

Field list#
Address:

123 Example Street Example, EX Canada A1B 2C3

Organization:

humankind

Status:

This is a “work in progress”

Version:

1

Field name:

This is a generic bibliographic field.

Field name 2:

Generic bibliographic fields may contain multiple body elements.

Like this.

Glossary#

This is a glossary with definition terms for thing like Writing:

Documentation#

Provides users with the knowledge they need to use something.

Reading#

The process of taking information into ones mind through the use of eyes.

Writing#

The process of putting thoughts into a medium for other people to read.

Here’s another glossary, with more detail. The important bit here is that the contents of the definition are multi-paragraph.

Import Package#

A Python module which can contain other modules or recursively, other packages.

An import package is more commonly referred to with the single word “package”, but this guide will use the expanded term when more clarity is needed to prevent confusion with a Distribution Package which is also commonly called a “package”.

Package Index#

A repository of distributions with a web interface to automate package discovery and consumption.

Bullet Lists#
Simple#
  • A simple list.

  • There are no margins between list items.

  • Simple lists do not contain multiple paragraphs. That’s a complex list.

  • In the case of a nested list

    • There are no margins between elements

      • Still no margins

        • Still no margins

Complex#
  • A bullet list

    • Nested bullet list.

    • Nested item 2.

  • Item 2.

    Paragraph 2 of item 2.

    • Nested bullet list.

    • Nested item 2.

      • Third level.

      • Item 2.

    • Nested item 3.

  • inline literall

  • inline literall

  • inline literall

  • This item has multiple paragraphs.

    This item has multiple paragraphs.

  • This item has multiple paragraphs.

    This item has multiple paragraphs.

Second list level#
  • here is a list in a second-level section.

  • yahoo

  • yahoo

    • yahoo

    • here is an inner bullet oh

      • one more with an inline literally. yahoo

        heh heh. child. try to beat this embed:

         1from requests.exceptions import ConnectionError, HTTPError, RetryError
         2from sphinx.application import Sphinx
         3from sphinx.builders.dirhtml import DirectoryHTMLBuilder
         4from sphinx.errors import ExtensionError
         5
         6from . import edit_this_page, logo, pygment, short_link, toctree, translator, utils
         7
         8__version__ = "0.15.3rc1"
         9
        10
        11def update_config(app):
        
    • and another. yahoo

    • yahoo

    • hi

  • how about an admonition?

    Note

    This is a note nested in a list.

  • and hehe

But deeper down the rabbit hole#
  • I kept saying that, “deeper down the rabbit hole”. yahoo

    • I cackle at night yahoo.

  • I’m so lonely here in GZ guangzhou

  • A man of python destiny, hopes and dreams. yahoo

Hlists#
  • First item

  • Second item

  • Third item

  • Forth item

  • Fifth item

  • Sixths item

Hlist with images

  • https://source.unsplash.com/200x200/daily?cute+puppy

    This is a short caption for a figure.#

  • https://source.unsplash.com/200x200/daily?cute+puppy

    This is a long caption for a figure. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec porttitor dolor in odio posuere, vitae ornare libero mattis. In lobortis justo vestibulum nibh aliquet, non.#

Numbered List#
  1. One,

  2. Two.

  3. Three with long text. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed feugiat sagittis neque quis eleifend. Duis rutrum lectus sit amet mattis suscipit.

    1. Using bullets and letters. (A)

    1. Using bullets and letters. (B)

    1. Using bullets and letters. (C)

Mimicking ReadTheDocs’ PR previews

This is simulating how ReadTheDocs puts admonitions on top of previews.

Really Long Page Title because we should test sidebar wrapping#

This page basically exists to show-off the cool table of contents sidebar.

Heading 1#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 2#

Let’s make sure multiple permalinks work: one, two, three.

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 3#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 4#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 5#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 6#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 7#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 7.1#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 7.2#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 7.3#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 7.4#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 8#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 9#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 10#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 11#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 12#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 13#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 14#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 15 – this one is intentionally really long#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 16 – this one is also lots of words that would wrap content#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 17#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 18#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 19#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 20#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 21#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 22#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 23#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 24#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 25#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 26#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 27#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 28#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 29#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 30#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 31#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 32#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 33#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 34#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 35#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 36#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 37#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 38#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 39#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 40#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 41#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 42#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Heading 43#

Lorem ipsum dolor sit amet consectetur adipisicing elit. Itaque sit temporibus cupiditate in ducimus illum assumenda dolor, dignissimos laboriosam voluptate dolorem dolore eum repellendus minima, nisi sequi? Eveniet, dignissimos asperiores!

Structural Elements#

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec lorem neque, interdum in ipsum nec, finibus dictum velit. Ut eu efficitur arcu, id aliquam erat. In sit amet diam gravida, imperdiet tellus eu, gravida nisl. Praesent aliquet odio eget libero elementum, quis rhoncus tellus tincidunt. Suspendisse quis volutpat ipsum. Sed lobortis scelerisque tristique. Aenean condimentum risus tellus, quis accumsan ipsum laoreet ut. Integer porttitor maximus suscipit. Mauris in posuere sapien. Aliquam accumsan feugiat ligula, nec fringilla libero commodo sed. Proin et erat pharetra.


Etiam turpis ante, luctus sed velit tristique, finibus volutpat dui. Nam sagittis vel ante nec malesuada. Praesent dignissim mi nec ornare elementum. Nunc eu augue vel sem dignissim cursus sed et nulla. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Pellentesque dictum dui sem, non placerat tortor rhoncus in. Sed placerat nulla at rhoncus iaculis.

Document Section#

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed condimentum nulla vel neque venenatis, nec placerat lorem placerat. Cras purus eros, gravida vitae tincidunt id, vehicula nec nulla. Fusce aliquet auctor cursus. Phasellus ex neque, vestibulum non est vitae, viverra fringilla tortor. Donec vestibulum convallis justo, a faucibus lorem vulputate vel. Aliquam cursus odio eu felis sodales aliquet. Aliquam erat volutpat. Maecenas eget dictum mauris. Suspendisse arcu eros, condimentum eget risus sed, luctus efficitur arcu. Cras ut dictum mi. Nulla congue interdum lorem, semper semper enim commodo nec.

Document Subsection#

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam efficitur in eros et blandit. Nunc maximus, nisl at auctor vestibulum, justo ex sollicitudin ligula, id faucibus urna orci tristique nisl. Duis auctor rutrum orci, in ornare lacus condimentum quis. Quisque arcu velit, facilisis quis interdum ac, hendrerit auctor mauris. Curabitur urna nibh, porttitor at ante sit amet, vestibulum interdum dolor. Duis dictum elit orci, tincidunt imperdiet sem pellentesque et. In vehicula pellentesque varius. Phasellus a turpis sollicitudin, bibendum massa et, imperdiet neque. Integer quis sapien in magna rutrum bibendum. Integer cursus ex sed magna vehicula finibus. Proin tempus orci quis dolor tempus, nec condimentum odio vestibulum. Etiam efficitur sollicitudin libero, tincidunt volutpat ligula interdum sed.

Document Subsubsection#

Donec non rutrum lorem. Aenean sagittis metus at pharetra fringilla. Nunc sapien dolor, cursus sed nisi at, pretium tristique lectus. Sed pellentesque leo lectus, et convallis ipsum euismod a. Integer at leo vitae felis pretium aliquam fringilla quis odio. Sed pharetra enim accumsan feugiat pretium. Maecenas at pharetra tortor. Morbi semper eget mi vel finibus. Cras rutrum nulla eros, id feugiat arcu pellentesque ut. Sed finibus tortor ac nisi ultrices viverra. Duis feugiat malesuada sapien, at commodo ante porttitor ac. Curabitur posuere mauris mi, vel ornare orci scelerisque sit amet. Suspendisse nec fringilla dui.

Document Paragraph#

Pellentesque nec est in odio ultrices elementum. Vestibulum et hendrerit sapien, quis vulputate turpis. Suspendisse potenti. Curabitur tristique sit amet lectus non viverra. Phasellus rutrum dapibus turpis sed imperdiet. Mauris maximus viverra ante. Donec eu egestas mauris. Morbi vulputate tincidunt euismod. Integer vel porttitor neque. Donec at lacus suscipit, lacinia lectus vel, sagittis lectus.

Structural Elements 2#

Etiam turpis ante, luctus sed velit tristique, finibus volutpat dui. Nam sagittis vel ante nec malesuada. Praesent dignissim mi nec ornare elementum. Nunc eu augue vel sem dignissim cursus sed et nulla. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Pellentesque dictum dui sem, non placerat tortor rhoncus in. Sed placerat nulla at rhoncus iaculis.

Document Section#

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed condimentum nulla vel neque venenatis, nec placerat lorem placerat. Cras purus eros, gravida vitae tincidunt id, vehicula nec nulla. Fusce aliquet auctor cursus. Phasellus ex neque, vestibulum non est vitae, viverra fringilla tortor. Donec vestibulum convallis justo, a faucibus lorem vulputate vel. Aliquam cursus odio eu felis sodales aliquet. Aliquam erat volutpat. Maecenas eget dictum mauris. Suspendisse arcu eros, condimentum eget risus sed, luctus efficitur arcu. Cras ut dictum mi. Nulla congue interdum lorem, semper semper enim commodo nec.

Document Subsection#
https://source.unsplash.com/200x200/daily?cute+puppy

This is a caption for a figure. Text should wrap around the caption.#

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam efficitur in eros et blandit. Nunc maximus, nisl at auctor vestibulum, justo ex sollicitudin ligula, id faucibus urna orci tristique nisl. Duis auctor rutrum orci, in ornare lacus condimentum quis. Quisque arcu velit, facilisis quis interdum ac, hendrerit auctor mauris. Curabitur urna nibh, porttitor at ante sit amet, vestibulum interdum dolor. Duis dictum elit orci, tincidunt imperdiet sem pellentesque et. In vehicula pellentesque varius. Phasellus a turpis sollicitudin, bibendum massa et, imperdiet neque. Integer quis sapien in magna rutrum bibendum. Integer cursus ex sed magna vehicula finibus. Proin tempus orci quis dolor tempus, nec condimentum odio vestibulum. Etiam efficitur sollicitudin libero, tincidunt volutpat ligula interdum sed. Praesent congue sagittis nisl et suscipit. Vivamus sagittis risus et egestas commodo.Cras venenatis arcu in pharetra interdum. Donec quis metus porttitor tellus cursus lobortis. Quisque et orci magna. Fusce rhoncus mi mi, at vehicula massa rhoncus quis. Mauris augue leo, pretium eget molestie vitae, efficitur nec nulla. In hac habitasse platea dictumst. Sed sit amet imperdiet purus.

Tables#
Grid Tables#

Here’s a grid table followed by a simple table:

Header row, column 1 (header rows optional)

Header 2

Header 3

Header 4

body row 1, column 1

column 2

column 3

column 4

body row 2

Cells may span columns.

body row 3

Cells may span rows.

  • Table cells

  • contain

  • body elements.

body row 4

body row 5

Cells may also be empty: -->

Inputs

Output

A

B

A or B

False

False

False

True

False

True

False

True

True

True

True

True

Giant Tables#

Header 1

Header 2

Header 3

Header 1

Header 2

Header 3

Header 1

Header 2

Header 3

Header 1

Header 2

Header 3

body row 1

column 2

column 3

body row 1

column 2

column 3

body row 1

column 2

column 3

body row 1

column 2

column 3

body row 1

column 2

column 3

body row 1

column 2

column 3

body row 1

column 2

column 3

body row 1

column 2

column 3

body row 1

column 2

column 3

body row 1

column 2

column 3

body row 1

column 2

column 3

body row 1

column 2

column 3

body row 1

column 2

column 3

body row 1

column 2

column 3

body row 1

column 2

column 3

body row 1

column 2

column 3

Table containing code#

Version

Installing

Pradyun’s pip fork and installer

pip install "pip @ git+https://github.com/pradyunsg/pip#20.3.3" "installer @ git+https://github.com/pradyunsg/installer"

PyPI

pip install pip installer
List Tables#
List tables can have captions like this one.#

List table

Header 1

Header 2

Header 3 long. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sit amet mauris arcu.

Stub Row 1

Row 1

Column 2

Column 3 long. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sit amet mauris arcu.

Stub Row 2

Row 2

Column 2

Column 3 long. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sit amet mauris arcu.

Stub Row 3

Row 3

Column 2

Column 3 long. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam sit amet mauris arcu.

This is a list table with images in it.#
https://source.unsplash.com/200x200/daily?cute+puppy

This is a short caption for a figure.#

https://source.unsplash.com/200x200/daily?cute+puppy

This is a long caption for a figure. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec porttitor dolor in odio posuere, vitae ornare libero mattis. In lobortis justo vestibulum nibh aliquet, non.#

Typography#

This is quite important, for a website where the majority of the content is going to be prose.

Notice the font family being used for the prose, as well as the font family being used for the heading. Think about the spacing between the lines, as well as the spacing between various paragraphs. Also keep the font weight in mind, and consider if/how you want antialiasing and font-smoothing to work.

Multiple paragraphs are a common occurance, because you often need more than a single paragraph to describe a thing. The rest of this paragraph is gonna be the famous lorem-ipsum: Lorem ipsum dolor sit amet consectetur adipisicing elit. Accusamus, sunt voluptatum tenetur libero nulla esse veritatis accusantium earum commodi hic voluptatem officia culpa optio atque. Quaerat sed quibusdam ratione nam.

Headings#

This next bit will explore how the various headings look. Think about how the content separation should work, and how the various headings should interact with the main content.

Heading 3#
Heading 4#
Heading 5#
Heading 6#
Heading 2 with content#

Lorem ipsum dolor sit amet consectetur adipisicing elit.

Accusamus, sunt voluptatum tenetur libero nulla esse veritatis accusantium earum commodi hic voluptatem officia culpa optio atque. Quaerat sed quibusdam ratione nam.

Heading 3 with content#

Lorem ipsum dolor sit amet consectetur adipisicing elit.

Accusamus, sunt voluptatum tenetur libero nulla esse veritatis accusantium earum commodi hic voluptatem officia culpa optio atque. Quaerat sed quibusdam ratione nam.

Heading 4 with content#

Lorem ipsum dolor sit amet consectetur adipisicing elit.

Accusamus, sunt voluptatum tenetur libero nulla esse veritatis accusantium earum commodi hic voluptatem officia culpa optio atque. Quaerat sed quibusdam ratione nam.

Heading 5 with content#

Lorem ipsum dolor sit amet consectetur adipisicing elit.

Accusamus, sunt voluptatum tenetur libero nulla esse veritatis accusantium earum commodi hic voluptatem officia culpa optio atque. Quaerat sed quibusdam ratione nam.

Heading 6 with content#

Lorem ipsum dolor sit amet consectetur adipisicing elit.

Accusamus, sunt voluptatum tenetur libero nulla esse veritatis accusantium earum commodi hic voluptatem officia culpa optio atque. Quaerat sed quibusdam ratione nam.

PyData Library Styles#

This theme has built-in support and special styling for several major visualization libraries in the PyData ecosystem. This ensures that the images and output generated by these libraries looks good for both light and dark modes. Below are examples of each that we use as a benchmark for reference.

Pandas#
[1]:
import string

import numpy as np
import pandas as pd

rng = np.random.default_rng(seed=15485863)
data = rng.standard_normal((100, 26))
df = pd.DataFrame(data, columns=list(string.ascii_lowercase))
df
[1]:
a b c d e f g h i j ... q r s t u v w x y z
0 1.064993 -0.835020 1.366174 0.568616 1.062697 -1.651245 -0.591375 -0.591991 1.674089 -0.394414 ... -0.378030 1.085214 1.248008 0.847716 -2.009990 2.244824 -1.283696 -0.292551 0.049112 -0.061071
1 0.175635 -1.029685 0.608107 0.965867 -0.296914 1.511633 0.551440 -2.093487 -0.363041 -0.842695 ... -1.184430 -0.399641 1.149865 0.801796 -0.745362 -0.914683 -0.332012 0.401275 0.167847 -0.674393
2 -1.627893 -1.132004 -0.520023 1.433833 0.499023 0.609095 -1.440980 1.263088 0.282536 0.788140 ... 1.330569 0.729197 0.172394 -0.311494 0.428182 0.059321 -1.093189 0.006239 0.011220 0.882787
3 0.104182 -0.119232 1.426785 0.744443 0.143632 0.342422 0.591960 0.653388 -0.221575 -0.305475 ... -0.117631 -0.705664 -0.041554 0.365820 1.054793 0.280238 -0.302220 -1.105060 -1.344887 -0.186901
4 0.404584 2.172183 -0.498760 -0.537456 -0.174159 -0.421315 -0.461453 -0.456776 -0.811049 0.470270 ... -0.970498 -0.424077 0.017638 0.764396 -0.055982 0.369587 0.566487 -0.709265 0.041741 1.427378
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
95 0.730475 0.638252 -1.327878 0.402921 0.300998 -2.103696 0.177649 0.226409 0.391869 -2.687118 ... -1.019080 0.449696 0.603108 1.325479 -0.354819 -0.122947 -0.555267 -0.319204 1.543449 1.219027
96 -1.563950 -0.496752 -0.135757 1.468133 -0.255600 -0.551909 1.069691 0.656629 -1.674868 -0.192483 ... -0.197569 1.751076 0.536964 0.748986 -0.631070 -0.719372 0.053761 1.282812 1.842575 -0.250804
97 0.116719 -0.877987 -0.173280 -0.226328 0.514574 1.021983 -0.869675 -1.426881 1.028629 -0.403335 ... -0.328254 1.291479 0.540613 0.876653 -0.129568 -0.756255 0.614621 0.747284 -0.416865 -1.230327
98 0.744639 1.312439 1.144209 -0.749547 0.111659 -0.153397 -0.230551 -1.585670 -0.279647 0.482702 ... 1.193722 -0.229955 0.201680 -0.128116 -1.278398 -0.280277 0.109736 -1.402238 1.064833 -2.022736
99 -2.392240 -1.005938 -0.227638 -1.720300 -0.297324 -0.320110 -0.338110 -0.089035 -0.009806 1.585349 ... 0.717063 0.589935 0.718870 1.777263 -0.072043 -0.490852 0.535639 -0.009055 0.045785 0.322065

100 rows × 26 columns

Matplotlib#
[2]:
import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.scatter(df["a"], df["b"], c=df["b"], s=3)
[2]:
<matplotlib.collections.PathCollection at 0x7f3f14190880>
_images/examples_pydata_3_1.png
[3]:
rng = np.random.default_rng()
data = rng.standard_normal((3, 100))
fig, ax = plt.subplots()
ax.scatter(data[0], data[1], c=data[2], s=3)
[3]:
<matplotlib.collections.PathCollection at 0x7f3f1205b370>
_images/examples_pydata_4_1.png
Plotly#

The HTML below shouldn’t display, but it uses RequireJS to make sure that all works as expected. If the widgets don’t show up, RequireJS may be broken.

[4]:
import plotly.io as pio
import plotly.express as px
import plotly.offline as py

pio.renderers.default = "notebook"

df = px.data.iris()
fig = px.scatter(df, x="sepal_width", y="sepal_length", color="species", size="sepal_length")
fig
Xarray#

Here we demonstrate xarray to ensure that it shows up properly.

[5]:
import xarray as xr
data = xr.DataArray(
        np.random.randn(2, 3),
        dims=("x", "y"),
        coords={"x": [10, 20]}, attrs={"foo": "bar"}
      )
data
[5]:
<xarray.DataArray (x: 2, y: 3)> Size: 48B
array([[0.75874197, 0.15375513, 0.29742673],
       [2.06725715, 0.81590978, 1.73315064]])
Coordinates:
  * x        (x) int64 16B 10 20
Dimensions without coordinates: y
Attributes:
    foo:      bar
ipyleaflet#

ipyleaflet is a Jupyter/Leaflet bridge enabling interactive maps in the Jupyter notebook environment. this demonstrate how you can integrate maps in your documentation.

[6]:
from ipyleaflet import Map, basemaps

# display a map centered on France
m = Map(basemap=basemaps.Esri.WorldImagery,  zoom=5, center=[46.21, 2.21])
m
[6]:

Execution Libraries#

Many execution libraries can be used to display the output of IPyhton cells. We used MySTnb to parse and display the outputs presented in PyData Library Styles. In this section we’ll show alternatives that runs code for you using a Jupyter like kernel.

Jupyterlite#

Warning

The jupyterLite lib is not yet providing a handle to switch from light to dark theme. If you consider using it in your documentation you should also enforce the light theme to your users. Follow jupyterlite/jupyterlite-sphinx#69 for more information.

jupyterlite-sphinx brings the power of JupyterLite to your Sphinx documentation. It makes a full JupyterLite deployment in your docs and provide some utilities for using that deployment easily.

This section demonstrate how it displays in a pydata-sphinx-theme context:

Try Replite!
jupyter-sphinx#

Another common library is jupyter-sphinx. This section demonstrates a subset of functionality to make sure it behaves as expected.

import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng()
data = rng.standard_normal((3, 100))
fig, ax = plt.subplots()
ax.scatter(data[0], data[1], c=data[2], s=3)
<matplotlib.collections.PathCollection at 0x7f5ac5d6b340>
_images/execution_0_1.png

Test of no sidebar#

This page shows off what the documentation looks like when you explicitly tell Sphinx not to include any sidebars via the following configuration:

html_sidebars = {
  "path/to/page": [],
}
html_theme_options = {
    "secondary_sidebar_items": {
        "path/to/page": [],
    },
}

Both the primary and secondary sidebars should be entirely gone, and the main content should expand slightly to make up the extra space.

Test of persistent search field#

There should also be a persistent (non-hidden) search field in the primary sidebar of this page, and if you use the keyboard shortcut it should focus the persistent field, not overlay the hidden one.

Test of in-page TOC with no right sidebar#

This page tests that the local contents directive looks okay.

Attention

We do not recommend using this directive on pages that use this theme because PyData Theme provides an in-page table of contents in the right sidebar by default.

If you do choose to use an inline, in-page table of contents, we recommend that you turn off the right sidebar as follows.

Add a local table of contents (in-page)#

Add the local table of contents directive near the top of your .rst page:

.. contents:: Page contents
    :local:

This directive will generate a table of contents for the section where this was added, as shown on this page.

Turn off the right sidebar for a single page#

On the very top line of your .rst file, insert the following line:

:html_theme.sidebar_secondary.remove: true

This will render the page without the right sidebar, also known as the secondary sidebar, which contains the table of contents for that page.

Be aware that if you remove the sidebar you may also remove the “Edit on …” and “Show source” links for that page, since by default those are configured for the right sidebar.

Section to show off pages with many sub pages#

To create an additional level of nesting in the sidebar, construct a nested toctree:

Sub page 1#

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec lorem neque, interdum in ipsum nec, finibus dictum velit. Ut eu efficitur arcu, id aliquam erat. In sit amet diam gravida, imperdiet tellus eu, gravida nisl. Praesent aliquet odio eget libero elementum, quis rhoncus tellus tincidunt. Suspendisse quis volutpat ipsum. Sed lobortis scelerisque tristique. Aenean condimentum risus tellus, quis accumsan ipsum laoreet ut. Integer porttitor maximus suscipit. Mauris in posuere sapien. Aliquam accumsan feugiat ligula, nec fringilla libero commodo sed. Proin et erat pharetra.

Sub page 2#

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec lorem neque, interdum in ipsum nec, finibus dictum velit. Ut eu efficitur arcu, id aliquam erat. In sit amet diam gravida, imperdiet tellus eu, gravida nisl. Praesent aliquet odio eget libero elementum, quis rhoncus tellus tincidunt. Suspendisse quis volutpat ipsum. Sed lobortis scelerisque tristique. Aenean condimentum risus tellus, quis accumsan ipsum laoreet ut. Integer porttitor maximus suscipit. Mauris in posuere sapien. Aliquam accumsan feugiat ligula, nec fringilla libero commodo sed. Proin et erat pharetra.

Section with sub sub pages#

To create an additional level of nesting in the sidebar, construct a nested toctree:

Sub sub page 1#

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec lorem neque, interdum in ipsum nec, finibus dictum velit. Ut eu efficitur arcu, id aliquam erat. In sit amet diam gravida, imperdiet tellus eu, gravida nisl. Praesent aliquet odio eget libero elementum, quis rhoncus tellus tincidunt. Suspendisse quis volutpat ipsum. Sed lobortis scelerisque tristique. Aenean condimentum risus tellus, quis accumsan ipsum laoreet ut. Integer porttitor maximus suscipit. Mauris in posuere sapien. Aliquam accumsan feugiat ligula, nec fringilla libero commodo sed. Proin et erat pharetra.

Sub sub sub page 1#

Test.

Sub sub page 2#

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec lorem neque, interdum in ipsum nec, finibus dictum velit. Ut eu efficitur arcu, id aliquam erat. In sit amet diam gravida, imperdiet tellus eu, gravida nisl. Praesent aliquet odio eget libero elementum, quis rhoncus tellus tincidunt. Suspendisse quis volutpat ipsum. Sed lobortis scelerisque tristique. Aenean condimentum risus tellus, quis accumsan ipsum laoreet ut. Integer porttitor maximus suscipit. Mauris in posuere sapien. Aliquam accumsan feugiat ligula, nec fringilla libero commodo sed. Proin et erat pharetra.

Sub sub page 3#

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec lorem neque, interdum in ipsum nec, finibus dictum velit. Ut eu efficitur arcu, id aliquam erat. In sit amet diam gravida, imperdiet tellus eu, gravida nisl. Praesent aliquet odio eget libero elementum, quis rhoncus tellus tincidunt. Suspendisse quis volutpat ipsum. Sed lobortis scelerisque tristique. Aenean condimentum risus tellus, quis accumsan ipsum laoreet ut. Integer porttitor maximus suscipit. Mauris in posuere sapien. Aliquam accumsan feugiat ligula, nec fringilla libero commodo sed. Proin et erat pharetra.

Top-level headers and the TOC#

Your right table of contents will behave slightly differently depending on whether your page has one top-level header, or multiple top-level headers. See below for more information.

An example with multiple top-level headers#

If a page has multiple top-level headers on it, then the in-page Table of Contents will show each top-level header. On this page, there are multiple top-level headers. As a result, the top-level headers all appear in the right Table of Contents. Here’s an example of a page structure with multiple top-level headers:

My first header
===============

My sub-header
-------------

My second header
================

My second sub-header
--------------------
And here’s a second-level header#

Notice how it is nested underneath “Top-level header 2” in the TOC.

An example with a single top-level header#

If the page only has a single top-level header, it is assumed to be the page title, and only the headers underneath the top-level header will be used for the right Table of Contents.

On most pages in this documentation, only a single top-level header is used. For example, they have a page structure like:

My title
========

My header
---------

My second header
----------------

API#

The content of the exposed pydata_sphinx_theme API.

API Reference#

This page contains auto-generated API reference documentation [1].

pydata_sphinx_theme#

Bootstrap-based sphinx theme from the PyData community.

Submodules#
pydata_sphinx_theme.edit_this_page#

Create an “edit this page” url compatible with bitbucket, gitlab and github.

Module Contents#
Functions#

setup_edit_url(app, pagename, templatename, context, ...)

Add a function that jinja can access for returning the edit URL of a page.

pydata_sphinx_theme.edit_this_page.setup_edit_url(app, pagename, templatename, context, doctree)[source]#

Add a function that jinja can access for returning the edit URL of a page.

Parameters:
  • app (sphinx.application.Sphinx)

  • pagename (str)

  • templatename (str)

Return type:

None

pydata_sphinx_theme.pygment#

Handle pygment css.

inspired by the Furo theme pradyunsg/furo

Module Contents#
Functions#

_get_styles(formatter, prefix)

Get styles out of a formatter, where everything has the correct prefix.

get_pygments_stylesheet(light_style, dark_style)

Generate the theme-specific pygments.css.

overwrite_pygments_css(app[, exception])

Overwrite pygments.css to allow dynamic light/dark switching.

pydata_sphinx_theme.pygment._get_styles(formatter, prefix)[source]#

Get styles out of a formatter, where everything has the correct prefix.

Parameters:
  • formatter (pygments.formatters.HtmlFormatter)

  • prefix (str)

Return type:

None

pydata_sphinx_theme.pygment.get_pygments_stylesheet(light_style, dark_style)[source]#

Generate the theme-specific pygments.css.

There is no way to tell Sphinx how the theme handles modes.

Parameters:
  • light_style (str)

  • dark_style (str)

Return type:

str

pydata_sphinx_theme.pygment.overwrite_pygments_css(app, exception=None)[source]#

Overwrite pygments.css to allow dynamic light/dark switching.

Sphinx natively supports config variables pygments_style and pygments_dark_style. However, quoting from www.sphinx-doc.org/en/master/development/theming.html#creating-themes

The pygments_dark_style setting […is used] when the CSS media query (prefers-color-scheme: dark) evaluates to true.

This does not allow for dynamic switching by the user, so at build time we overwrite the pygment.css file so that it embeds 2 versions:

  • the light theme prefixed with “[data-theme=”light”]”

  • the dark theme prefixed with “[data-theme=”dark”]”

Fallbacks are defined in this function in case the user-requested (or our theme-specified) pygments theme is not available.

Parameters:

app (sphinx.application.Sphinx)

pydata_sphinx_theme.toctree#

Methods to build the toctree used in the html pages.

Module Contents#
Functions#

_get_ancestor_pagename(app, pagename, startdepth)

Get the name of pagename's ancestor that is rooted startdepth levels below the global root.

add_collapse_checkboxes(soup)

Add checkboxes to collapse children in a toctree.

add_inline_math(node)

Render a node with HTML tags that activate MathJax processing.

add_toctree_functions(app, pagename, templatename, ...)

Add functions so Jinja templates can add toctree objects.

get_nonroot_toctree(app, pagename, ancestorname, ...)

Get the partial TocTree (rooted at ancestorname) that dominates pagename.

pydata_sphinx_theme.toctree._get_ancestor_pagename(app, pagename, startdepth)[source]#

Get the name of pagename’s ancestor that is rooted startdepth levels below the global root.

Parameters:
  • app (sphinx.application.Sphinx)

  • pagename (str)

  • startdepth (int)

Return type:

str

pydata_sphinx_theme.toctree.add_collapse_checkboxes(soup)[source]#

Add checkboxes to collapse children in a toctree.

Parameters:

soup (bs4.BeautifulSoup)

Return type:

None

pydata_sphinx_theme.toctree.add_inline_math(node)[source]#

Render a node with HTML tags that activate MathJax processing.

This is meant for use with rendering section titles with math in them, because math outputs are ignored by pydata-sphinx-theme’s header.

related to the behaviour of a normal math node from: sphinx-doc/sphinx

Parameters:

node (docutils.nodes.Node)

Return type:

str

pydata_sphinx_theme.toctree.add_toctree_functions(app, pagename, templatename, context, doctree)[source]#

Add functions so Jinja templates can add toctree objects.

Parameters:
  • app (sphinx.application.Sphinx)

  • pagename (str)

  • templatename (str)

Return type:

None

pydata_sphinx_theme.toctree.get_nonroot_toctree(app, pagename, ancestorname, toctree, **kwargs)[source]#

Get the partial TocTree (rooted at ancestorname) that dominates pagename.

Parameters: app : Sphinx app. pagename : Name of the current page (as Sphinx knows it; i.e., its relative path from the documentation root). ancestorname : Name of a page that dominates pagename and that will serve as the root of the TocTree fragment. toctree : A Sphinx TocTree object. Since this is always needed when finding the ancestorname (see _get_ancestor_pagename), it’s more efficient to pass it here to re-use it. kwargs : passed to the Sphinx toctree template function.

This is similar to context[“toctree”](**kwargs) (AKA toctree(**kwargs) within a Jinja template), or TocTree.get_toctree_for(), which always uses the “root” doctree (i.e., doctree = self.env.get_doctree(self.env.config.root_doc)).

Parameters:
  • app (sphinx.application.Sphinx)

  • pagename (str)

  • ancestorname (str)

pydata_sphinx_theme.translator#

A custom Sphinx HTML Translator for Bootstrap layout.

Module Contents#
Classes#

BootstrapHTML5TranslatorMixin

Mixin HTML Translator for a Bootstrap-ified Sphinx layout.

Functions#

setup_translators(app)

Add bootstrap HTML functionality if we are using an HTML translator.

Attributes#

logger

class pydata_sphinx_theme.translator.BootstrapHTML5TranslatorMixin(*args, **kwds)[source]#

Mixin HTML Translator for a Bootstrap-ified Sphinx layout.

Only a couple of functions have been overridden to produce valid HTML to be directly styled with Bootstrap, and fulfill acessibility best practices.

starttag(*args, **kwargs)[source]#

Perform small modifications to tags.

  • ensure aria-level is set for any tag with heading role

  • ensure <pre> tags have tabindex=”0”.

visit_literal_block(node)[source]#

Modify literal blocks.

  • add tabindex=”0” to <pre> tags within the HTML tree of the literal block

visit_table(node)[source]#

Custom visit table method.

Copy of sphinx source to not add ‘docutils’ and ‘align-default’ classes but add ‘table’ class.

pydata_sphinx_theme.translator.setup_translators(app)[source]#

Add bootstrap HTML functionality if we are using an HTML translator.

This re-uses the pre-existing Sphinx translator and adds extra functionality defined in BootstrapHTML5TranslatorMixin. This way we can retain the original translator’s behavior and configuration, and _only_ add the extra bootstrap rules. If we don’t detect an HTML-based translator, then we do nothing.

Parameters:

app (sphinx.application.Sphinx)

pydata_sphinx_theme.translator.logger[source]#
pydata_sphinx_theme.utils#

General helpers for the management of config parameters.

Module Contents#
Functions#

_get_matching_sidebar_items(pagename, sidebars)

Get the matching sidebar templates to render for the given pagename.

_has_wildcard(pattern)

Check whether the pattern contains a wildcard.

_update_and_remove_templates(app, context, templates, ...)

Update templates to include html suffix if needed; remove templates which render empty.

config_provided_by_user(app, key)

Check if the user has manually provided the config.

escape_ansi(string)

Helper function to remove ansi coloring from sphinx warnings.

get_theme_options_dict(app)

Return theme options for the application w/ a fallback if they don't exist.

maybe_warn(app, msg, *args, **kwargs)

Wraps the Sphinx logger to allow warning suppression.

set_secondary_sidebar_items(app, pagename, ...)

Set the secondary sidebar items to render for the given pagename.

traverse_or_findall(node, condition, **kwargs)

Triage node.traverse (docutils <0.18.1) vs node.findall.

Attributes#

SPHINX_LOGGER

pydata_sphinx_theme.utils._get_matching_sidebar_items(pagename, sidebars)[source]#

Get the matching sidebar templates to render for the given pagename.

If a page matches more than one pattern, a warning is emitted, and the templates for the last matching pattern are used.

This function was adapted from sphinx.builders.html.StandaloneHTMLBuilder.add_sidebars.

Parameters:
  • pagename (str)

  • sidebars (Dict[str, List[str]])

Return type:

List[str]

pydata_sphinx_theme.utils._has_wildcard(pattern)[source]#

Check whether the pattern contains a wildcard.

Taken from sphinx.builders.StandaloneHTMLBuilder.add_sidebars.

Parameters:

pattern (str)

Return type:

bool

pydata_sphinx_theme.utils._update_and_remove_templates(app, context, templates, section, templates_skip_empty_check=None)[source]#

Update templates to include html suffix if needed; remove templates which render empty.

Parameters:
  • app (sphinx.application.Sphinx) – Sphinx application passed to the html page context

  • context (Dict[str, Any]) – The html page context; dictionary of values passed to the templating engine

  • templates (Union[List, str]) – A list of template names, or a string of comma separated template names

  • section (str) – Name of the template section where the templates are to be rendered. Valid section names include any of the sphinx or html_theme_options that take templates or lists of templates as arguments, for example: theme_navbar_start, theme_primary_sidebar_end, theme_secondary_sidebar_items, sidebars, etc. For a complete list of valid section names, see the source for pydata_sphinx_theme.update_and_remove_templates() and pydata_sphinx_theme.utils.set_secondary_sidebar_items(), both of which call this function.

  • templates_skip_empty_check (Optional[List[str]]) – Names of any templates which should never be removed from the list of filtered templates returned by this function. These templates aren’t checked if they render empty, which can save time if the template is slow to render.

Returns:

A list of template names (including ‘.html’ suffix) to render into the section

Return type:

List[str]

pydata_sphinx_theme.utils.config_provided_by_user(app, key)[source]#

Check if the user has manually provided the config.

Parameters:
  • app (sphinx.application.Sphinx)

  • key (str)

Return type:

bool

pydata_sphinx_theme.utils.escape_ansi(string)[source]#

Helper function to remove ansi coloring from sphinx warnings.

Parameters:

string (str)

Return type:

str

pydata_sphinx_theme.utils.get_theme_options_dict(app)[source]#

Return theme options for the application w/ a fallback if they don’t exist.

The “top-level” mapping (the one we should usually check first, and modify if desired) is app.builder.theme_options. It is created by Sphinx as a copy of app.config.html_theme_options (containing user-configs from their conf.py); sometimes that copy never occurs though which is why we check both.

Parameters:

app (sphinx.application.Sphinx)

Return type:

Dict[str, Any]

pydata_sphinx_theme.utils.maybe_warn(app, msg, *args, **kwargs)[source]#

Wraps the Sphinx logger to allow warning suppression.

Parameters:

app (sphinx.application.Sphinx)

pydata_sphinx_theme.utils.set_secondary_sidebar_items(app, pagename, templatename, context, doctree)[source]#

Set the secondary sidebar items to render for the given pagename.

Parameters:
  • app (sphinx.application.Sphinx)

  • pagename (str)

  • templatename (str)

Return type:

None

pydata_sphinx_theme.utils.traverse_or_findall(node, condition, **kwargs)[source]#

Triage node.traverse (docutils <0.18.1) vs node.findall.

TODO: This check can be removed when the minimum supported docutils version for numpydoc is docutils>=0.18.1.

Parameters:
  • node (docutils.nodes.Node)

  • condition (Union[Callable, type])

Return type:

Iterable[docutils.nodes.Node]

pydata_sphinx_theme.utils.SPHINX_LOGGER[source]#
Package Contents#
Functions#

_fix_canonical_url(app, pagename, templatename, ...)

Fix the canonical URL when using the dirhtml builder.

setup(app)

Setup the Sphinx application.

update_and_remove_templates(app, pagename, ...)

Update template names and assets for page build.

update_config(app)

Update config with new default values and handle deprecated keys.

Attributes#

__version__

pydata_sphinx_theme._fix_canonical_url(app, pagename, templatename, context, doctree)[source]#

Fix the canonical URL when using the dirhtml builder.

Sphinx builds a canonical URL if html_baseurl config is set. However, it builds a URL ending with “.html” when using the dirhtml builder, which is incorrect. Detect this and generate the correct URL for each page.

Workaround for sphinx-doc/sphinx#9730; can be removed when that is fixed, released, and available in our minimum supported Sphinx version.

Parameters:
  • app (sphinx.application.Sphinx)

  • pagename (str)

  • templatename (str)

  • context (dict)

Return type:

None

pydata_sphinx_theme.setup(app)[source]#

Setup the Sphinx application.

Parameters:

app (sphinx.application.Sphinx)

Return type:

Dict[str, str]

pydata_sphinx_theme.update_and_remove_templates(app, pagename, templatename, context, doctree)[source]#

Update template names and assets for page build.

Parameters:
  • app (sphinx.application.Sphinx)

  • pagename (str)

  • templatename (str)

Return type:

None

pydata_sphinx_theme.update_config(app)[source]#

Update config with new default values and handle deprecated keys.

pydata_sphinx_theme.__version__ = '0.15.3rc1'[source]#