Skip to main content

Automatically generate tabbed code blocks for multiple Python versions in mkdocs, markdown and Sphinx

Project description

AutoPyTabs

Tooling to automatically generate tabbed code examples for different Python versions in mkdocs or Sphinx based documentations, or a plain markdown workflow, making use of the pymdown "tabbed" markdown extension for markdown, and sphinx{design} tabs for Sphinx.

Motivation

Writing and maintaining documentation can be tedious, especially the task of including code snippets for different versions of Python. AutoPyTabs aims to solve this problem by automatically generating those "versioned snippets" at build-time, which means there's only one file to maintain, and to be checked into VCS.

Table of contents

  1. Usage with mkdocs / markdown
    1. Configuration
    2. Examples
    3. Selectively disable
    4. Compatibility with pymdownx.snippets
  2. Usage with Sphinx
    1. Configuration
    2. Directives
    3. Examples
    4. Compatibility with other extensions

Installation

For mkdocs: pip install auto-pytabs[mkdocs] For markdown: pip install auto-pytabs[markdown] For sphinx: pip install auto-pytabs[sphinx]

Usage with mkdocs / markdown

Configuration

Mkdocs plugin

site_name: My Docs
markdown_extensions:
  - pymdownx.tabbed:
plugins:
  - auto_pytabs:
      min_version: "3.7"  # optional
      max_version: "3.11" # optional
      tab_title_template: "Python {min_version}+"  # optional
      no_cache: false  # optional

Markdown extension

import markdown

md = markdown.Markdown(
    extensions=["auto_pytabs"],
    extension_configs={
        "auto_pytabs": {
            "min_version": "3.7",  # optional
            "max_version": "3.11",  # optional
            "tab_title_template": "Python {min_version}+",  # optional
            "no_cache": False,  # optional
        }
    },
)

Mkdocs plugins vs markdown extension

AutoPyTabs ships as both a markdown extension and an mkdocs plugin, both of which can be used in mkdocs. The only difference between them is that the mkdocs plugin performs automatic cache-eviction of unused files. This is not easily possible with a markdown extension since it does not have a clearly defined build phase with which an extension could interact, meaning an extension does not know when the build is "done", and therefore also not if a cache file is truly unused.

If you are using mkdocs, the mkdocs plugin is recommended. If you have caching disabled, there will be no difference either way.

Examples

Input

```python
from typing import Optional, Dict

def foo(bar: Optional[str]) -> Dict[str, str]:
    ...
```

Equivalent markdown

=== "Python 3.7+"
    ```python
    from typing import Optional, Dict

    def foo(bar: Optional[str]) -> Dict[str, str]:
        ...
    ```

=== "Python 3.9+"
    ```python
    from typing import Optional
    
    
    def foo(bar: Optional[str]) -> dict[str, str]:
        ...
    ```

==== "Python 3.10+"
    ```python
    def foo(bar: str | None) -> dict[str, str]:
        ...
    ```

Nested blocks

Nested tabs are supported as well:

Input

=== "Level 1-1"

    === "Level 2-1"

        ```python
        from typing import List
        x: List[str]
        ```

    === "Level 2-2"
    
        Hello, world!

=== "Level 1-2"

    Goodbye, world!

Equivalent markdown

=== "Level 1-1"

    === "Level 2-1"

        === "Python 3.7+"
            ```python
            from typing import List
            x: List[str]
            ```
        
        === "Python 3.9+"
            ```python
            x: list[str]
            ```

    === "Level 2-2"

        Goodbye, world!

=== "Level 1-2"
    Hello, world!
    

Selectively disable

You can disable conversion for a single code block:

<!-- autopytabs: disable-block -->
```python
from typing import Set, Optional

def bar(baz: Optional[str]) -> Set[str]:
    ...
```

Or for whole sections / files

<!-- autopytabs: disable -->
everything after this will be ignored
<!-- autopytabs: enable -->
re-enables conversion again

Compatibility with pymdownx.snippets

If the pymdownx.snippets extension is used, make sure that it runs before AutoPyTab

Usage with Sphinx

AutPyTabs provides a Sphinx extension auto_pytabs.sphinx_ext, enabling its functionality for the .. code-block and .. literalinclude directives.

Configuration

extensions = ["auto_pytabs.sphinx_ext", "sphinx_design"]

auto_pytabs_min_version = (3, 7)  # optional
auto_pytabs_max_version = (3, 11)  # optional
auto_pytabs_tab_title_template = "Python {min_version}+"  # optional 
auto_pytabs_no_cache = True  # disabled caching

Examples

Input

.. code-block:: python

   from typing import Optional, Dict
   
   def foo(bar: Optional[str]) -> Dict[str, str]:
       ...

Equivalent ReST

.. tab-set::

   .. tab-item:: Python 3.7+
   
       .. code-block:: python
       
          from typing import Optional, Dict
      
          def foo(bar: Optional[str]) -> Dict[str, str]:
              ...

   .. tab-item:: Python 3.9+
   
      .. code-block:: python
      
          from typing import Optional
          
          
          def foo(bar: Optional[str]) -> dict[str, str]:
              ...

   .. tab-item:: Python 3.10+
   
      .. code-block:: python
      
          def foo(bar: str | None) -> dict[str, str]:
              ...

Directives

AutoPyTabs overrides the built-in code-block and literal-include directives, extending them with auto-upgrade and tabbing functionality, which means no special directives, and therefore changes to existing documents are needed.

Additionally, a :no-upgrade: option is added to the directives, which can be used to selectively fall back the default behaviour.

Two new directives are provided as well:

  • .. pytabs-code-block::
  • .. pytabs-literalinclude::

which by default act exactly like .. code-block and .. literalinclude respectively, and are mainly to provide AutoPyTab's functionality in compatibility mode.

Compatibility mode

If you don't want the default behaviour of directive overrides, and instead wish to use the .. pytabs- directives manually (e.g. because of compatibility issues with other extensions or because you only want to apply it to select code blocks) you can make use AutoPyTabs' compatibility mode. To enable it, simply use the auto_pytabs.sphinx_ext_compat extension instead of auto_pytabs.sphinx_ext. Now, only content within .. pytabs- directives will be upgraded.

Compatibility with other extensions

Normally the directive overrides don't cause any problems and are very convenient, since no changes to existing documents have to be made. However, if other extensions are included, which themselves override one of those directives, one of them will inadvertently override the other, depending on the order they're defined in extensions.

To combat this, you can use the compatibility mode extension instead, which only includes the new directives.

If you control the conflicting overrides, you can alternatively inherit from auto_py_tabs.sphinx_ext.CodeBlockOverride and auto_py_tabs.sphinx_ext.LiteralIncludeOverride instead of sphinx.directives.code.CodeBlock and sphinx.directives.code.LiteralInclude respectively.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

auto_pytabs-0.1.2.tar.gz (12.7 kB view hashes)

Uploaded Source

Built Distribution

auto_pytabs-0.1.2-py3-none-any.whl (11.2 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page