{"id":16807544,"url":"https://github.com/provinzkraut/autopytabs","last_synced_at":"2025-03-22T02:31:39.418Z","repository":{"id":65559780,"uuid":"573009565","full_name":"provinzkraut/AutoPyTabs","owner":"provinzkraut","description":"Automatically generate code examples for different Python versions in mkdocs or Sphinx based documentations","archived":false,"fork":false,"pushed_at":"2024-08-18T13:02:03.000Z","size":253,"stargazers_count":12,"open_issues_count":2,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-17T16:12:28.770Z","etag":null,"topics":["documentation","markdown","markdown-extension","mkdocs","mkdocs-plugin","python","sphinx","sphinx-extension"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/provinzkraut.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-12-01T14:04:03.000Z","updated_at":"2025-03-06T20:49:21.000Z","dependencies_parsed_at":"2024-08-18T13:06:13.737Z","dependency_job_id":null,"html_url":"https://github.com/provinzkraut/AutoPyTabs","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/provinzkraut%2FAutoPyTabs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/provinzkraut%2FAutoPyTabs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/provinzkraut%2FAutoPyTabs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/provinzkraut%2FAutoPyTabs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/provinzkraut","download_url":"https://codeload.github.com/provinzkraut/AutoPyTabs/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244898185,"owners_count":20528331,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["documentation","markdown","markdown-extension","mkdocs","mkdocs-plugin","python","sphinx","sphinx-extension"],"created_at":"2024-10-13T09:54:04.983Z","updated_at":"2025-03-22T02:31:39.100Z","avatar_url":"https://github.com/provinzkraut.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# AutoPyTabs\n\nAutomatically generate code examples for different Python versions in\n[mkdocs](https://www.mkdocs.org) or [Sphinx](https://www.sphinx-doc.org) based documentations, or a plain\n[markdown](https://python-markdown.github.io/) workflow, making use of the\n[pymdown \"tabbed\"](https://facelessuser.github.io/pymdown-extensions/extensions/tabbed/) markdown extension for markdown,\nand [sphinx{design} tabs](https://sphinx-design.readthedocs.io/en/latest/tabs.html) for Sphinx.\n\n## Rationale\n\n### The problem\n\nPython project documentation typically include code examples. Given that most of the time, a project will support\nmultiple versions of Python, it would be ideal to showcase the adjustments that can or need to be made for different\nPython versions. This can be achieved by including several versions of the example code, conveniently displayed using\nthe [pymdown \"tabbed\"](https://facelessuser.github.io/pymdown-extensions/extensions/tabbed/) extension for markdown, or\n[sphinx{design} tabs](https://sphinx-design.readthedocs.io/en/latest/tabs.html) for Sphinx.\n\nThis, however, raises several problems:\n\n1. Maintaining multiple versions of a single example is tedious and error-prone as they can easily\n   become out of sync\n2. Figuring out which examples need to be changed for which specific Python version is a labour intensive task\n3. Dropping or adding support for Python versions requires revisiting every example in the documentation\n4. Checking potentially ~4 versions of a single example into VCS creates unnecessary noise\n\nGiven those, it's no surprise that the current standard is to only show examples for the lowest supported version of Python.\n\n### The solution\n\n**AutoPyTabs** aims to solve all of these problems by automatically generating versions (using the awesome\n[ruff](https://github.com/charliermarsh/ruff) project) of code examples, targeting different Python versions\n**at build-time**, based on a base version (the lowest supported Python version).\nThis means that:\n\n1. There exists only one version of each example: The lowest supported version becomes the source of truth,\n   therefore preventing out-of-sync examples and reducing maintenance burden\n2. Dropping or adding support for Python versions can be done via a simple change in a configuration file\n\n\u003chr\u003e\n\n## Table of contents\n\n1. [Usage with mkdocs / markdown](#usage-markdown)\n   1. [Configuration](#markdown-config)\n   2. [Differences between the mkdocs plugin vs markdown extension](#differences-between-the-mkdocs-plugin-and-markdown-extension)\n   3. [Examples](#markdown-examples)\n   4. [Selectively disable](#selectively-disable)\n   5. [Compatibility with `pymdownx.snippets`](#compatibility-with-pymdownxsnippets)\n2. [Usage with Sphinx](#usage-with-sphinx)\n   1. [Configuration](#sphinx-config)\n   2. [Directives](#directives)\n   3. [Examples](#sphinx-examples)\n   4. [Compatibility with other extensions](#compatibility-with-other-extensions)\n\n\u003chr\u003e \n\n## Installation\n\nFor mkdocs: `pip install auto-pytabs[mkdocs]`\nFor markdown: `pip install auto-pytabs[markdown]`\nFor sphinx: `pip install auto-pytabs[sphinx]`\n\n\u003ch2 id=\"usage-markdown\"\u003eUsage with mkdocs / markdown\u003c/h2\u003e\n\n\u003ch3 id=\"markdown-config\"\u003eConfiguration\u003c/h3\u003e\n\n#### Mkdocs plugin\n\n```yaml\nsite_name: My Docs\nmarkdown_extensions:\n  - pymdownx.tabbed:\nplugins:\n  - auto_pytabs:\n      min_version: \"3.7\"  # optional\n      max_version: \"3.12\" # optional\n      tab_title_template: \"Python {min_version}+\"  # optional\n      no_cache: false  # optional\n      default_tab: \"highest\"  # optional\n      reverse_order: false  # optional\n```\n\n*Available configuration options*\n\n| Name                 | Default                   | Description                                                                |\n| -------------------- | ------------------------- | -------------------------------------------------------------------------- |\n| `min_version`        | `(3, 7)`                  | Minimum python version                                                     |\n| `max_version`        | `(3, 12)`                 | Maximum python version                                                     |\n| `tab_title_template` | `\"Python {min_version}+\"` | Template for tab titles                                                    |\n| `no_cache`           | `False`                   | Disable file system caching                                                |\n| `default_tab`        | `highest`                 | (`highest` or `lowest`) Version tab to preselect                           |\n| `reverse_order`      | `False`                   | Reverse the order of tabs. Default is to go from lowest to highest version |\n\n#### Markdown extension\n\n```python\nimport markdown\n\nmd = markdown.Markdown(\n    extensions=[\"auto_pytabs\"],\n    extension_configs={\n        \"auto_pytabs\": {\n            \"min_version\": \"3.7\",  # optional\n            \"max_version\": \"3.12\",  # optional\n            \"tab_title_template\": \"Python {min_version}+\",  # optional\n            \"default_tab\": \"highest\",  # optional\n            \"reverse_order\": False,  # optional\n        }\n    },\n)\n```\n\n*Available configuration options*\n\n| Name                 | Default                   | Description                                                                |\n| -------------------- | ------------------------- | -------------------------------------------------------------------------- |\n| `min_version`        | `(3, 7)`                  | Minimum python version to generate code for                                |\n| `max_version`        | `(3, 7)`                  | Maximum python version to generate code for                                |\n| `tab_title_template` | `\"Python {min_version}+\"` | Template for tab titles                                                    |\n| `default_tab`        | `highest`                 | (`highest` or `lowest`) Version tab to preselect                           |\n| `reverse_order`      | `False`                   | Reverse the order of tabs. Default is to go from lowest to highest version |\n\n### Differences between the mkdocs plugin and markdown extension\n\nAutoPyTabs ships as a markdown extension and an mkdocs plugin, both of which can be used in mkdocs. The only difference\nbetween them is that the mkdocs plugin supports caching, which can make subsequent builds faster (i.e. when using `mkdocs serve`).\nThe reason why the markdown extension does not support caching is that `markdown` does not have clearly defined build\nsteps with wich an extension could interact (like mkdocs [plugin events](https://www.mkdocs.org/dev-guide/plugins/#events)),\nmaking it impossible to know when to persist cached items to disk / evict unused items.\n\n**If you are using mkdocs, the mkdocs plugin is recommended**. If you have caching disabled, there will be no difference either way.\n\nShould you wish to integrate the markdown extension into a build process where you can manually persist the cache after the build,\nyou can explicitly pass it a cache:\n\n```python\nimport markdown\nfrom auto_pytabs.core import Cache\n\ncache = Cache()\n\nmd = markdown.Markdown(\n    extensions=[\"auto_pytabs\"],\n    extension_configs={\n        \"auto_pytabs\": {\n           \"cache\": cache\n        }\n    },\n)\n\n\ndef build_markdown() -\u003e None:\n    md.convertFile(\"document.md\", \"document.html\")\n    cache.persist()\n```\n\n\u003ch3 id=\"markdown-examples\"\u003eExamples\u003c/h3\u003e\n\n**Input**\n\n\u003cpre\u003e\n```python\nfrom typing import Optional, Dict\n\ndef foo(bar: Optional[str]) -\u003e Dict[str, str]:\n    ...\n```\n\u003c/pre\u003e\n\n**Equivalent markdown**\n\n\u003cpre\u003e\n=== \"Python 3.7+\"\n    ```python\n    from typing import Optional, Dict\n\n    def foo(bar: Optional[str]) -\u003e Dict[str, str]:\n        ...\n    ```\n\n=== \"Python 3.9+\"\n    ```python\n    from typing import Optional\n    \n    \n    def foo(bar: Optional[str]) -\u003e dict[str, str]:\n        ...\n    ```\n\n==== \"Python 3.10+\"\n    ```python\n    def foo(bar: str | None) -\u003e dict[str, str]:\n        ...\n    ```\n\u003c/pre\u003e\n\n#### Nested blocks\n\nNested tabs are supported as well:\n\n**Input**\n\n\u003cpre\u003e\n=== \"Level 1-1\"\n\n    === \"Level 2-1\"\n\n        ```python\n        from typing import List\n        x: List[str]\n        ```\n\n    === \"Level 2-2\"\n    \n        Hello, world!\n\n=== \"Level 1-2\"\n\n    Goodbye, world!\n\u003c/pre\u003e\n\n**Equivalent markdown**\n\n\u003cpre\u003e\n=== \"Level 1-1\"\n\n    === \"Level 2-1\"\n\n        === \"Python 3.7+\"\n            ```python\n            from typing import List\n            x: List[str]\n            ```\n        \n        === \"Python 3.9+\"\n            ```python\n            x: list[str]\n            ```\n\n    === \"Level 2-2\"\n\n        Goodbye, world!\n\n=== \"Level 1-2\"\n    Hello, world!\n    \n\u003c/pre\u003e\n\n### Selectively disable\n\nYou can disable conversion for a single code block:\n\n````\n\u003c!-- autopytabs: disable-block --\u003e\n```python\nfrom typing import Set, Optional\n\ndef bar(baz: Optional[str]) -\u003e Set[str]:\n    ...\n```\n````\n\nOr for whole sections / files\n\n```\n\u003c!-- autopytabs: disable --\u003e\neverything after this will be ignored\n\u003c!-- autopytabs: enable --\u003e\nre-enables conversion again\n```\n\n### Compatibility with `pymdownx.snippets`\n\nIf the `pymdownx.snippets` extension is used, make sure that it runs **before** AutoPyTab\n\n\u003chr\u003e\n\n## Usage with Sphinx\n\nAutPyTabs provides a Sphinx extension `auto_pytabs.sphinx_ext`, enabling its functionality\nfor the `.. code-block` and `.. literalinclude` directives.\n\n\u003ch3 id=\"sphinx-config\"\u003eConfiguration\u003c/h3\u003e\n\n#### Example configuration\n\n```python\nextensions = [\"auto_pytabs.sphinx_ext\", \"sphinx_design\"]\n\nauto_pytabs_min_version = (3, 7)  # optional\nauto_pytabs_max_version = (3, 11)  # optional\nauto_pytabs_tab_title_template = \"Python {min_version}+\"  # optional \n# auto_pytabs_no_cache = True  # disabled file system caching\n# auto_pytabs_compat_mode = True  # enable compatibility mode\n# auto_pytabs_default_tab = \"lowest\"  # Pre-select the tab with the lowest version\n# auto_pytabs_reverse_order = True  # reverse the order of tabs to highest \u003e lowest\n```\n\n#### Available configuration options\n\n| Name                             | Default                   | Description                                                                |\n| -------------------------------- | ------------------------- | -------------------------------------------------------------------------- |\n| `auto_pytabs_min_version`        | `(3, 7)`                  | Minimum python version to generate code for                                |\n| `auto_pytabs_max_version`        | `(3, 7)`                  | Maximum python version to generate code for                                |\n| `auto_pytabs_tab_title_template` | `\"Python {min_version}+\"` | Template for tab titles                                                    |\n| `auto_pytabs_no_cache`           | `False`                   | Disable file system caching                                                |\n| `auto_pytabs_compat_mode`        | `False`                   | Enable [compatibility mode](#compatibility-mode)                           |\n| `auto_pytabs_default_tab`        | `highest`                 | Either `highest` or `lowest`. Version tab to preselect                     |\n| `auto_pytabs_reverse_order`      | `False`                   | Reverse the order of tabs. Default is to go from lowest to highest version |\n\n\u003ch3 id=\"sphinx-examples\"\u003eExamples\u003c/h3\u003e\n\n**Input**\n\n```rst\n.. code-block:: python\n\n   from typing import Optional, Dict\n   \n   def foo(bar: Optional[str]) -\u003e Dict[str, str]:\n       ...\n```\n\n**Equivalent ReST**\n\n```rst\n.. tab-set::\n\n   .. tab-item:: Python 3.7+\n   \n       .. code-block:: python\n       \n          from typing import Optional, Dict\n      \n          def foo(bar: Optional[str]) -\u003e Dict[str, str]:\n              ...\n\n   .. tab-item:: Python 3.9+\n   \n      .. code-block:: python\n      \n          from typing import Optional\n          \n          \n          def foo(bar: Optional[str]) -\u003e dict[str, str]:\n              ...\n\n   .. tab-item:: Python 3.10+\n   \n      .. code-block:: python\n      \n          def foo(bar: str | None) -\u003e dict[str, str]:\n              ...\n\n```\n\n### Directives\n\nAutoPyTabs overrides the built-in `code-block` and `literal-include` directives,\nextending them with auto-upgrade and tabbing functionality, which means no special\ndirectives, and therefore changes to existing documents are needed.\n\nAdditionally, a `:no-upgrade:` option is added to the directives, which can be used to\nselectively fall back the default behaviour.\n\nTwo new directives are provided as well:\n\n- `.. pytabs-code-block::`\n- `.. pytabs-literalinclude::`\n\nwhich by default act exactly like `.. code-block` and `.. literalinclude` respectively,\nand are mainly to provide AutoPyTab's functionality in [compatibility mode](#compatibility-mode).\n\n### Compatibility mode\n\nIf you don't want the default behaviour of directive overrides, and instead wish to use the\n`.. pytabs-` directives manually (e.g. because of compatibility issues with other extensions\nor because you only want to apply it to select code blocks) you can make use AutoPyTabs' compatibility\nmode. To enable it, simply use the `auto_pytabs_compat_mode = True` in `conf.py`. Now, only content within `.. pytabs-`\ndirectives will be upgraded.\n\n### Compatibility with other extensions\n\nNormally the directive overrides don't cause any problems and are very convenient,\nsince no changes to existing documents have to be made. However, if other extensions are included,\nwhich themselves override one of those directives, one of them will inadvertently override the other,\ndepending on the order they're defined in `extensions`.\n\nTo combat this, you can use the [compatibility mode](#compatibility-mode) extension instead, which\nonly includes the new directives.\n\nIf you control the conflicting overrides, you can alternatively inherit from\n`auto_py_tabs.sphinx_ext.CodeBlockOverride` and `auto_py_tabs.sphinx_ext.LiteralIncludeOverride`\ninstead of `sphinx.directives.code.CodeBlock` and `sphinx.directives.code.LiteralInclude` respectively.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprovinzkraut%2Fautopytabs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fprovinzkraut%2Fautopytabs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprovinzkraut%2Fautopytabs/lists"}