pax_global_header 0000666 0000000 0000000 00000000064 14707035566 0014527 g ustar 00root root 0000000 0000000 52 comment=f5c7295d2ea5897bd46d44ebb095a44b198d99cd
sphinx-autoapi-3.3.3/ 0000775 0000000 0000000 00000000000 14707035566 0014506 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/.devcontainer/ 0000775 0000000 0000000 00000000000 14707035566 0017245 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/.devcontainer/devcontainer.json 0000664 0000000 0000000 00000001053 14707035566 0022620 0 ustar 00root root 0000000 0000000 // For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/python
{
"name": "Sphinx AutoAPI",
"image": "mcr.microsoft.com/devcontainers/python:0-3.11",
// Features to add to the dev container. More info: https://containers.dev/features.
// "features": {},
// Configure tool-specific properties.
"customizations": {
},
// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "pip3 install ."
}
sphinx-autoapi-3.3.3/.github/ 0000775 0000000 0000000 00000000000 14707035566 0016046 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/.github/workflows/ 0000775 0000000 0000000 00000000000 14707035566 0020103 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/.github/workflows/main.yml 0000664 0000000 0000000 00000001421 14707035566 0021550 0 ustar 00root root 0000000 0000000 name: tests
on:
- push
- pull_request
jobs:
test:
strategy:
matrix:
# Keep this in sync with tox.ini
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
platform: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true
- name: Install dependencies
run: |
python -m pip install --upgrade pip setuptools wheel
python -m pip install tox tox-gh-actions
- name: Run tests
run: tox
sphinx-autoapi-3.3.3/.github/workflows/release.yml 0000664 0000000 0000000 00000004464 14707035566 0022256 0 ustar 00root root 0000000 0000000 name: Publish Python 🐍 distribution 📦 to PyPI
on: push
jobs:
build:
name: Build distribution 📦
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.x"
- name: Install pypa/build
run: >-
python3 -m
pip install
build
--user
- name: Build a binary wheel and a source tarball
run: python3 -m build
- name: Store the distribution packages
uses: actions/upload-artifact@v4
with:
name: python-package-distributions
path: dist/
publish-to-pypi:
name: >-
Publish Python 🐍 distribution 📦 to PyPI
if: startsWith(github.ref, 'refs/tags/') # only publish to PyPI on tag pushes
needs:
- build
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/p/sphinx-autoapi
permissions:
id-token: write # IMPORTANT: mandatory for trusted publishing
steps:
- name: Download all the dists
uses: actions/download-artifact@v4
with:
name: python-package-distributions
path: dist/
- name: Publish distribution 📦 to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
github-release:
name: >-
Sign the Python 🐍 distribution 📦 with Sigstore
and upload them to GitHub Release
needs:
- publish-to-pypi
runs-on: ubuntu-latest
permissions:
contents: write # IMPORTANT: mandatory for making GitHub Releases
id-token: write # IMPORTANT: mandatory for sigstore
steps:
- name: Download all the dists
uses: actions/download-artifact@v4
with:
name: python-package-distributions
path: dist/
- name: Sign the dists with Sigstore
uses: sigstore/gh-action-sigstore-python@v3.0.0
with:
inputs: >-
./dist/*.tar.gz
./dist/*.whl
- name: Upload artifact signatures to GitHub Release
env:
GITHUB_TOKEN: ${{ github.token }}
# Upload to GitHub Release using the `gh` CLI.
# `dist/` contains the built packages, and the
# sigstore-produced signatures and certificates.
run: >-
gh release upload
'${{ github.ref_name }}' dist/**
--repo '${{ github.repository }}'
sphinx-autoapi-3.3.3/.gitignore 0000664 0000000 0000000 00000000460 14707035566 0016476 0 ustar 00root root 0000000 0000000 *.egg-info
*.pyc
*.swp
.doctrees
_build_rtd
_build
docs/autoapi
readthedocs_build
tests/*/autoapi
tests/dotnetexample/example/Identity/
_api_
.tox
.eggs
.ropeproject/
.cache
.pytest_cache/
build/
dist/
tests/python/pyexample/autoapi/example/index.rst
tests/python/pymovedconfpy/autoapi/example/index.rst
sphinx-autoapi-3.3.3/.readthedocs.yml 0000664 0000000 0000000 00000001164 14707035566 0017576 0 ustar 00root root 0000000 0000000 version: 2
# Set the OS, Python version and other tools you might need
build:
os: ubuntu-22.04
tools:
python: "3.11"
apt_packages:
- graphviz
# Build documentation in the docs/ directory with Sphinx
sphinx:
configuration: docs/conf.py
# Optionally build your docs in additional formats such as PDF and ePub
# formats:
# - pdf
# - epub
# Optional but recommended, declare the Python requirements required
# to build your documentation
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
python:
install:
- method: pip
path: .
extra_requirements:
- docs
sphinx-autoapi-3.3.3/CHANGELOG.rst 0000664 0000000 0000000 00000055507 14707035566 0016543 0 ustar 00root root 0000000 0000000 Changelog
=========
Versions follow `Semantic Versioning `_ (``..``).
.. towncrier release notes start
v3.3.3 (2024-10-25)
-------------------
Bugfixes
^^^^^^^^
- Document packages and modules under a single "submodules" heading (#450)
- Fix crash when __init__ is assigned to (#488)
- Fix documenting incorrect attributes from __init__ (#497)
Misc
^^^^
- #426, #462, #491, #492
v3.3.2 (2024-09-25)
-------------------
Bugfixes
^^^^^^^^
- Fix types missing from documentation generated by autodoc-style directives. (#473)
v3.3.1 (2024-09-01)
-------------------
Bugfixes
^^^^^^^^
- Fix all class members missing when documenting a module with the same name as a standard library module
Members inherited from the standard library can also have their skip value
overridden by autoapi-skip-member. (#478)
Misc
^^^^
- Updated all github actions.
v3.3.0 (2024-08-28)
-------------------
Features
^^^^^^^^
- Do not document members inherited from standard library classes. (#467)
Bugfixes
^^^^^^^^
- Fix instance attributes not being documented by inherited-members (#477)
Misc
^^^^
- #425
- Fix the parser returning a dictionary instead of a list in the empty parse scenario
- Rename testenvs to all follow similar naming style
v3.2.1 (2024-07-23)
-------------------
Bugfixes
^^^^^^^^
- Fix error or duplicates when __init__ assigns to a property (#466)
v3.2.0 (2024-07-20)
-------------------
Features
^^^^^^^^
- functools.cached_property is considered a property (#436)
Bugfixes
^^^^^^^^
- Gracefully handle no objects being rendered (#448)
- Fix ignoring undocumented instance attributes (#451)
Deprecations and Removals
^^^^^^^^^^^^^^^^^^^^^^^^^
- Removed ability for autoapi_template_dir to be relative to cwd. This was supposed to have been retired in v3 (#457)
- Removed autoapi_include_summaries option. This was supposed to have been retired in v3
Misc
^^^^
- #428, #449
v3.1.2 (2024-06-20)
-------------------
Bugfixes
^^^^^^^^
- Fix imported members being rendered in modules (#452)
v3.1.1 (2024-05-22)
-------------------
Bugfixes
^^^^^^^^
- Fix private subpackages causing orphan pages (#446)
v3.1.0 (2024-05-20)
-------------------
Features
^^^^^^^^
- Objects can render to their own page (#226)
- Render PEP-695 type aliases as TypeAlias assignments. (#414)
Bugfixes
^^^^^^^^
- Values are always rendered for TypeAlises and PEP-695 type aliases. (#224)
- Fix submodule with `__init__.pyi` documented as `__init__` instead of submodule name (#398)
- Fix IndexError when a module docstring contains only a heading (#412)
- Preserve strings inside Literal type annotations (#423)
- Stopped using xrefs in page titles (#427)
- Fix unpickable configuration value warning when using autoapi_prepare_jinja_env (#445)
- Fix emitting ignore event twice for methods.
Misc
^^^^
- #388
v3.0.0 (2023-09-26)
-------------------
Bugfixes
^^^^^^^^
- Ensure `tooltip` is always a `str`. (str-tooltip)
- Replaced usage of deprecated sphinx.util.status_iterator (#391)
Deprecations and Removals
^^^^^^^^^^^^^^^^^^^^^^^^^
- Removed support for documenting languages other than Python (#248)
- Removed support for Python 3.7
Misc
^^^^
- #389, #390, #392, #407
v2.1.1 (2023-06-10)
-------------------
Bugfixes
^^^^^^^^
- Fix "document isn't included" warning when using autoapi_add_toctree_entry (#319)
- Types used in PEP-604 union syntax can be linked with intersphinx (#366)
- Fix class overrides not rendering correctly.
- Fix separated type comments for arguments not merging correctly in Python 3.7
- Fixed viewcode being unable to find the source code for imported objects
Improved Documentation
^^^^^^^^^^^^^^^^^^^^^^
- Made it clearer how to customise what objects AutoAPI will document. (#339)
Misc
^^^^
- #375, #382
v2.1.0 (2023-03-28)
-------------------
Deprecations and Removals
^^^^^^^^^^^^^^^^^^^^^^^^^
- Support for documenting languages other than Python is deprecated. (#248)
- Removed the option to have autoapi generate toctree entries for domain objects.
Domain objects are now added to the toctree by Sphinx.
Dropped support for sphinx < 5.2.0. (#369)
Misc
^^^^
- Added basic type checking.
- Integrated towncrier into the release workflow.
v2.0.1 (2023-01-16)
-------------------
Features
^^^^^^^^
- Can turn off the addition of documented objects to the TOC tree.
- Added support for Python 3.11.
Bug Fixes
^^^^^^^^^
- `#330 `: (Python)
Render tuple values as tuples, not lists.
- `#341 `: (Python)
Fix module level assignments to class attributes being documented as
module level attributes.
- (Python) Fix "bysource" sort order showing items in alphabetical order.
- (Python) Use the correct directives for a variable type and value.
Trivial/Internal Changes
^^^^^^^^^^^^^^^^^^^^^^^^
- Removed some autogenerated test data from the repository.
v2.0.0 (2022-09-27)
-------------------
Breaking Changes
^^^^^^^^^^^^^^^^
- Dropped support for Sphinx <4.
- `#352 `: (Python)
Properties are rendered with the ``property`` directive,
fixing support for Sphinx 5.2.
A new ``PythonPythonMapper`` object (``PythonProperty``) has been created
to support this change. This object can be passed to templates, filters,
and hooks.
A new ``property.rst`` template has also been created to support this change.
Trivial/Internal Changes
^^^^^^^^^^^^^^^^^^^^^^^^
- Use https links where possible in documentation.
- Pass correct argument types to ``status_iterator``.
V1.9.0 (2022-07-25)
-------------------
Breaking Changes
^^^^^^^^^^^^^^^^
- Dropped support for Python 3.6.
Features
^^^^^^^^
- Added support for Python 3.10.
- `#222 `:
Marked extension as parallel read safe.
Bug Fixes
^^^^^^^^^
- `#324 `: (Python)
Fail elegantly when no source files are found.
- (Python) Stop calling ``autodoc-process-docstring`` when docstring is empty.
Works around https://github.com/sphinx-doc/sphinx/issues/10701.
- `#318 `: (Python)
Fixed misaligned argument types on methods/classmethods when using type comments.
- `#278 `: (Python)
Limit signatures to 60 characters in summaries.
- Fix keyerror when using markdown sources.
- `#328 `: (Python)
Fix kw-only marker getting ignored if first in the signature.
Trivial/Internal Changes
^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed tests in Sphinx 5.
- Fixed many typos throughout the documentation.
v1.8.4 (2021-08-16)
-------------------
Bug Fixes
^^^^^^^^^
- `#301 `: (Python)
Fixed compatibility with astroid 2.7+.
v1.8.3 (2021-07-31)
-------------------
Bug Fixes
^^^^^^^^^
- `#299 `: (Python)
Fixed incorrect indentation in generated documentation when a class with no
constructor has a summary line spanning multiple lines.
Trivial/Internal Changes
^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed broken link to Jinja objects.inv.
v1.8.2 (2021-07-26)
-------------------
Bug Fixes
^^^^^^^^^
- Fixed error when parsing a class with no constructor.
- `#293 `:
Fixed failure to build out of source conf.py files.
Configuration values using relative values are now relative to the source directory
instead of relative to the conf.py file.
- `#289 `: (Python)
Fixed AttributeError using inheritance diagrams on a module with plain imports.
- `#292 `:
Explicitly use the domain for generated directives.
v1.8.1 (2021-04-24)
-------------------
Bug Fixes
^^^^^^^^^
- `#273 `:
Fixed type annotations being shown for only a single module.
v1.8.0 (2021-04-12)
-------------------
Features
^^^^^^^^
- Expandable value for multi-line string attributes.
- `#265 `:
Can resolve the qualified paths of parameters to generics.
- `#275 `:
Warnings have been categorised and can be suppressed through ``suppress_warnings``.
- `#280 `:
Data attributes are documented in module summaries.
Bug Fixes
^^^^^^^^^
- `#273 `:
Fixed setting ``autodoc_typehints`` to ``none`` or ``description``
not turning off signature type hints.
``autodoc_typehints`` integration is considered experimental until
the extension properly supports overload functions.
- `#261 `:
Fixed data annotations causing pickle or deepcopy errors.
- Documentation can be generated when multiple source directories
share a single ``conf.py`` file.
Trivial/Internal Changes
^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed ``DeprecationWarning`` for invalid escape sequence ``\s`` in tests.
- Fixed ``FutureWarning`` for ``Node.traverse()`` becoming an iterator instead of list.
- New example implementation of ``autoapi-skip-member`` Sphinx event.
- Can run tests with tox 4.
- Updated packaging to use PEP-517.
- All unittest style tests have been converted to pytest style tests.
- An exception raised by docfx is raised directly instead of wrapping it.
- Started using Github Actions for continuous integration.
V1.7.0 (2021-01-31)
-------------------
Features
^^^^^^^^
- The fully qualified path of objects are included type annotations
so that Sphinx can link to them.
- Added support for Sphinx 3.3. and 3.4.
- `#240 `:
The docstrings of ``object.__init__``, ``object.__new__``,
``type.__init__``, and ``type.__new__`` are not inherited.
Bug Fixes
^^^^^^^^^
- `#260 `:
The overload signatures of ``__init__`` methods are documented.
V1.6.0 (2021-01-20)
-------------------
Breaking Changes
^^^^^^^^^^^^^^^^
- Dropped support for Python 2 and Sphinx 1.x/2.x.
Python 2 source code can still be parsed.
Features
^^^^^^^^
- (Python) Added support for using type hints as parameter types and return types
via the ``sphinx.ext.autodoc.typehints`` extension.
- `#191 `:
Basic incremental build support is enabled ``autoapi_keep_files`` is enabled.
Providing none of the source files have changed,
AutoAPI will skip parsing the source code and regenerating the API documentation.
- `#200 `:
Can pass a callback that edits the Jinja Environment object before
template rendering begins.
This allows custom filters, tests, and globals to be added to the environment.
- Added support for Python 3.9.
Bug Fixes
^^^^^^^^^
- `#246 `: (Python)
Fixed TypeError when parsing a class that inherits from ``type``.
- `#244 `:
Fixed an unnecessary deprecation warning being raised when running
sphinx-build from the same directory as conf.py.
- (Python) Fixed properties documented by Autodoc directives getting documented as methods.
V1.5.1 (2020-10-01)
-------------------
Bug Fixes
^^^^^^^^^
- Fixed AttributeError when generating an inheritance diagram for a module.
V1.5.0 (2020-08-31)
-------------------
This will be the last minor version to support Python 2 and Sphinx 1.x/2.x.
Features
^^^^^^^^
- `#222 `:
Declare the extension as parallel unsafe.
- `#217 `: (Python)
All overload signatures are documented.
- `#243 `:
Files are found in order of preference according to ``autoapi_file_patterns``.
- Added support for Sphinx 3.2.
Bug Fixes
^^^^^^^^^
- `#219 `: (Python)
Fixed return types not showing for methods.
- (Python) Fixed incorrect formatting of properties on generated method directives.
- Fixed every toctree entry getting added as a new list.
- `#234 `:
Fixed only some entries getting added to the toctree.
Trivial/Internal Changes
^^^^^^^^^^^^^^^^^^^^^^^^
- autoapisummary directive inherits from autosummary for future stability.
v1.4.0 (2020-06-07)
-------------------
Features
^^^^^^^^
- `#197 `: Added
``autoapi.__version__`` and ``autoapi.__version_info__`` attributes
for accessing version information.
- `#201 `: (Python)
Added the ``autoapi_member_order`` option to allow the order that members
are documented to be configurable.
- `#203 `: (Python)
A class without a docstring inherits one from its parent.
A methods without a docstring inherits one from the method that it overrides.
- `#204 `: (Python)
Added the ``imported-members`` AutoAPI option to be able to enable or disable
documenting objects imported from the same top-level package or module
without needing to override templates.
Bug Fixes
^^^^^^^^^
- `#198 `:
Documentation describes the required layout for template override directories.
- `#195 `: (Python)
Fixed incorrect formatting when ``show-inheritance-diagram``
and ``private-members`` are turned on.
- `#193 ` and
`#208 `: (Python)
Inheritance diagrams can follow imports to find classes to document.
- `#213 `: (Python)
Fixed module summary never showing.
Trivial/Internal Changes
^^^^^^^^^^^^^^^^^^^^^^^^
- black shows diffs by default
- `#207 `:
Fixed a typo in the code of the golang tutorial.
v1.3.0 (2020-04-05)
-------------------
Breaking Changes
^^^^^^^^^^^^^^^^
- Dropped support for Python 3.4 and 3.5.
Features
^^^^^^^^
- `#151 `: (Python)
Added the ``autoapi_python_use_implicit_namespaces`` option to allow
AutoAPI to search for implicit namespace packages.
- Added support for Sphinx 2.2 and 2.3.
- Added support for Python 3.8.
- `#140 `: (Python)
Added the ``autoapi-inheritance-diagram`` directive to create
inheritance diagrams without importing modules.
Enable the ``show-inheritance-diagram`` AutoAPI option to
turn the diagrams on in generated documentation.
- `#183 `: (Python)
Added the ``show-inheritance`` AutoAPI option to be able to enable or disable
the display of a list of base classes in generated documentation about a class.
Added the ``inherited-members`` AutoAPI option to be able to enable or disable
the display of members inherited from a base class
in generated documentation about a class.
- The ``autoapi_include_summaries`` option has been replaced with the
``show-module-summary`` AutoAPI option.
``autoapi_include_summaries`` will stop working in the next major version.
- Added support for Sphinx 2.4 and 3.0
Bug Fixes
^^^^^^^^^
- `#186 `: (Python)
Fixed an exception when there are too many argument type annotations
in a type comment.
- (Python) args and kwargs type annotations can be read from
the function type comment.
Trivial/Internal Changes
^^^^^^^^^^^^^^^^^^^^^^^^
- Tests are now included in the sdist.
v1.2.1 (2019-10-09)
-------------------
Bug Fixes
^^^^^^^^^
- (Python) "Invalid desc node" warning no longer raised for autodoc-style
directives.
v1.2.0 (2019-10-05)
-------------------
Features
^^^^^^^^
- (Python) Can read per argument type comments with astroid > 2.2.5.
- (Python) Added autoapidecorator directive with Sphinx >= 2.0.
- (Python) Can use autodoc_docstring_signature with Autodoc-style directives.
- (Python) Added autoapi-skip-member event.
- Made it more clear which file causes an error, when an error occurs.
- Sphinx language domains are now optional dependencies.
Bug Fixes
^^^^^^^^^
- (Python) Forward reference annotations are no longer rendered as strings.
- (Python) autoapifunction directive no longer documents async functions as
a normal function.
- (Python) Fixed unicode decode errors in some Python 3 situations.
- Documentation more accurately describes what configuration accepts
relative paths and where they are relative to.
v1.1.0 (2019-06-23)
-------------------
Features
^^^^^^^^
- (Python) Can override ignoring local imports in modules by using __all__.
Bug Fixes
^^^^^^^^^
- (Python) Fixed incorrect formatting of functions and methods.
- Added support for Sphinx 2.1.
Trivial/Internal Changes
^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed some dead links in the README.
- Fixed lint virtualenv.
v1.0.0 (2019-04-24)
-------------------
Features
^^^^^^^^
- `#100 `: (Python)
Added support for documenting C extensions via ``.pyi`` stub files.
- Added support for Sphinx 2.0.
- Toned down the API reference index page.
- (Go) Patterns configured in ``autoapi_ignore`` are passed to godocjson.
- New and improved documentation.
- No longer need to set ``autoapi_add_toctree_entry`` to False when ``autoapi_generate_api_docs`` is False.
- `#139 `
Added support for basic type annotations in documentation generation and autodoc-style directives.
Bug Fixes
^^^^^^^^^
- `#159 `: (Python)
Fixed ``UnicodeDecodeError`` on Python 2 when a documenting an attribute that contains binary data.
- (Python) Fixed private submodules displaying when ``private-members`` is turned off.
- Templates no longer produce excessive whitespace.
- (Python) Fixed an error when giving an invalid object to an autodoc-style directive.
Trivial/Internal Changes
^^^^^^^^^^^^^^^^^^^^^^^^
- No longer pin the version of black.
- Added missing test environments to travis.
v0.7.1 (2019-02-04)
-------------------
Bug Fixes
^^^^^^^^^
- (Python) Fixed a false warning when importing a local module.
v0.7.0 (2019-01-30)
-------------------
Breaking Changes
^^^^^^^^^^^^^^^^
- Dropped support for Sphinx<1.6.
Features
^^^^^^^^
- Added debug messages about what AutoAPI is doing.
Bug Fixes
^^^^^^^^^
- `#156 `: (Python) Made import resolution more stable.
Also capable of giving more detailed warnings.
Trivial/Internal Changes
^^^^^^^^^^^^^^^^^^^^^^^^
- Code is now formatted using black.
- Removed references to old css and js files.
- Replaced usage of deprecated Sphinx features.
- Reorganised tests to be more pytest-like.
v0.6.2 (2018-11-15)
-------------------
Bug Fixes
^^^^^^^^^
- (Python) Fixed some import chains failing to resolve depending on resolution order.
v0.6.1 (2018-11-14)
-------------------
Bug Fixes
^^^^^^^^^
- (Python) Fixed unicode decoding on Python 3.7.
- (Python) Fixed autodoc directives not documenting anything in submodules or subpackages.
- (Python) Fixed error parsing files with unicode docstrings.
- (Python) Fixed error when documenting something that's imported in more than one place.
Trivial/Internal Changes
^^^^^^^^^^^^^^^^^^^^^^^^
- (Python) Added Python 3.7 testing.
- Started testing against stable version of Sphinx 1.8.
- Fixed all "no title" warnings during tests.
v0.6.0 (2018-08-20)
-------------------
Breaking Changes
^^^^^^^^^^^^^^^^
- `#152 `: Removed the ``autoapi_add_api_root_toctree`` option.
This has been replaced with the ``autoapi_add_toctree_entry`` option.
- `#25 `: Removed distutils support.
- Removed redundant ``package_dir`` and ``package_data`` options.
Features
^^^^^^^^
- (Python) Added viewcode support for imported members.
- `#146 `: (Python) No longer documents ``__init__()`` attributes without a docstring.
- `#153 `: (Python) Can document a public python API.
- `#111 `: (Python) Can opt to write manual documentation through new autodoc-style directives.
- `#152 `: Made it easier to remove default index page.
Also removed autoapi_add_api_root_toctree config option
- `#150 `: (Python) ``private-members`` also controls private subpackages and submodules.
- (Python) Added support for static and class methods.
- (Python) Methods include ``self`` in their arguments.
This more closely matches autodoc behaviour.
- `#145 `: (Python) Added support for detecting Python exceptions.
- (Python) Can control how __init__ docstring is displayed.
- (Python) Added support for viewcode.
- (Python) Source files no longer need to be in ``sys.path``.
Bug Fixes
^^^^^^^^^
- (Python) Fixed linking to builtin bases.
- (Python) Fixed properties being documented more than once when set in ``__init__()``.
- (Python) Fixed nested classes not getting displayed.
- `#148 `: (Python) Fixed astroid 2.0 compatibility.
- (Python) Fixed filtered classes and attributes getting displayed.
- (Python) Fixed incorrect display of long lists.
- `#125 `: (Javascript) Fixed running incorrect jsdoc command on Windows.
- `#125 `: (Python) Support specifying package directories in ``autoapi_dirs``.
Trivial/Internal Changes
^^^^^^^^^^^^^^^^^^^^^^^^
- Added Sphinx 1.7 and 1.8.0b1 testing.
- `#120 `: Updated documentation to remove outdated references.
- Removed old testing dependencies.
- `#143 `: Removed unnecessary wheel dependency.
sphinx-autoapi-3.3.3/LICENSE.rst 0000664 0000000 0000000 00000002124 14707035566 0016321 0 ustar 00root root 0000000 0000000 The MIT License (MIT)
=====================
Copyright (c) 2015 Read the Docs, Inc
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
sphinx-autoapi-3.3.3/MANIFEST.in 0000664 0000000 0000000 00000000134 14707035566 0016242 0 ustar 00root root 0000000 0000000 recursive-include autoapi *.rst
include *.rst
include LICENSE.mit
recursive-include tests *
sphinx-autoapi-3.3.3/README.rst 0000664 0000000 0000000 00000006724 14707035566 0016206 0 ustar 00root root 0000000 0000000 Sphinx AutoAPI
==============
.. image:: https://readthedocs.org/projects/sphinx-autoapi/badge/?version=latest
:target: https://sphinx-autoapi.readthedocs.org
:alt: Documentation
.. image:: https://github.com/readthedocs/sphinx-autoapi/actions/workflows/main.yml/badge.svg?branch=main
:target: https://github.com/readthedocs/sphinx-autoapi/actions/workflows/main.yml?query=branch%3Amain
:alt: Github Build Status
.. image:: https://img.shields.io/pypi/v/sphinx-autoapi.svg
:target: https://pypi.org/project/sphinx-autoapi/
:alt: PyPI Version
.. image:: https://img.shields.io/pypi/pyversions/sphinx-autoapi.svg
:target: https://pypi.org/project/sphinx-autoapi/
:alt: Supported Python Versions
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
:target: https://github.com/python/black
:alt: Formatted with Black
Sphinx AutoAPI is a Sphinx extension for generating complete API documentation
without needing to load, run, or import the project being documented.
In contrast to the traditional `Sphinx autodoc `_,
which requires manual authoring and uses code imports,
AutoAPI finds and generates documentation by parsing source code.
For more information, see `the full documentation `_.
Getting Started
---------------
The following steps will walk through how to add AutoAPI to an existing Sphinx project.
For instructions on how to set up a Sphinx project,
see `Sphinx's documentation `_.
Installation
~~~~~~~~~~~~
AutoAPI can be installed through pip:
.. code-block:: bash
pip install sphinx-autoapi
Next, add and configure AutoAPI in your Sphinx project's `conf.py`.
.. code-block:: python
extensions.append('autoapi.extension')
autoapi_dirs = ['path/to/source/files', 'src']
When the documentation is built,
AutoAPI will now generate API documentation into an `autoapi/` directory
and add an entry to the documentation in your top level table of contents!
To configure AutoAPI behaviour further,
see the `Configuration documentation `_.
Contributing
------------
Running the tests
~~~~~~~~~~~~~~~~~
Tests are executed through `tox `_.
.. code-block:: bash
tox
Code Style
~~~~~~~~~~
Code is formatted using `black `_.
You can check your formatting using black's check mode:
.. code-block:: bash
tox -e format
You can also get black to format your changes for you:
.. code-block:: bash
black autoapi/ tests/
You can even get black to format changes automatically when you commit using `pre-commit `_:
.. code-block:: bash
pip install pre-commit
pre-commit install
Release Notes
~~~~~~~~~~~~~
Release notes are managed through `towncrier `_.
When making a pull request you will need to create a news fragment to document your change:
.. code-block:: bash
tox -e release_notes -- create --help
Versioning
----------
We use `SemVer `_ for versioning. For the versions available, see the `tags on this repository `_.
License
-------
This project is licensed under the MIT License.
See the `LICENSE.rst `_ file for details.
sphinx-autoapi-3.3.3/autoapi/ 0000775 0000000 0000000 00000000000 14707035566 0016150 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/autoapi/__init__.py 0000664 0000000 0000000 00000000174 14707035566 0020263 0 ustar 00root root 0000000 0000000 """Sphinx AutoAPI"""
from .extension import setup
__all__ = ("setup",)
__version__ = "3.3.3"
__version_info__ = (3, 3, 3)
sphinx-autoapi-3.3.3/autoapi/_astroid_utils.py 0000664 0000000 0000000 00000051304 14707035566 0021551 0 ustar 00root root 0000000 0000000 from __future__ import annotations
import builtins
from collections.abc import Iterable
import itertools
import re
import sys
from typing import Any, NamedTuple
import astroid
import astroid.nodes
if sys.version_info < (3, 10): # PY310
from stdlib_list import in_stdlib
else:
def in_stdlib(module_name: str) -> bool:
return module_name in sys.stdlib_module_names
class ArgInfo(NamedTuple):
prefix: str | None
name: str | None
annotation: str | None
default_value: str | None
def resolve_import_alias(
name: str, import_names: Iterable[tuple[str, str | None]]
) -> str:
"""Resolve a name from an aliased import to its original name.
Args:
name: The potentially aliased name to resolve.
import_names: The pairs of original names and aliases from the import.
Returns:
The original name.
"""
resolved_name = name
for import_name, imported_as in import_names:
if import_name == name:
break
if imported_as == name:
resolved_name = import_name
break
return resolved_name
def get_full_import_name(import_from: astroid.nodes.ImportFrom, name: str) -> str:
"""Get the full path of a name from a ``from x import y`` statement.
Args:
import_from: The astroid node to resolve the name of.
name: The short name or alias of what was imported.
This is ``y`` in ``from x import y``
and ``z`` in ``from x import y as z``.
Returns:
str: The full import path of the name.
"""
partial_basename = resolve_import_alias(name, import_from.names)
module_name = import_from.modname
if import_from.level:
module = import_from.root()
assert isinstance(module, astroid.nodes.Module)
module_name = module.relative_to_absolute_name(
import_from.modname, level=import_from.level
)
return f"{module_name}.{partial_basename}"
def resolve_qualname(node: astroid.nodes.NodeNG, basename: str) -> str:
"""Resolve where a node is defined to get its fully qualified name.
Args:
node: The node representing the base name.
basename: The partial base name to resolve.
Returns:
The fully resolved base name.
"""
full_basename = basename
top_level_name = re.sub(r"\(.*\)", "", basename).split(".", 1)[0]
if isinstance(node, astroid.nodes.LocalsDictNodeNG):
lookup_node = node
else:
lookup_node = node.scope()
assigns = lookup_node.lookup(top_level_name)[1]
for assignment in assigns:
if isinstance(assignment, astroid.nodes.ImportFrom):
import_name = get_full_import_name(assignment, top_level_name)
full_basename = basename.replace(top_level_name, import_name, 1)
break
if isinstance(assignment, astroid.nodes.Import):
import_name = resolve_import_alias(top_level_name, assignment.names)
full_basename = basename.replace(top_level_name, import_name, 1)
break
if isinstance(assignment, astroid.nodes.ClassDef):
full_basename = assignment.qname()
break
if isinstance(assignment, astroid.nodes.AssignName):
full_basename = f"{assignment.scope().qname()}.{assignment.name}"
if isinstance(node, astroid.nodes.Call):
full_basename = re.sub(r"\(.*\)", "()", full_basename)
if full_basename.startswith("builtins."):
return full_basename[len("builtins.") :]
if full_basename.startswith("__builtin__."):
return full_basename[len("__builtin__.") :]
return full_basename
def get_full_basenames(node: astroid.nodes.ClassDef) -> Iterable[str]:
"""Resolve the partial names of a class' bases to fully qualified names.
Args:
node: The class definition node to resolve the bases of.
Returns:
The fully qualified names.
"""
for base in node.bases:
yield _resolve_annotation(base)
def _get_const_value(node: astroid.nodes.NodeNG) -> str | None:
if isinstance(node, astroid.nodes.Const):
if isinstance(node.value, str) and "\n" in node.value:
return f'"""{node.value}"""'
class NotConstException(Exception):
pass
def _inner(node: astroid.nodes.NodeNG) -> Any:
if isinstance(node, (astroid.nodes.List, astroid.nodes.Tuple)):
new_value = []
for element in node.elts:
new_value.append(_inner(element))
if isinstance(node, astroid.nodes.Tuple):
return tuple(new_value)
return new_value
elif isinstance(node, astroid.nodes.Const):
# Don't allow multi-line strings inside a data structure.
if isinstance(node.value, str) and "\n" in node.value:
raise NotConstException()
return node.value
raise NotConstException()
try:
result = _inner(node)
except NotConstException:
return None
return repr(result)
def get_assign_value(
node: astroid.nodes.Assign | astroid.nodes.AnnAssign,
) -> tuple[str, str | None] | None:
"""Get the name and value of the assignment of the given node.
Assignments to multiple names are ignored, as per PEP 257.
Args:
node: The node to get the assignment value from.
Returns:
The name that is assigned to, and the string representation of
the value assigned to the name (if it can be converted).
"""
try:
targets = node.targets
except AttributeError:
targets = [node.target]
if len(targets) == 1:
target = targets[0]
if isinstance(target, astroid.nodes.AssignName):
name = target.name
elif isinstance(target, astroid.nodes.AssignAttr):
name = target.attrname
else:
return None
return (name, _get_const_value(node.value))
return None
def get_assign_annotation(
node: astroid.nodes.Assign | astroid.nodes.AnnAssign,
) -> str | None:
"""Get the type annotation of the assignment of the given node.
Args:
node: The node to get the annotation for.
Returns:
The type annotation as a string, or None if one does not exist.
"""
annotation_node = None
try:
annotation_node = node.annotation
except AttributeError:
annotation_node = node.type_annotation
return format_annotation(annotation_node)
def is_decorated_with_property(node: astroid.nodes.FunctionDef) -> bool:
"""Check if the function is decorated as a property.
Args:
node: The node to check.
Returns:
True if the function is a property, False otherwise.
"""
if not node.decorators:
return False
for decorator in node.decorators.nodes:
if not isinstance(decorator, astroid.nodes.Name):
continue
try:
if _is_property_decorator(decorator):
return True
except astroid.InferenceError:
pass
return False
def _is_property_decorator(decorator: astroid.nodes.Name) -> bool:
def _is_property_class(class_node: astroid.nodes.ClassDef) -> bool:
return (
class_node.name == "property"
and class_node.root().name == builtins.__name__
) or (
class_node.name == "cached_property"
and class_node.root().name == "functools"
)
for inferred in decorator.infer():
if not isinstance(inferred, astroid.nodes.ClassDef):
continue
if _is_property_class(inferred):
return True
if any(_is_property_class(ancestor) for ancestor in inferred.ancestors()):
return True
return False
def is_decorated_with_property_setter(node: astroid.nodes.FunctionDef) -> bool:
"""Check if the function is decorated as a property setter.
Args:
node: The node to check.
Returns:
True if the function is a property setter, False otherwise.
"""
if not node.decorators:
return False
for decorator in node.decorators.nodes:
if (
isinstance(decorator, astroid.nodes.Attribute)
and decorator.attrname == "setter"
):
return True
return False
def is_decorated_with_overload(node: astroid.nodes.FunctionDef) -> bool:
"""Check if the function is decorated as an overload definition.
Args:
node: The node to check.
Returns:
True if the function is an overload definition, False otherwise.
"""
if not node.decorators:
return False
for decorator in node.decorators.nodes:
if not isinstance(decorator, (astroid.nodes.Name, astroid.nodes.Attribute)):
continue
try:
if _is_overload_decorator(decorator):
return True
except astroid.InferenceError:
pass
return False
def _is_overload_decorator(
decorator: astroid.nodes.Name | astroid.nodes.Attribute,
) -> bool:
for inferred in decorator.infer():
if not isinstance(inferred, astroid.nodes.FunctionDef):
continue
if inferred.name == "overload" and inferred.root().name == "typing":
return True
return False
def is_constructor(node: astroid.nodes.FunctionDef) -> bool:
"""Check if the function is a constructor.
Args:
node: The node to check.
Returns:
True if the function is a constructor, False otherwise.
"""
return (
node.parent
and isinstance(node.parent.scope(), astroid.nodes.ClassDef)
and node.name == "__init__"
)
def is_exception(node: astroid.nodes.ClassDef) -> bool:
"""Check if a class is an exception.
Args:
node: The node to check.
Returns:
True if the class is an exception, False otherwise.
"""
if node.name in ("Exception", "BaseException") and node.root().name == "builtins":
return True
if not hasattr(node, "ancestors"):
return False
return any(is_exception(parent) for parent in node.ancestors(recurs=True))
def is_local_import_from(node: astroid.nodes.NodeNG, package_name: str) -> bool:
"""Check if a node is an import from the local package.
Args:
node: The node to check.
package_name: The name of the local package.
Returns:
True if the node is an import from the local package. False otherwise.
"""
if not isinstance(node, astroid.nodes.ImportFrom):
return False
return (
node.level
or node.modname == package_name
or node.modname.startswith(package_name + ".")
)
def get_module_all(node: astroid.nodes.Module) -> list[str] | None:
"""Get the contents of the ``__all__`` variable from a module.
Args:
node: The module to get ``__all__`` from.
Returns:
The contents of ``__all__`` if defined. Otherwise ``None``.
"""
all_ = None
if "__all__" in node.locals:
assigned = next(node.igetattr("__all__"))
if assigned is not astroid.Uninferable:
all_ = []
for elt in getattr(assigned, "elts", ()):
try:
elt_name = next(elt.infer())
except astroid.InferenceError:
continue
if elt_name is astroid.Uninferable:
continue
if isinstance(elt_name, astroid.nodes.Const) and isinstance(
elt_name.value, str
):
all_.append(elt_name.value)
return all_
def _is_ellipsis(node: astroid.nodes.NodeNG) -> bool:
return isinstance(node, astroid.nodes.Const) and node.value == Ellipsis
def merge_annotations(
annotations: Iterable[astroid.nodes.NodeNG],
comment_annotations: Iterable[astroid.nodes.NodeNG],
) -> Iterable[astroid.nodes.NodeNG | None]:
for ann, comment_ann in itertools.zip_longest(annotations, comment_annotations):
if ann and not _is_ellipsis(ann):
yield ann
elif comment_ann and not _is_ellipsis(comment_ann):
yield comment_ann
else:
yield None
def _resolve_annotation(annotation: astroid.nodes.NodeNG) -> str:
resolved: str
if isinstance(annotation, astroid.nodes.Const):
resolved = resolve_qualname(annotation, str(annotation.value))
elif isinstance(annotation, astroid.nodes.Name):
resolved = resolve_qualname(annotation, annotation.name)
elif isinstance(annotation, astroid.nodes.Attribute):
resolved = resolve_qualname(annotation, annotation.as_string())
elif isinstance(annotation, astroid.nodes.Subscript):
value = _resolve_annotation(annotation.value)
slice_node = annotation.slice
# astroid.Index was removed in astroid v3
if hasattr(astroid.nodes, "Index") and isinstance(
slice_node, astroid.nodes.Index
):
slice_node = slice_node.value
if value == "Literal":
if isinstance(slice_node, astroid.nodes.Tuple):
elts = slice_node.elts
else:
elts = [slice_node]
slice_ = ", ".join(
(
elt.as_string()
if isinstance(elt, astroid.nodes.Const)
else _resolve_annotation(elt)
)
for elt in elts
)
elif isinstance(slice_node, astroid.nodes.Tuple):
slice_ = ", ".join(_resolve_annotation(elt) for elt in slice_node.elts)
else:
slice_ = _resolve_annotation(slice_node)
resolved = f"{value}[{slice_}]"
elif isinstance(annotation, astroid.nodes.Tuple):
resolved = (
"(" + ", ".join(_resolve_annotation(elt) for elt in annotation.elts) + ")"
)
elif isinstance(annotation, astroid.nodes.List):
resolved = (
"[" + ", ".join(_resolve_annotation(elt) for elt in annotation.elts) + "]"
)
elif isinstance(annotation, astroid.nodes.BinOp) and annotation.op == "|":
left = _resolve_annotation(annotation.left)
right = _resolve_annotation(annotation.right)
resolved = f"{left} | {right}"
else:
resolved = annotation.as_string()
if resolved.startswith("typing."):
return resolved[len("typing.") :]
# Sphinx is capable of linking anything in the same module
# without needing a fully qualified path.
module_prefix = annotation.root().name + "."
if resolved.startswith(module_prefix):
return resolved[len(module_prefix) :]
return resolved
def format_annotation(annotation: astroid.nodes.NodeNG | None) -> str | None:
if annotation:
return _resolve_annotation(annotation)
return annotation
def _iter_args(
args: list[astroid.nodes.AssignName],
annotations: list[astroid.nodes.NodeNG | None],
defaults: list[astroid.nodes.NodeNG],
) -> Iterable[tuple[str, str | None, str | None]]:
default_offset = len(args) - len(defaults)
packed = itertools.zip_longest(args, annotations)
for i, (arg, annotation) in enumerate(packed):
default = None
if defaults is not None and i >= default_offset:
if defaults[i - default_offset] is not None:
default = defaults[i - default_offset].as_string()
name = arg.name
if isinstance(arg, astroid.nodes.Tuple):
argument_names = ", ".join(x.name for x in arg.elts)
name = f"({argument_names})"
yield (name, format_annotation(annotation), default)
def get_args_info(args_node: astroid.nodes.Arguments) -> list[ArgInfo]:
result: list[ArgInfo] = []
positional_only_defaults = []
positional_or_keyword_defaults = args_node.defaults
if args_node.defaults:
args = args_node.args or []
positional_or_keyword_defaults = args_node.defaults[-len(args) :]
positional_only_defaults = args_node.defaults[
: len(args_node.defaults) - len(args)
]
plain_annotations = args_node.annotations or ()
func_comment_annotations = args_node.parent.type_comment_args or []
if args_node.parent.type in ("method", "classmethod"):
func_comment_annotations = [None] + func_comment_annotations
comment_annotations = args_node.type_comment_posonlyargs
comment_annotations += args_node.type_comment_args or []
comment_annotations += args_node.type_comment_kwonlyargs
annotations = list(
merge_annotations(
plain_annotations,
merge_annotations(func_comment_annotations, comment_annotations),
)
)
annotation_offset = 0
if args_node.posonlyargs:
posonlyargs_annotations = args_node.posonlyargs_annotations
if not any(args_node.posonlyargs_annotations):
num_args = len(args_node.posonlyargs)
posonlyargs_annotations = annotations[
annotation_offset : annotation_offset + num_args
]
for arg, annotation, default in _iter_args(
args_node.posonlyargs, posonlyargs_annotations, positional_only_defaults
):
result.append(ArgInfo(None, arg, annotation, default))
result.append(ArgInfo("/", None, None, None))
if not any(args_node.posonlyargs_annotations):
annotation_offset += num_args
if args_node.args:
num_args = len(args_node.args)
for arg, annotation, default in _iter_args(
args_node.args,
annotations[annotation_offset : annotation_offset + num_args],
positional_or_keyword_defaults,
):
result.append(ArgInfo(None, arg, annotation, default))
annotation_offset += num_args
if args_node.vararg:
annotation = None
if args_node.varargannotation:
annotation = format_annotation(args_node.varargannotation)
elif len(annotations) > annotation_offset and annotations[annotation_offset]:
annotation = format_annotation(annotations[annotation_offset])
annotation_offset += 1
result.append(ArgInfo("*", args_node.vararg, annotation, None))
if args_node.kwonlyargs:
if not args_node.vararg:
result.append(ArgInfo("*", None, None, None))
kwonlyargs_annotations = args_node.kwonlyargs_annotations
if not any(args_node.kwonlyargs_annotations):
num_args = len(args_node.kwonlyargs)
kwonlyargs_annotations = annotations[
annotation_offset : annotation_offset + num_args
]
for arg, annotation, default in _iter_args(
args_node.kwonlyargs,
kwonlyargs_annotations,
args_node.kw_defaults,
):
result.append(ArgInfo(None, arg, annotation, default))
if not any(args_node.kwonlyargs_annotations):
annotation_offset += num_args
if args_node.kwarg:
annotation = None
if args_node.kwargannotation:
annotation = format_annotation(args_node.kwargannotation)
elif len(annotations) > annotation_offset and annotations[annotation_offset]:
annotation = format_annotation(annotations[annotation_offset])
annotation_offset += 1
result.append(ArgInfo("**", args_node.kwarg, annotation, None))
if args_node.parent.type in ("method", "classmethod") and result:
result.pop(0)
return result
def get_return_annotation(node: astroid.nodes.FunctionDef) -> str | None:
"""Get the return annotation of a node.
Args:
node: The node to get the return annotation for.
Returns:
The return annotation of the given node.
"""
return_annotation = None
if node.returns:
return_annotation = format_annotation(node.returns)
elif node.type_comment_returns:
return_annotation = format_annotation(node.type_comment_returns)
return return_annotation
def get_class_docstring(node: astroid.nodes.ClassDef) -> str:
"""Get the docstring of a node, using a parent docstring if needed.
Args:
node: The node to get a docstring for.
Returns:
The docstring of the class, or the empty string if no docstring
was found or defined.
"""
doc = node.doc_node.value if node.doc_node else ""
if not doc:
for base in node.ancestors():
if base.qname() in (
"__builtins__.object",
"builtins.object",
"builtins.type",
):
continue
if base.doc_node is not None:
return base.doc_node.value
return doc
def is_abstract_class(node: astroid.nodes.ClassDef) -> bool:
metaclass = node.metaclass()
if metaclass and metaclass.name == "ABCMeta":
return True
if "abc.ABC" in node.basenames:
return True
if any(method.is_abstract(pass_is_abstract=False) for method in node.methods()):
return True
return False
sphinx-autoapi-3.3.3/autoapi/_mapper.py 0000664 0000000 0000000 00000055506 14707035566 0020160 0 ustar 00root root 0000000 0000000 import collections
import copy
import fnmatch
import itertools
import operator
import os
import re
import sys
from jinja2 import Environment, FileSystemLoader
import sphinx
import sphinx.environment
from sphinx.errors import ExtensionError
import sphinx.util
import sphinx.util.logging
from sphinx.util.console import colorize
from sphinx.util.display import status_iterator
import sphinx.util.docstrings
from sphinx.util.osutil import ensuredir
from ._parser import Parser
from ._objects import (
PythonClass,
PythonFunction,
PythonModule,
PythonMethod,
PythonPackage,
PythonProperty,
PythonAttribute,
PythonData,
PythonException,
)
from .settings import OWN_PAGE_LEVELS, TEMPLATE_DIR
if sys.version_info < (3, 10): # PY310
from stdlib_list import in_stdlib
else:
def in_stdlib(module_name: str) -> bool:
return module_name in sys.stdlib_module_names
LOGGER = sphinx.util.logging.getLogger(__name__)
def _expand_wildcard_placeholder(original_module, originals_map, placeholder):
"""Expand a wildcard placeholder to a sequence of named placeholders.
:param original_module: The data dictionary of the module
that the placeholder is imported from.
:type original_module: dict
:param originals_map: A map of the names of children under the module
to their data dictionaries.
:type originals_map: dict(str, dict)
:param placeholder: The wildcard placeholder to expand.
:type placeholder: dict
:returns: The placeholders that the wildcard placeholder represents.
:rtype: list(dict)
"""
originals = originals_map.values()
if original_module["all"] is not None:
originals = []
for name in original_module["all"]:
if name == "__all__":
continue
if name not in originals_map:
msg = f"Invalid __all__ entry {name} in {original_module['name']}"
LOGGER.warning(msg, type="autoapi", subtype="python_import_resolution")
continue
originals.append(originals_map[name])
placeholders = []
for original in originals:
new_full_name = placeholder["full_name"].replace("*", original["name"])
new_qual_name = placeholder["qual_name"].replace("*", original["name"])
new_original_path = placeholder["original_path"].replace("*", original["name"])
if "original_path" in original:
new_original_path = original["original_path"]
new_placeholder = dict(
placeholder,
name=original["name"],
qual_name=new_qual_name,
full_name=new_full_name,
original_path=new_original_path,
)
placeholders.append(new_placeholder)
return placeholders
def _resolve_module_placeholders(modules, module_name, visit_path, resolved):
"""Resolve all placeholder children under a module.
Args:
modules (dict(str, dict)): A mapping of module names to their
data dictionary. Placeholders are resolved in place.
module_name (str): The name of the module to resolve.
visit_path: An ordered set of visited module names.
visited (collections.OrderedDict)
resolved (set(str)): A set of already resolved module names.
"""
if module_name in resolved:
return
visit_path[module_name] = True
module, children = modules[module_name]
for child in list(children.values()):
if child["type"] != "placeholder":
continue
if child["original_path"] in modules:
module["children"].remove(child)
children.pop(child["name"])
continue
imported_from, original_name = child["original_path"].rsplit(".", 1)
if imported_from in visit_path:
visit_str = ", ".join(visit_path)
msg = f"Cannot resolve cyclic import: {visit_str}, {imported_from}"
LOGGER.warning(msg, type="autoapi", subtype="python_import_resolution")
module["children"].remove(child)
children.pop(child["name"])
continue
if imported_from not in modules:
msg = (
f"Cannot resolve import of unknown module {imported_from}"
f" in {module_name}"
)
LOGGER.warning(msg, type="autoapi", subtype="python_import_resolution")
module["children"].remove(child)
children.pop(child["name"])
continue
_resolve_module_placeholders(modules, imported_from, visit_path, resolved)
if original_name == "*":
original_module, originals_map = modules[imported_from]
# Replace the wildcard placeholder
# with a list of named placeholders.
new_placeholders = _expand_wildcard_placeholder(
original_module, originals_map, child
)
child_index = module["children"].index(child)
module["children"][child_index : child_index + 1] = new_placeholders
children.pop(child["name"])
for new_placeholder in new_placeholders:
if new_placeholder["name"] not in children:
children[new_placeholder["name"]] = new_placeholder
original = originals_map[new_placeholder["name"]]
_resolve_placeholder(new_placeholder, original)
elif original_name not in modules[imported_from][1]:
msg = f"Cannot resolve import of {child['original_path']} in {module_name}"
LOGGER.warning(msg, type="autoapi", subtype="python_import_resolution")
module["children"].remove(child)
children.pop(child["name"])
continue
else:
original = modules[imported_from][1][original_name]
_resolve_placeholder(child, original)
del visit_path[module_name]
resolved.add(module_name)
def _resolve_placeholder(placeholder, original):
"""Resolve a placeholder to the given original object.
Args:
placeholder (dict): The placeholder to resolve, in place.
original (dict): The object that the placeholder represents.
"""
new = copy.deepcopy(original)
# We are supposed to be resolving the placeholder,
# not replacing it with another.
assert original["type"] != "placeholder"
# The name remains the same.
new["name"] = placeholder["name"]
new["qual_name"] = placeholder["qual_name"]
new["full_name"] = placeholder["full_name"]
# Record where the placeholder originally came from.
new["original_path"] = original["full_name"]
# The source lines for this placeholder do not exist in this file.
# The keys might not exist if original is a resolved placeholder.
new.pop("from_line_no", None)
new.pop("to_line_no", None)
# Resolve the children
stack = list(new.get("children", ()))
while stack:
child = stack.pop()
# Relocate the child to the new location
assert child["full_name"].startswith(original["full_name"])
suffix = child["full_name"][len(original["full_name"]) :]
child["full_name"] = new["full_name"] + suffix
# The source lines for this placeholder do not exist in this file.
# The keys might not exist if original is a resolved placeholder.
child.pop("from_line_no", None)
child.pop("to_line_no", None)
# Resolve the remaining children
stack.extend(child.get("children", ()))
placeholder.clear()
placeholder.update(new)
def _link_objs(value):
result = ""
delims = r"(\s*[\[\]\(\),]\s*)"
delims_re = re.compile(delims)
sub_targets = re.split(delims, value.strip())
for sub_target in sub_targets:
sub_target = sub_target.strip()
if delims_re.match(sub_target):
result += f"{sub_target}"
if sub_target.endswith(","):
result += " "
else:
result += "\\ "
elif sub_target:
result += f":py:obj:`{sub_target}`\\ "
# Strip off the extra "\ "
return result[:-2]
class Mapper:
"""Base class for mapping `PythonMapperBase` objects to Sphinx.
Args:
app: Sphinx application instance
"""
_OBJ_MAP = {
cls.type: cls
for cls in (
PythonClass,
PythonFunction,
PythonModule,
PythonMethod,
PythonPackage,
PythonProperty,
PythonAttribute,
PythonData,
PythonException,
)
}
def __init__(self, app, template_dir=None, dir_root=None, url_root=None):
self.app = app
template_paths = [TEMPLATE_DIR]
if template_dir:
# Put at the front so it's loaded first
template_paths.insert(0, template_dir)
self.jinja_env = Environment(
loader=FileSystemLoader(template_paths),
trim_blocks=True,
lstrip_blocks=True,
)
def _wrapped_prepare(value):
return value
self.jinja_env.filters["prepare_docstring"] = _wrapped_prepare
if self.app.config.autoapi_prepare_jinja_env:
self.app.config.autoapi_prepare_jinja_env(self.jinja_env)
own_page_level = self.app.config.autoapi_own_page_level
desired_page_level = OWN_PAGE_LEVELS.index(own_page_level)
self.own_page_types = set(OWN_PAGE_LEVELS[: desired_page_level + 1])
self.dir_root = dir_root
self.url_root = url_root
# Mapping of {filepath -> raw data}
self.paths = collections.OrderedDict()
# Mapping of {object id -> Python Object}
self.objects_to_render = collections.OrderedDict()
# Mapping of {object id -> Python Object}
self.all_objects = collections.OrderedDict()
# Mapping of {namespace id -> Python Object}
self.namespaces = collections.OrderedDict()
self.jinja_env.filters["link_objs"] = _link_objs
self._use_implicit_namespace = (
self.app.config.autoapi_python_use_implicit_namespaces
)
@staticmethod
def find_files(patterns, dirs, ignore):
if not ignore:
ignore = []
pattern_regexes = []
for pattern in patterns:
regex = re.compile(fnmatch.translate(pattern).replace(".*", "(.*)"))
pattern_regexes.append((pattern, regex))
for _dir in dirs:
for root, _, filenames in os.walk(_dir):
seen = set()
for pattern, pattern_re in pattern_regexes:
for filename in fnmatch.filter(filenames, pattern):
skip = False
match = re.match(pattern_re, filename)
norm_name = match.groups()
if norm_name in seen:
continue
# Skip ignored files
for ignore_pattern in ignore:
if fnmatch.fnmatch(
os.path.join(root, filename), ignore_pattern
):
LOGGER.info(
colorize("bold", "[AutoAPI] ")
+ colorize(
"darkgreen", f"Ignoring {root}/{filename}"
)
)
skip = True
if skip:
continue
# Make sure the path is full
if not os.path.isabs(filename):
filename = os.path.join(root, filename)
yield filename
seen.add(norm_name)
def output_rst(self, source_suffix):
for _, obj in status_iterator(
self.objects_to_render.items(),
colorize("bold", "[AutoAPI] ") + "Rendering Data... ",
length=len(self.objects_to_render),
verbosity=1,
stringify_func=(lambda x: x[0]),
):
rst = obj.render(is_own_page=True)
if not rst:
continue
output_dir = obj.output_dir(self.dir_root)
ensuredir(output_dir)
output_path = output_dir / obj.output_filename()
path = f"{output_path}{source_suffix}"
with open(path, "wb+") as detail_file:
detail_file.write(rst.encode("utf-8"))
if self.app.config.autoapi_add_toctree_entry:
self._output_top_rst()
def _output_top_rst(self):
# Render Top Index
top_level_index = os.path.join(self.dir_root, "index.rst")
pages = [obj for obj in self.objects_to_render.values() if obj.display]
if not pages:
msg = (
"No modules were rendered. "
"Do you need to set autoapi_options to render additional objects?"
)
LOGGER.warning(msg, type="autoapi", subtype="nothing_rendered")
return
with open(top_level_index, "wb") as top_level_file:
content = self.jinja_env.get_template("index.rst")
top_level_file.write(content.render(pages=pages).encode("utf-8"))
def _need_to_load(self, files):
last_files = getattr(self.app.env, "autoapi_source_files", [])
self.app.env.autoapi_source_files = files
last_mtime = getattr(self.app.env, "autoapi_max_mtime", 0)
this_mtime = max(os.path.getmtime(file) for _, file in files)
self.app.env.autoapi_max_mtime = this_mtime
if not self.app.config.autoapi_keep_files:
return True
if self.app.env.config_status != sphinx.environment.CONFIG_OK:
return True
return last_files != files or not last_mtime or last_mtime < this_mtime
def _find_files(self, patterns, dirs, ignore):
for dir_ in dirs:
dir_root = dir_
if (
os.path.exists(os.path.join(dir_, "__init__.py"))
or os.path.exists(os.path.join(dir_, "__init__.pyi"))
or self._use_implicit_namespace
):
dir_root = os.path.abspath(os.path.join(dir_, os.pardir))
for path in self.find_files(patterns=patterns, dirs=[dir_], ignore=ignore):
yield dir_root, path
def load(self, patterns, dirs, ignore=None):
"""Load objects from the filesystem into the ``paths`` dictionary
Also include an attribute on the object, ``relative_path`` which is the
shortened, relative path the package/module
"""
dir_root_files = list(self._find_files(patterns, dirs, ignore))
if not dir_root_files:
raise ExtensionError(f"No source files found in: {','.join(dirs)}")
if not self._need_to_load(dir_root_files):
LOGGER.debug(
"[AutoAPI] Skipping read stage because source files have not changed."
)
return False
for dir_root, path in status_iterator(
dir_root_files,
colorize("bold", "[AutoAPI] Reading files... "),
length=len(dir_root_files),
stringify_func=(lambda x: x[1]),
):
data = self.read_file(path=path, dir_root=dir_root)
if data:
data["relative_path"] = os.path.relpath(path, dir_root)
self.paths[path] = data
return True
def read_file(self, path, **kwargs):
"""Read file input into memory, returning deserialized objects
Args:
path: Path of file to read
"""
dir_root = kwargs.get("dir_root")
try:
if self._use_implicit_namespace:
parsed_data = Parser().parse_file_in_namespace(path, dir_root)
else:
parsed_data = Parser().parse_file(path)
return parsed_data
except (OSError, TypeError, ImportError):
LOGGER.debug("Reason:", exc_info=True)
LOGGER.warning(
f"Unable to read file: {path}",
type="autoapi",
subtype="not_readable",
)
return None
def _skip_if_stdlib(self):
documented_modules = {obj["full_name"] for obj in self.paths.values()}
q = collections.deque(self.paths.values())
while q:
obj = q.popleft()
if "children" in obj:
q.extend(obj["children"])
if obj.get("inherited", False):
module = obj["inherited_from"]["full_name"].split(".", 1)[0]
if (
in_stdlib(module)
and not obj["inherited_from"]["is_abstract"]
and module not in documented_modules
):
obj["hide"] = True
def _resolve_placeholders(self):
"""Resolve objects that have been imported from elsewhere."""
modules = {}
for module in self.paths.values():
children = {child["name"]: child for child in module["children"]}
modules[module["name"]] = (module, children)
resolved = set()
for module_name in modules:
visit_path = collections.OrderedDict()
_resolve_module_placeholders(modules, module_name, visit_path, resolved)
def _hide_yo_kids(self):
"""For all direct children of a module/package, hide them if needed."""
for module in self.paths.values():
if module["all"] is not None:
all_names = set(module["all"])
for child in module["children"]:
if child["qual_name"] not in all_names:
child["hide"] = True
elif module["type"] == "module":
for child in module["children"]:
if "original_path" in child:
child["hide"] = True
def map(self, options=None):
self._skip_if_stdlib()
self._resolve_placeholders()
self._hide_yo_kids()
self.app.env.autoapi_annotations = {}
for _, data in status_iterator(
self.paths.items(),
colorize("bold", "[AutoAPI] ") + "Mapping Data... ",
length=len(self.paths),
stringify_func=(lambda x: x[0]),
):
for obj in self.create_class(data, options=options):
self.all_objects[obj.id] = obj
self._create_module_hierarchy()
self._render_selection()
self.app.env.autoapi_objects = self.objects_to_render
self.app.env.autoapi_all_objects = self.all_objects
def _create_module_hierarchy(self) -> None:
"""Populate the sub{module,package}s attributes of all top level objects."""
for obj in self.all_objects.values():
parent_name = obj.name.rsplit(".", 1)[0]
if parent_name in self.all_objects and parent_name != obj.name:
parent = self.all_objects[parent_name]
attr = f"sub{obj.type}s"
getattr(parent, attr).append(obj)
for obj in self.all_objects.values():
obj.submodules.sort()
obj.subpackages.sort()
def _render_selection(self):
"""Propagate display values to children."""
for obj in sorted(self.all_objects.values(), key=lambda obj: len(obj.id)):
if obj.display:
assert obj.type in self.own_page_types
self.objects_to_render[obj.id] = obj
else:
for module in itertools.chain(obj.subpackages, obj.submodules):
module.obj["hide"] = True
def _inner(parent):
for child in parent.children:
self.all_objects[child.id] = child
if not parent.display:
child.obj["hide"] = True
if child.display and child.type in self.own_page_types:
self.objects_to_render[child.id] = child
_inner(child)
for obj in list(self.all_objects.values()):
_inner(obj)
def create_class(self, data, options=None):
"""Create a class from the passed in data
Args:
data: dictionary data of parser output
"""
try:
cls = self._OBJ_MAP[data["type"]]
except KeyError:
# this warning intentionally has no (sub-)type
LOGGER.warning(f"Unknown type: {data['type']}")
else:
obj = cls(
data,
class_content=self.app.config.autoapi_python_class_content,
options=self.app.config.autoapi_options,
jinja_env=self.jinja_env,
app=self.app,
url_root=self.url_root,
)
for child_data in data.get("children", []):
for child_obj in self.create_class(child_data, options=options):
obj.children.append(child_obj)
# Some objects require children to establish their docstring
# or type annotations (eg classes with inheritance),
# so do this after all children have been created.
lines = obj.docstring.splitlines()
if lines:
# Add back the trailing newline that .splitlines removes
lines.append("")
if "autodoc-process-docstring" in self.app.events.events:
self.app.emit(
"autodoc-process-docstring",
cls.type,
obj.name,
None,
None,
lines,
)
obj.docstring = "\n".join(lines)
self._record_typehints(obj)
# Parser gives children in source order already
if self.app.config.autoapi_member_order == "alphabetical":
obj.children.sort(key=operator.attrgetter("name"))
elif self.app.config.autoapi_member_order == "groupwise":
obj.children.sort(key=lambda x: (x.member_order, x.name))
yield obj
def _record_typehints(self, obj):
if (
isinstance(obj, (PythonClass, PythonFunction, PythonMethod))
and not obj.overloads
) or isinstance(obj, PythonProperty):
obj_annotations = {}
include_return_annotation = True
obj_data = obj.obj
if isinstance(obj, PythonClass):
constructor = obj.constructor
if constructor:
include_return_annotation = False
obj_data = constructor.obj
else:
return
for _, name, annotation, _ in obj_data["args"]:
if name and annotation:
obj_annotations[name] = annotation
return_annotation = obj_data["return_annotation"]
if include_return_annotation and return_annotation:
obj_annotations["return"] = return_annotation
self.app.env.autoapi_annotations[obj.id] = obj_annotations
sphinx-autoapi-3.3.3/autoapi/_objects.py 0000664 0000000 0000000 00000037551 14707035566 0020325 0 ustar 00root root 0000000 0000000 from __future__ import annotations
import functools
import pathlib
import sphinx
import sphinx.util
import sphinx.util.logging
from .settings import OWN_PAGE_LEVELS
LOGGER = sphinx.util.logging.getLogger(__name__)
def _format_args(args_info, include_annotations=True, ignore_self=None):
result = []
for i, (prefix, name, annotation, default) in enumerate(args_info):
if i == 0 and ignore_self is not None and name == ignore_self:
continue
formatted = (
(prefix or "")
+ (name or "")
+ (f": {annotation}" if annotation and include_annotations else "")
+ ((" = {}" if annotation else "={}").format(default) if default else "")
)
result.append(formatted)
return ", ".join(result)
class PythonObject:
"""A class representing an entity from the parsed source code.
This class turns the dictionaries output by the parser into an object.
Args:
obj: JSON object representing this object
jinja_env: A template environment for rendering this object
"""
member_order = 0
"""The ordering of objects when doing "groupwise" sorting."""
type: str
def __init__(
self, obj, jinja_env, app, url_root, options=None, class_content="class"
):
self.app = app
self.obj = obj
self.options = options
self.jinja_env = jinja_env
self.url_root = url_root
self.name: str = obj["name"]
"""The name of the object, as named in the parsed source code.
This name will have no periods in it.
"""
self.qual_name: str = obj["qual_name"]
"""The qualified name for this object."""
self.id: str = obj.get("full_name", self.name)
"""A globally unique identifier for this object.
This is the same as the fully qualified name of the object.
"""
self.children: list[PythonObject] = []
"""The members of this object.
For example, the classes and functions defined in the parent module.
"""
self._docstring: str = obj["doc"]
self.imported: bool = "original_path" in obj
"""Whether this object was imported from another module."""
self.inherited: bool = obj.get("inherited", False)
"""Whether this was inherited from an ancestor of the parent class."""
# For later
self._class_content = class_content
self._display_cache: bool | None = None
def __getstate__(self):
"""Obtains serialisable data for pickling."""
__dict__ = self.__dict__.copy()
__dict__.update(app=None, jinja_env=None) # clear unpickable attributes
return __dict__
def render(self, **kwargs):
LOGGER.log("VERBOSE", "Rendering %s", self.id)
template = self.jinja_env.get_template(f"python/{self.type}.rst")
ctx = {}
ctx.update(**self.get_context_data())
ctx.update(**kwargs)
return template.render(**ctx)
@property
def rendered(self):
"""Shortcut to render an object in templates."""
return self.render()
def get_context_data(self):
own_page_level = self.app.config.autoapi_own_page_level
desired_page_level = OWN_PAGE_LEVELS.index(own_page_level)
own_page_types = set(OWN_PAGE_LEVELS[: desired_page_level + 1])
return {
"autoapi_options": self.app.config.autoapi_options,
"include_summaries": self.app.config.autoapi_include_summaries,
"obj": self,
"own_page_types": own_page_types,
"sphinx_version": sphinx.version_info,
}
def __lt__(self, other):
"""Object sorting comparison"""
if not isinstance(other, PythonObject):
return NotImplemented
return self.id < other.id
def __str__(self) -> str:
return f"<{self.__class__.__name__} {self.id}>"
@property
def short_name(self) -> str:
"""Shorten name property"""
return self.name.split(".")[-1]
def output_dir(self, root):
"""The directory to render this object."""
module = self.id[: -(len("." + self.qual_name))]
parts = [root] + module.split(".")
return pathlib.PurePosixPath(*parts)
def output_filename(self) -> str:
"""The name of the file to render into, without a file suffix."""
filename = self.qual_name
if filename == "index":
filename = ".index"
return filename
@property
def include_path(self) -> str:
"""Return 'absolute' path without regarding OS path separator
This is used in ``toctree`` directives, as Sphinx always expects Unix
path separators
"""
return str(self.output_dir(self.url_root) / self.output_filename())
@property
def docstring(self) -> str:
"""The docstring for this object.
If a docstring did not exist on the object,
this will be the empty string.
For classes, this will also depend on the
:confval:`autoapi_python_class_content` option.
"""
return self._docstring
@docstring.setter
def docstring(self, value: str) -> None:
self._docstring = value
self._docstring_resolved = True
@property
def is_top_level_object(self) -> bool:
"""Whether this object is at the very top level (True) or not (False).
This will be False for subpackages and submodules.
"""
return "." not in self.id
@property
def is_undoc_member(self) -> bool:
"""Whether this object has a docstring (False) or not (True)."""
return not bool(self.docstring)
@property
def is_private_member(self) -> bool:
"""Whether this object is private (True) or not (False)."""
return self.short_name.startswith("_") and not self.short_name.endswith("__")
@property
def is_special_member(self) -> bool:
"""Whether this object is a special member (True) or not (False)."""
return self.short_name.startswith("__") and self.short_name.endswith("__")
@property
def display(self) -> bool:
"""Whether this object should be displayed in documentation.
This attribute depends on the configuration options given in
:confval:`autoapi_options` and the result of :event:`autoapi-skip-member`.
"""
if self._display_cache is None:
self._display_cache = not self._ask_ignore(self._should_skip())
return self._display_cache
@property
def summary(self) -> str:
"""The summary line of the docstring.
The summary line is the first non-empty line, as-per :pep:`257`.
This will be the empty string if the object does not have a docstring.
"""
for line in self.docstring.splitlines():
line = line.strip()
if line:
return line
return ""
def _should_skip(self) -> bool:
skip_undoc_member = self.is_undoc_member and "undoc-members" not in self.options
skip_private_member = (
self.is_private_member and "private-members" not in self.options
)
skip_special_member = (
self.is_special_member and "special-members" not in self.options
)
skip_imported_member = self.imported and "imported-members" not in self.options
skip_inherited_member = (
self.inherited and "inherited-members" not in self.options
)
return (
self.obj.get("hide", False)
or skip_undoc_member
or skip_private_member
or skip_special_member
or skip_imported_member
or skip_inherited_member
)
def _ask_ignore(self, skip: bool) -> bool:
ask_result = self.app.emit_firstresult(
"autoapi-skip-member", self.type, self.id, self, skip, self.options
)
return ask_result if ask_result is not None else skip
def _children_of_type(self, type_: str) -> list[PythonObject]:
return list(child for child in self.children if child.type == type_)
class PythonFunction(PythonObject):
"""The representation of a function."""
type = "function"
member_order = 30
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
autodoc_typehints = getattr(self.app.config, "autodoc_typehints", "signature")
show_annotations = autodoc_typehints != "none" and not (
autodoc_typehints == "description" and not self.obj["overloads"]
)
self.args: str = _format_args(self.obj["args"], show_annotations)
"""The arguments to this object, formatted as a string."""
self.return_annotation: str | None = (
self.obj["return_annotation"] if show_annotations else None
)
"""The type annotation for the return type of this function.
This will be ``None`` if an annotation
or annotation comment was not given.
"""
self.properties: list[str] = self.obj["properties"]
"""The properties that describe what type of function this is.
Can be only be: async.
"""
self.overloads: list[tuple[str, str]] = [
(_format_args(args), return_annotation)
for args, return_annotation in self.obj["overloads"]
]
"""The overloaded signatures of this function.
Each tuple is a tuple of ``(args, return_annotation)``
"""
class PythonMethod(PythonFunction):
"""The representation of a method."""
type = "method"
member_order = 50
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.properties: list[str] = self.obj["properties"]
"""The properties that describe what type of method this is.
Can be any of: abstractmethod, async, classmethod, property, staticmethod.
"""
def _should_skip(self) -> bool:
return super()._should_skip() or self.name in (
"__new__",
"__init__",
)
class PythonProperty(PythonObject):
"""The representation of a property on a class."""
type = "property"
member_order = 60
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.annotation: str | None = self.obj["return_annotation"]
"""The type annotation of this property."""
self.properties: list[str] = self.obj["properties"]
"""The properties that describe what type of property this is.
Can be any of: abstractmethod, classmethod.
"""
class PythonData(PythonObject):
"""Global, module level data."""
type = "data"
member_order = 40
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.value: str | None = self.obj.get("value")
"""The value of this attribute.
This will be ``None`` if the value is not constant.
"""
self.annotation: str | None = self.obj.get("annotation")
"""The type annotation of this attribute.
This will be ``None`` if an annotation
or annotation comment was not given.
"""
class PythonAttribute(PythonData):
"""An object/class level attribute."""
type = "attribute"
member_order = 60
class TopLevelPythonPythonMapper(PythonObject):
"""A common base class for modules and packages."""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.subpackages = []
self.submodules = []
self.all = self.obj["all"]
"""The contents of ``__all__`` if assigned to.
Only constants are included.
This will be ``None`` if no ``__all__`` was set.
:type: list(str) or None
"""
@property
def functions(self):
"""All of the member functions.
:type: list(PythonFunction)
"""
return self._children_of_type("function")
@property
def classes(self):
"""All of the member classes.
:type: list(PythonClass)
"""
return self._children_of_type("class")
def output_dir(self, root):
"""The path to the file to render into, without a file suffix."""
parts = [root] + self.name.split(".")
return pathlib.PurePosixPath(*parts)
def output_filename(self):
"""The path to the file to render into, without a file suffix."""
return "index"
class PythonModule(TopLevelPythonPythonMapper):
"""The representation of a module."""
type = "module"
class PythonPackage(TopLevelPythonPythonMapper):
"""The representation of a package."""
type = "package"
class PythonClass(PythonObject):
"""The representation of a class."""
type = "class"
member_order = 20
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.bases: list[str] = self.obj["bases"]
"""The fully qualified names of all base classes."""
self._docstring_resolved: bool = False
@property
def args(self) -> str:
"""The arguments to this object, formatted as a string."""
args = ""
if self.constructor:
autodoc_typehints = getattr(
self.app.config, "autodoc_typehints", "signature"
)
show_annotations = autodoc_typehints != "none" and not (
autodoc_typehints == "description" and not self.constructor.overloads
)
args_data = self.constructor.obj["args"]
args = _format_args(args_data, show_annotations, ignore_self="self")
return args
@property
def overloads(self) -> list[tuple[str, str]]:
overloads = []
if self.constructor:
overload_data = self.constructor.obj["overloads"]
autodoc_typehints = getattr(
self.app.config, "autodoc_typehints", "signature"
)
show_annotations = autodoc_typehints not in ("none", "description")
overloads = [
(
_format_args(args, show_annotations, ignore_self="self"),
return_annotation,
)
for args, return_annotation in overload_data
]
return overloads
@property
def docstring(self) -> str:
docstring = self._docstring
if not self._docstring_resolved and self._class_content in ("both", "init"):
constructor_docstring = self.constructor_docstring
if constructor_docstring:
if self._class_content == "both":
docstring = f"{docstring}\n{constructor_docstring}"
else:
docstring = constructor_docstring
return docstring
@docstring.setter
def docstring(self, value: str) -> None:
self._docstring = value
self._docstring_resolved = True
@property
def methods(self):
return self._children_of_type("method")
@property
def properties(self):
return self._children_of_type("property")
@property
def attributes(self):
return self._children_of_type("attribute")
@property
def classes(self):
return self._children_of_type("class")
@property
@functools.lru_cache
def constructor(self):
for child in self.children:
if child.short_name == "__init__":
if not child.type == "method":
break
return child
return None
@property
def constructor_docstring(self) -> str:
docstring = ""
constructor = self.constructor
if constructor and constructor.docstring:
docstring = constructor.docstring
else:
for child in self.children:
if child.short_name == "__new__":
docstring = child.docstring
break
return docstring
class PythonException(PythonClass):
"""The representation of an exception class."""
type = "exception"
member_order = 10
sphinx-autoapi-3.3.3/autoapi/_parser.py 0000664 0000000 0000000 00000033367 14707035566 0020171 0 ustar 00root root 0000000 0000000 import collections
import os
import astroid
import astroid.builder
import sphinx.util.docstrings
from . import _astroid_utils
def _prepare_docstring(doc):
return "\n".join(sphinx.util.docstrings.prepare_docstring(doc))
class Parser:
def __init__(self):
self._qual_name_stack = []
self._full_name_stack = []
self._encoding = None
def _get_qual_name(self, name):
return ".".join(self._qual_name_stack + [name])
def _get_full_name(self, name):
return ".".join(self._full_name_stack + [name])
def _parse_file(self, file_path, condition):
directory, filename = os.path.split(file_path)
module_parts = []
if filename != "__init__.py" and filename != "__init__.pyi":
module_part = os.path.splitext(filename)[0]
module_parts = [module_part]
module_parts = collections.deque(module_parts)
while directory and condition(directory):
directory, module_part = os.path.split(directory)
if module_part:
module_parts.appendleft(module_part)
module_name = ".".join(module_parts)
node = astroid.builder.AstroidBuilder().file_build(file_path, module_name)
return self.parse(node)
def parse_file(self, file_path):
return self._parse_file(
file_path,
lambda directory: (
os.path.isfile(os.path.join(directory, "__init__.py"))
or os.path.isfile(os.path.join(directory, "__init__.pyi"))
),
)
def parse_file_in_namespace(self, file_path, dir_root):
return self._parse_file(
file_path, lambda directory: os.path.abspath(directory) != dir_root
)
def parse_annassign(self, node):
# Don't document module level assignments to class attributes
if isinstance(node.target, astroid.nodes.AssignAttr):
return []
return self._parse_assign(node)
def parse_assign(self, node):
# Don't document module level assignments to class attributes
if any(isinstance(target, astroid.nodes.AssignAttr) for target in node.targets):
return []
return self._parse_assign(node)
def _parse_assign(self, node):
doc = ""
doc_node = node.next_sibling()
if isinstance(doc_node, astroid.nodes.Expr) and isinstance(
doc_node.value, astroid.nodes.Const
):
doc = doc_node.value.value
type_ = "data"
if isinstance(
node.scope(), astroid.nodes.ClassDef
) or _astroid_utils.is_constructor(node.scope()):
type_ = "attribute"
assign_value = _astroid_utils.get_assign_value(node)
if not assign_value:
return []
target = assign_value[0]
value = assign_value[1]
annotation = _astroid_utils.get_assign_annotation(node)
if annotation in ("TypeAlias", "typing.TypeAlias"):
value = node.value.as_string()
data = {
"type": type_,
"name": target,
"qual_name": self._get_qual_name(target),
"full_name": self._get_full_name(target),
"doc": _prepare_docstring(doc),
"value": value,
"from_line_no": node.fromlineno,
"to_line_no": node.tolineno,
"annotation": annotation,
}
return [data]
def _parse_classdef(self, node, use_name_stacks):
if use_name_stacks:
qual_name = self._get_qual_name(node.name)
full_name = self._get_full_name(node.name)
self._qual_name_stack.append(node.name)
self._full_name_stack.append(node.name)
else:
qual_name = node.qname()[len(node.root().qname()) + 1 :]
full_name = node.qname()
type_ = "class"
if _astroid_utils.is_exception(node):
type_ = "exception"
data = {
"type": type_,
"name": node.name,
"qual_name": qual_name,
"full_name": full_name,
"bases": list(_astroid_utils.get_full_basenames(node)),
"doc": _prepare_docstring(_astroid_utils.get_class_docstring(node)),
"from_line_no": node.fromlineno,
"to_line_no": node.tolineno,
"children": [],
"is_abstract": _astroid_utils.is_abstract_class(node),
}
overloads = {}
for child in node.get_children():
children_data = self.parse(child)
for child_data in children_data:
if _parse_child(child_data, overloads):
data["children"].append(child_data)
data["children"] = list(self._resolve_inheritance(data))
return data
def _resolve_inheritance(self, *mro_data):
overridden = set()
children = {}
for i, cls_data in enumerate(mro_data):
seen = set()
base_children = []
overloads = {}
for child_data in cls_data["children"]:
name = child_data["name"]
existing_child = children.get(name)
if existing_child and not existing_child["doc"]:
existing_child["doc"] = child_data["doc"]
if name in overridden:
continue
seen.add(name)
if _parse_child(child_data, overloads):
base_children.append(child_data)
child_data["inherited"] = i != 0
if child_data["inherited"]:
child_data["inherited_from"] = cls_data
overridden.update(seen)
for base_child in base_children:
existing_child = children.get(base_child["name"])
if (
existing_child
# If an attribute was assigned to but this class has a property
# with the same name, then the property was assigned to,
# and not an attribute.
and not (
base_child["type"] == "property"
and existing_child["type"] == "attribute"
)
):
continue
children[base_child["name"]] = base_child
return children.values()
def _relevant_ancestors(self, node):
for base in node.ancestors():
if base.qname() in (
"__builtins__.object",
"builtins.object",
"builtins.type",
):
continue
yield base
def parse_classdef(self, node):
data = self._parse_classdef(node, use_name_stacks=True)
ancestors = self._relevant_ancestors(node)
ancestor_data = [
self._parse_classdef(base, use_name_stacks=False) for base in ancestors
]
if ancestor_data:
data["children"] = list(self._resolve_inheritance(data, *ancestor_data))
self._qual_name_stack.pop()
self._full_name_stack.pop()
return [data]
def parse_asyncfunctiondef(self, node):
return self.parse_functiondef(node)
def parse_functiondef(self, node):
if _astroid_utils.is_decorated_with_property_setter(node):
return []
type_ = "method"
properties = []
if node.type == "function":
type_ = "function"
if isinstance(node, astroid.AsyncFunctionDef):
properties.append("async")
elif _astroid_utils.is_decorated_with_property(node):
type_ = "property"
if node.type == "classmethod":
properties.append(node.type)
if node.is_abstract(pass_is_abstract=False):
properties.append("abstractmethod")
else:
# "__new__" method is implicit classmethod
if node.type in ("staticmethod", "classmethod") and node.name != "__new__":
properties.append(node.type)
if node.is_abstract(pass_is_abstract=False):
properties.append("abstractmethod")
if isinstance(node, astroid.AsyncFunctionDef):
properties.append("async")
data = {
"type": type_,
"name": node.name,
"qual_name": self._get_qual_name(node.name),
"full_name": self._get_full_name(node.name),
"args": _astroid_utils.get_args_info(node.args),
"doc": _prepare_docstring(node.doc_node.value if node.doc_node else ""),
"from_line_no": node.fromlineno,
"to_line_no": node.tolineno,
"return_annotation": _astroid_utils.get_return_annotation(node),
"properties": properties,
"is_overload": _astroid_utils.is_decorated_with_overload(node),
"overloads": [],
}
result = [data]
if node.name == "__init__":
for child in node.get_children():
if isinstance(child, (astroid.nodes.Assign, astroid.nodes.AnnAssign)):
# Verify we are assigning to self.
if isinstance(child, astroid.nodes.Assign):
targets = child.targets
else:
targets = [child.target]
target_ok = True
for target in targets:
if not isinstance(target, astroid.nodes.AssignAttr):
target_ok = False
break
_object = target.expr
if (
not isinstance(_object, astroid.nodes.Name)
or _object.name != "self"
):
target_ok = False
break
if not target_ok:
continue
child_data = self._parse_assign(child)
result.extend(data for data in child_data)
return result
def _parse_local_import_from(self, node):
result = []
for import_name, alias in node.names:
is_wildcard = (alias or import_name) == "*"
original_path = _astroid_utils.get_full_import_name(
node, alias or import_name
)
name = original_path if is_wildcard else (alias or import_name)
qual_name = self._get_qual_name(alias or import_name)
full_name = self._get_full_name(alias or import_name)
data = {
"type": "placeholder",
"name": name,
"qual_name": qual_name,
"full_name": full_name,
"original_path": original_path,
}
result.append(data)
return result
def parse_module(self, node):
path = node.path
if isinstance(node.path, list):
path = node.path[0] if node.path else None
type_ = "module"
if node.package:
type_ = "package"
self._full_name_stack = [node.name]
self._encoding = node.file_encoding
data = {
"type": type_,
"name": node.name,
"qual_name": node.name,
"full_name": node.name,
"doc": _prepare_docstring(node.doc_node.value if node.doc_node else ""),
"children": [],
"file_path": path,
"encoding": node.file_encoding,
"all": _astroid_utils.get_module_all(node),
}
overloads = {}
top_name = node.name.split(".", 1)[0]
for child in node.get_children():
if _astroid_utils.is_local_import_from(child, top_name):
children_data = self._parse_local_import_from(child)
else:
children_data = self.parse(child)
for child_data in children_data:
if _parse_child(child_data, overloads):
data["children"].append(child_data)
return data
def parse_typealias(self, node):
doc = ""
doc_node = node.next_sibling()
if isinstance(doc_node, astroid.nodes.Expr) and isinstance(
doc_node.value, astroid.nodes.Const
):
doc = doc_node.value.value
if isinstance(node.name, astroid.nodes.AssignName):
name = node.name.name
elif isinstance(node.name, astroid.nodes.AssignAttr):
name = node.name.attrname
else:
return []
data = {
"type": "data",
"name": name,
"qual_name": self._get_qual_name(name),
"full_name": self._get_full_name(name),
"doc": _prepare_docstring(doc),
"value": node.value.as_string(),
"from_line_no": node.fromlineno,
"to_line_no": node.tolineno,
"annotation": "TypeAlias",
}
return [data]
def parse(self, node):
data = []
node_type = node.__class__.__name__.lower()
parse_func = getattr(self, "parse_" + node_type, None)
if parse_func:
data = parse_func(node)
else:
for child in node.get_children():
data = self.parse(child)
if data:
break
return data
def _parse_child(child_data, overloads) -> bool:
if child_data["type"] in ("function", "method", "property"):
name = child_data["name"]
if name in overloads:
grouped = overloads[name]
grouped["doc"] = child_data["doc"]
if child_data["is_overload"]:
grouped["overloads"].append(
(child_data["args"], child_data["return_annotation"])
)
return False
if child_data["is_overload"] and name not in overloads:
overloads[name] = child_data
return True
sphinx-autoapi-3.3.3/autoapi/directives.py 0000664 0000000 0000000 00000004025 14707035566 0020664 0 ustar 00root root 0000000 0000000 """AutoAPI directives"""
from docutils.parsers.rst import Directive
from docutils import nodes
from sphinx.ext.autosummary import Autosummary, mangle_signature
from sphinx.util.nodes import nested_parse_with_titles
from ._objects import PythonFunction
class AutoapiSummary(Autosummary):
"""A version of autosummary that uses static analysis."""
def get_items(self, names):
items = []
env = self.state.document.settings.env
all_objects = env.autoapi_all_objects
max_item_chars = 60
for name in names:
obj = all_objects[name]
if isinstance(obj, PythonFunction):
if obj.overloads:
sig = "(\u2026)"
else:
sig = f"({obj.args})"
if obj.return_annotation is not None:
sig += f" \u2192 {obj.return_annotation}"
else:
sig = ""
if sig:
max_sig_chars = max(10, max_item_chars - len(obj.short_name))
sig = mangle_signature(sig, max_chars=max_sig_chars)
item = (obj.short_name, sig, obj.summary, obj.id)
items.append(item)
return items
class NestedParse(Directive):
"""Nested parsing to remove the first heading of included rST
This is used to handle the case where we like to remove user supplied
headings from module docstrings. This is required to reduce the number of
duplicate headings on sections.
"""
has_content = True
required_arguments = 0
optional_arguments = 0
final_argument_whitespace = False
def run(self):
node = nodes.container()
node.document = self.state.document
nested_parse_with_titles(self.state, self.content, node)
try:
if isinstance(node[0], nodes.section) and isinstance(
node[0][0], nodes.title
):
node.children = node[0][1:] + node.children[1:]
except IndexError:
pass
return node.children
sphinx-autoapi-3.3.3/autoapi/documenters.py 0000664 0000000 0000000 00000024301 14707035566 0021052 0 ustar 00root root 0000000 0000000 import re
from sphinx.ext import autodoc
from ._objects import (
PythonFunction,
PythonClass,
PythonMethod,
PythonProperty,
PythonData,
PythonAttribute,
PythonException,
)
class AutoapiDocumenter(autodoc.Documenter):
def get_attr(self, obj, name, *defargs):
attrgetters = self.env.app.registry.autodoc_attrgettrs
for type_, func in attrgetters.items():
if isinstance(obj, type_):
return func(obj, name, *defargs)
if name == "__doc__":
return obj.docstring
for child in obj.children:
if child.name == name:
return child
if defargs:
return defargs[0]
raise AttributeError(name)
def import_object(self):
max_splits = self.fullname.count(".")
for num_splits in range(max_splits, -1, -1):
path_stack = list(reversed(self.fullname.rsplit(".", num_splits)))
objects = self.env.autoapi_objects
parent = None
current = objects.get(path_stack.pop())
while current and path_stack:
parent = current
current = self.get_attr(current, path_stack.pop(), None)
if current:
self.object = current
self.object_name = current.name
self._method_parent = parent
return True
return False
def get_real_modname(self):
# Return a fake modname so that nothing can be imported
return None
def get_doc(self, encoding=None, ignore=1):
return [self.object.docstring.splitlines()]
def process_doc(self, docstrings):
for docstring in docstrings:
yield from docstring
yield ""
def get_object_members(self, want_all):
children = (
autodoc.ObjectMember(child.name, child) for child in self.object.children
)
if not want_all:
if not self.options.members:
return False, []
children = (
child for child in children if child.__name__ in self.options.members
)
elif not self.options.inherited_members:
children = (child for child in children if not child.object.inherited)
return False, children
class _AutoapiDocstringSignatureMixin:
def format_signature(self, **kwargs):
# Set "manual" attributes at the last possible moment.
# This is to let a manual entry or docstring searching happen first,
# and falling back to the discovered signature only when necessary.
if self.args is None:
self.args = self.object.args
if self.retann is None:
self.retann = self.object.return_annotation
return super().format_signature(**kwargs)
class AutoapiFunctionDocumenter(
AutoapiDocumenter, _AutoapiDocstringSignatureMixin, autodoc.FunctionDocumenter
):
objtype = "apifunction"
directivetype = "function"
# Always prefer AutoapiDocumenters
priority = autodoc.FunctionDocumenter.priority * 100 + 100
@classmethod
def can_document_member(cls, member, membername, isattr, parent):
return isinstance(member, PythonFunction)
def format_args(self, **kwargs):
return "(" + self.object.args + ")"
def add_directive_header(self, sig):
autodoc.Documenter.add_directive_header(self, sig)
if "async" in self.object.properties:
sourcename = self.get_sourcename()
self.add_line(" :async:", sourcename)
class AutoapiDecoratorDocumenter(
AutoapiFunctionDocumenter, AutoapiDocumenter, autodoc.DecoratorDocumenter
):
objtype = "apidecorator"
directivetype = "decorator"
priority = autodoc.DecoratorDocumenter.priority * 100 + 100
def format_signature(self, **kwargs):
if self.args is None:
self.args = self.format_args(**kwargs)
return super().format_signature(**kwargs)
def format_args(self, **kwargs):
to_format = self.object.args
if re.match(r"func\W", to_format) or to_format == "func":
if "," not in to_format:
return None
# We need to do better stripping here.
# An annotation with a comma will mess this up.
to_format = self.object.args.split(",", 1)[1]
return "(" + to_format + ")"
class AutoapiClassDocumenter(AutoapiDocumenter, autodoc.ClassDocumenter):
objtype = "apiclass"
directivetype = "class"
doc_as_attr = False
priority = autodoc.ClassDocumenter.priority * 100 + 100
@classmethod
def can_document_member(cls, member, membername, isattr, parent):
return isinstance(member, PythonClass)
def format_args(self, **kwargs):
return "(" + self.object.args + ")"
def add_directive_header(self, sig):
autodoc.Documenter.add_directive_header(self, sig)
if self.options.show_inheritance:
sourcename = self.get_sourcename()
self.add_line("", sourcename)
# TODO: Change sphinx to allow overriding of getting base names
if self.object.bases:
bases = ", ".join(f":class:`{base}`" for base in self.object.bases)
self.add_line(f" Bases: {bases}", sourcename)
def format_signature(self, **kwargs):
# Set "manual" attributes at the last possible moment.
# This is to let a manual entry or docstring searching happen first,
# and falling back to the discovered signature only when necessary.
if self.args is None:
self.args = self.object.args
return super().format_signature(**kwargs)
class AutoapiMethodDocumenter(
AutoapiDocumenter, _AutoapiDocstringSignatureMixin, autodoc.MethodDocumenter
):
objtype = "apimethod"
directivetype = "method"
priority = autodoc.MethodDocumenter.priority * 100 + 100
@classmethod
def can_document_member(cls, member, membername, isattr, parent):
return isinstance(member, PythonMethod)
def format_args(self, **kwargs):
return "(" + self.object.args + ")"
def import_object(self):
result = super().import_object()
if result:
self.parent = self._method_parent
if "staticmethod" in self.object.properties:
# document static members before ordinary ones
self.member_order = self.member_order - 2
elif "classmethod" in self.object.properties:
# document class members before ordinary ones but after static ones
self.member_order = self.member_order - 1
return result
def add_directive_header(self, sig):
autodoc.Documenter.add_directive_header(self, sig)
sourcename = self.get_sourcename()
for property_type in (
"abstractmethod",
"async",
"classmethod",
"staticmethod",
):
if property_type in self.object.properties:
self.add_line(f" :{property_type}:", sourcename)
class AutoapiPropertyDocumenter(AutoapiDocumenter, autodoc.PropertyDocumenter):
objtype = "apiproperty"
directivetype = "property"
priority = autodoc.PropertyDocumenter.priority * 100 + 100
@classmethod
def can_document_member(cls, member, membername, isattr, parent):
return isinstance(member, PythonProperty)
def add_directive_header(self, sig):
autodoc.ClassLevelDocumenter.add_directive_header(self, sig)
sourcename = self.get_sourcename()
for property_type in (
"abstractmethod",
"classmethod",
):
if property_type in self.object.properties:
self.add_line(f" :{property_type}:", sourcename)
if self.object.annotation:
self.add_line(f" :type: {self.object.annotation}", sourcename)
class AutoapiDataDocumenter(AutoapiDocumenter, autodoc.DataDocumenter):
objtype = "apidata"
directivetype = "data"
priority = autodoc.DataDocumenter.priority * 100 + 100
@classmethod
def can_document_member(cls, member, membername, isattr, parent):
return isinstance(member, PythonData)
def add_directive_header(self, sig):
autodoc.ModuleLevelDocumenter.add_directive_header(self, sig)
sourcename = self.get_sourcename()
if not self.options.annotation:
if self.object.value is not None:
self.add_line(f" :value: {self.object.value}", sourcename)
elif self.options.annotation is autodoc.SUPPRESS:
pass
else:
self.add_line(f" :annotation: {self.options.annotation}", sourcename)
if self.object.annotation:
self.add_line(f" :type: {self.object.annotation}", sourcename)
class AutoapiAttributeDocumenter(AutoapiDocumenter, autodoc.AttributeDocumenter):
objtype = "apiattribute"
directivetype = "attribute"
_datadescriptor = True
priority = autodoc.AttributeDocumenter.priority * 100 + 100
@classmethod
def can_document_member(cls, member, membername, isattr, parent):
return isinstance(member, PythonAttribute)
def add_directive_header(self, sig):
autodoc.ClassLevelDocumenter.add_directive_header(self, sig)
sourcename = self.get_sourcename()
if not self.options.annotation:
if self.object.value is not None:
self.add_line(f" :value: {self.object.value}", sourcename)
elif self.options.annotation is autodoc.SUPPRESS:
pass
else:
self.add_line(f" :annotation: {self.options.annotation}", sourcename)
if self.object.annotation:
self.add_line(f" :type: {self.object.annotation}", sourcename)
class AutoapiModuleDocumenter(AutoapiDocumenter, autodoc.ModuleDocumenter):
objtype = "apimodule"
directivetype = "module"
priority = autodoc.ModuleDocumenter.priority * 100 + 100
class AutoapiExceptionDocumenter(
AutoapiClassDocumenter, AutoapiDocumenter, autodoc.ExceptionDocumenter
):
objtype = "apiexception"
directivetype = "exception"
priority = autodoc.ExceptionDocumenter.priority * 100 + 100
@classmethod
def can_document_member(cls, member, membername, isattr, parent):
return isinstance(member, PythonException)
sphinx-autoapi-3.3.3/autoapi/extension.py 0000664 0000000 0000000 00000024073 14707035566 0020544 0 ustar 00root root 0000000 0000000 """Sphinx Auto-API Top-level Extension.
This extension allows you to automagically generate API documentation from your project.
"""
from __future__ import annotations
import os
import shutil
import sphinx
from sphinx.util.console import colorize
from sphinx.addnodes import toctree
from sphinx.errors import ExtensionError
import sphinx.util.logging
from docutils.parsers.rst import directives
from . import documenters
from .directives import AutoapiSummary, NestedParse
from .inheritance_diagrams import AutoapiInheritanceDiagram
from ._mapper import Mapper
from .settings import API_ROOT
LOGGER = sphinx.util.logging.getLogger(__name__)
_DEFAULT_FILE_PATTERNS = ["*.py", "*.pyi"]
_DEFAULT_IGNORE_PATTERNS = ["*migrations*"]
_DEFAULT_OPTIONS = [
"members",
"undoc-members",
"private-members",
"show-inheritance",
"show-module-summary",
"special-members",
"imported-members",
]
_VALID_PAGE_LEVELS = [
"module",
"class",
"function",
"method",
"attribute",
]
_VIEWCODE_CACHE: dict[str, tuple[str, dict[str, tuple[str, int, int]]]] = {}
"""Caches a module's parse results for use in viewcode."""
def _normalise_autoapi_dirs(autoapi_dirs, srcdir):
normalised_dirs = []
if isinstance(autoapi_dirs, str):
autoapi_dirs = [autoapi_dirs]
for path in autoapi_dirs:
if os.path.isabs(path):
normalised_dirs.append(path)
else:
normalised_dirs.append(os.path.normpath(os.path.join(srcdir, path)))
return normalised_dirs
def run_autoapi(app):
"""Load AutoAPI data from the filesystem."""
if not app.config.autoapi_dirs:
raise ExtensionError("You must configure an autoapi_dirs setting")
own_page_level = app.config.autoapi_own_page_level
if own_page_level not in _VALID_PAGE_LEVELS:
raise ValueError(f"Invalid autoapi_own_page_level '{own_page_level}")
# Make sure the paths are full
normalised_dirs = _normalise_autoapi_dirs(app.config.autoapi_dirs, app.srcdir)
for _dir in normalised_dirs:
if not os.path.exists(_dir):
raise ExtensionError(
f"AutoAPI Directory `{_dir}` not found. "
"Please check your `autoapi_dirs` setting."
)
template_dir = app.config.autoapi_template_dir
if template_dir and not os.path.isabs(template_dir):
template_dir = os.path.join(app.srcdir, app.config.autoapi_template_dir)
normalized_root = os.path.normpath(
os.path.join(app.srcdir, app.config.autoapi_root)
)
url_root = os.path.join("/", app.config.autoapi_root)
sphinx_mapper_obj = Mapper(
app, template_dir=template_dir, dir_root=normalized_root, url_root=url_root
)
if app.config.autoapi_file_patterns:
file_patterns = app.config.autoapi_file_patterns
else:
file_patterns = _DEFAULT_FILE_PATTERNS
if app.config.autoapi_ignore:
ignore_patterns = app.config.autoapi_ignore
else:
ignore_patterns = _DEFAULT_IGNORE_PATTERNS
if ".rst" in app.config.source_suffix:
out_suffix = ".rst"
elif ".txt" in app.config.source_suffix:
out_suffix = ".txt"
else:
# Fallback to first suffix listed
out_suffix = next(iter(app.config.source_suffix))
if sphinx_mapper_obj.load(
patterns=file_patterns, dirs=normalised_dirs, ignore=ignore_patterns
):
sphinx_mapper_obj.map(options=app.config.autoapi_options)
if app.config.autoapi_generate_api_docs:
sphinx_mapper_obj.output_rst(source_suffix=out_suffix)
# This function cannot be pickled into the Sphinx cache, so clear it.
# We won't need access to it again until a full rebuild is done anyway.
app.config.autoapi_prepare_jinja_env = None
def build_finished(app, exception):
if not app.config.autoapi_keep_files and app.config.autoapi_generate_api_docs:
normalized_root = os.path.normpath(
os.path.join(app.srcdir, app.config.autoapi_root)
)
if not os.path.exists(normalized_root):
return
if app.verbosity > 1:
LOGGER.info(
colorize("bold", "[AutoAPI] ")
+ colorize("darkgreen", "Cleaning generated .rst files")
)
shutil.rmtree(normalized_root)
def source_read(app, docname, source):
# temp_data is cleared after each source file has been processed,
# so populate the annotations at the beginning of every file read.
app.env.temp_data["annotations"] = getattr(app.env, "autoapi_annotations", {})
def doctree_read(app, doctree):
"""Inject AutoAPI into the TOC Tree dynamically."""
if app.env.docname == "index":
all_docs = set()
insert = True
nodes = list(doctree.findall(toctree))
toc_entry = f"{app.config.autoapi_root}/index"
add_entry = (
nodes
and app.config.autoapi_generate_api_docs
and app.config.autoapi_add_toctree_entry
)
if not add_entry:
return
# Capture all existing toctree entries
for node in nodes:
for entry in node["entries"]:
all_docs.add(entry[1])
# Don't insert autoapi it's already present
for doc in all_docs:
if doc.find(app.config.autoapi_root) != -1:
insert = False
if insert and app.config.autoapi_add_toctree_entry:
# Insert AutoAPI index
nodes[-1]["entries"].append((None, toc_entry))
nodes[-1]["includefiles"].append(toc_entry)
message_prefix = colorize("bold", "[AutoAPI] ")
message = colorize(
"darkgreen", f"Adding AutoAPI TOCTree [{toc_entry}] to index.rst"
)
LOGGER.info(message_prefix + message)
def viewcode_find(app, modname):
objects = app.env.autoapi_objects
if modname not in objects:
return None
if modname in _VIEWCODE_CACHE:
return _VIEWCODE_CACHE[modname]
locations = {}
module = objects[modname]
for child in module.children:
stack = [("", child)]
while stack:
prefix, obj = stack.pop()
type_ = "other"
if obj.type == "class":
type_ = "class"
elif obj.type in ("function", "method"):
type_ = "def"
full_name = prefix + obj.name
if "from_line_no" in obj.obj:
locations[full_name] = (
type_,
obj.obj["from_line_no"],
obj.obj["to_line_no"],
)
children = getattr(obj, "children", ())
stack.extend((full_name + ".", gchild) for gchild in children)
stream = open(module.obj["file_path"], encoding=module.obj.get("encoding", "utf-8"))
with stream as in_f:
source = in_f.read()
result = (source, locations)
_VIEWCODE_CACHE[modname] = result
return result
def viewcode_follow_imported(app, modname, attribute):
fullname = f"{modname}.{attribute}"
all_objects = app.env.autoapi_all_objects
if fullname not in all_objects:
return None
if all_objects[fullname].obj.get("type") == "method":
fullname = fullname[: fullname.rfind(".")]
attribute = attribute[: attribute.rfind(".")]
while all_objects[fullname].obj.get("original_path", "") != "":
fullname = all_objects[fullname].obj.get("original_path")
orig_path = fullname
if orig_path.endswith(attribute):
return orig_path[: -len(attribute) - 1]
return modname
def setup(app):
app.connect("builder-inited", run_autoapi)
app.connect("source-read", source_read)
# Use a lower priority than the default to ensure that we can
# inject into the toctree before Sphinx tries to use it
# in another doctree-read transformer.
app.connect("doctree-read", doctree_read, priority=400)
app.connect("build-finished", build_finished)
if "viewcode-find-source" in app.events.events:
app.connect("viewcode-find-source", viewcode_find)
if "viewcode-follow-imported" in app.events.events:
app.connect("viewcode-follow-imported", viewcode_follow_imported)
app.add_config_value("autoapi_root", API_ROOT, "html")
app.add_config_value("autoapi_ignore", [], "html")
app.add_config_value("autoapi_options", _DEFAULT_OPTIONS, "html")
app.add_config_value("autoapi_member_order", "bysource", "html")
app.add_config_value("autoapi_file_patterns", None, "html")
app.add_config_value("autoapi_dirs", [], "html")
app.add_config_value("autoapi_keep_files", False, "html")
app.add_config_value("autoapi_add_toctree_entry", True, "html")
app.add_config_value("autoapi_template_dir", None, "html")
app.add_config_value("autoapi_include_summaries", None, "html")
app.add_config_value("autoapi_python_use_implicit_namespaces", False, "html")
app.add_config_value("autoapi_python_class_content", "class", "html")
app.add_config_value("autoapi_generate_api_docs", True, "html")
app.add_config_value("autoapi_prepare_jinja_env", None, "html")
app.add_config_value("autoapi_own_page_level", "module", "html")
app.add_autodocumenter(documenters.AutoapiFunctionDocumenter)
app.add_autodocumenter(documenters.AutoapiPropertyDocumenter)
app.add_autodocumenter(documenters.AutoapiDecoratorDocumenter)
app.add_autodocumenter(documenters.AutoapiClassDocumenter)
app.add_autodocumenter(documenters.AutoapiMethodDocumenter)
app.add_autodocumenter(documenters.AutoapiDataDocumenter)
app.add_autodocumenter(documenters.AutoapiAttributeDocumenter)
app.add_autodocumenter(documenters.AutoapiModuleDocumenter)
app.add_autodocumenter(documenters.AutoapiExceptionDocumenter)
directives.register_directive("autoapi-nested-parse", NestedParse)
directives.register_directive("autoapisummary", AutoapiSummary)
app.setup_extension("sphinx.ext.autosummary")
app.add_event("autoapi-skip-member")
app.setup_extension("sphinx.ext.inheritance_diagram")
app.add_directive("autoapi-inheritance-diagram", AutoapiInheritanceDiagram)
return {
"parallel_read_safe": True,
"parallel_write_safe": True,
}
sphinx-autoapi-3.3.3/autoapi/inheritance_diagrams.py 0000664 0000000 0000000 00000010313 14707035566 0022660 0 ustar 00root root 0000000 0000000 import astroid
import sphinx.ext.inheritance_diagram
def _do_import_class(name, currmodule=None):
path_stack = list(reversed(name.split(".")))
if not currmodule:
currmodule = path_stack.pop()
try:
target = astroid.MANAGER.ast_from_module_name(currmodule)
while target and path_stack:
path_part = path_stack.pop()
target = (target.getattr(path_part) or (None,))[0]
while isinstance(target, (astroid.ImportFrom, astroid.Import)):
try:
target = target.do_import_module(path_part)
except astroid.AstroidImportError:
target = target.do_import_module()
target = (target.getattr(path_part) or (None,))[0]
break
except astroid.AstroidError:
target = None
return target
def _import_class(name, currmodule):
target = None
if currmodule:
target = _do_import_class(name, currmodule)
if target is None:
target = _do_import_class(name)
if not target:
raise sphinx.ext.inheritance_diagram.InheritanceException(
f"Could not import class or module {name} specified for inheritance diagram"
)
if isinstance(target, astroid.ClassDef):
return [target]
if isinstance(target, astroid.Module):
classes = []
for child in target.get_children():
if isinstance(child, astroid.ClassDef):
classes.append(child)
return classes
raise sphinx.ext.inheritance_diagram.InheritanceException(
f"{name} specified for inheritance diagram is not a class or module"
)
class _AutoapiInheritanceGraph(sphinx.ext.inheritance_diagram.InheritanceGraph):
@staticmethod
def _import_classes(class_names, currmodule):
classes = []
for name in class_names:
classes.extend(_import_class(name, currmodule))
return classes
def _class_info(
self, classes, show_builtins, private_bases, parts, aliases, top_classes
):
all_classes = {}
def recurse(cls):
if cls in all_classes:
return
if not show_builtins and cls.root().name == "builtins":
return
if not private_bases and cls.name.startswith("_"):
return
nodename = self.class_name(cls, parts, aliases)
fullname = self.class_name(cls, 0, aliases)
tooltip = None
if cls.doc_node:
doc = cls.doc_node.value.strip().split("\n")[0]
if doc:
tooltip = '"%s"' % doc.replace('"', '\\"')
baselist = []
all_classes[cls] = (nodename, fullname, baselist, tooltip or "")
if fullname in top_classes:
return
for base in cls.ancestors(recurs=False):
if not show_builtins and base.root().name == "builtins":
continue
if not private_bases and base.name.startswith("_"):
continue
baselist.append(self.class_name(base, parts, aliases))
if base not in all_classes:
recurse(base)
for cls in classes:
recurse(cls)
return list(all_classes.values())
@staticmethod
def class_name(node, parts=0, aliases=None):
fullname = node.qname()
if fullname.startswith(("__builtin__.", "builtins")):
fullname = fullname.split(".", 1)[-1]
if parts == 0:
result = fullname
else:
name_parts = fullname.split(".")
result = ".".join(name_parts[-parts:])
if aliases is not None and result in aliases:
return aliases[result]
return result
class AutoapiInheritanceDiagram(sphinx.ext.inheritance_diagram.InheritanceDiagram):
def run(self):
# Yucky! Monkeypatch InheritanceGraph to use our own
old_graph = sphinx.ext.inheritance_diagram.InheritanceGraph
sphinx.ext.inheritance_diagram.InheritanceGraph = _AutoapiInheritanceGraph
try:
return super().run()
finally:
sphinx.ext.inheritance_diagram.InheritanceGraph = old_graph
sphinx-autoapi-3.3.3/autoapi/settings.py 0000664 0000000 0000000 00000000572 14707035566 0020366 0 ustar 00root root 0000000 0000000 """Basic settings for AutoAPI projects.
You shouldn't need to touch this.
"""
import os
SITE_ROOT = os.path.dirname(os.path.realpath(__file__))
TEMPLATE_DIR = os.path.join(SITE_ROOT, "templates")
API_ROOT = "autoapi"
OWN_PAGE_LEVELS = [
"package",
"module",
"exception",
"class",
"function",
"method",
"property",
"data",
"attribute",
]
sphinx-autoapi-3.3.3/autoapi/templates/ 0000775 0000000 0000000 00000000000 14707035566 0020146 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/autoapi/templates/index.rst 0000664 0000000 0000000 00000000503 14707035566 0022005 0 ustar 00root root 0000000 0000000 API Reference
=============
This page contains auto-generated API reference documentation [#f1]_.
.. toctree::
:titlesonly:
{% for page in pages|selectattr("is_top_level_object") %}
{{ page.include_path }}
{% endfor %}
.. [#f1] Created with `sphinx-autoapi `_
sphinx-autoapi-3.3.3/autoapi/templates/python/ 0000775 0000000 0000000 00000000000 14707035566 0021467 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/autoapi/templates/python/attribute.rst 0000664 0000000 0000000 00000000040 14707035566 0024216 0 ustar 00root root 0000000 0000000 {% extends "python/data.rst" %}
sphinx-autoapi-3.3.3/autoapi/templates/python/class.rst 0000664 0000000 0000000 00000005231 14707035566 0023327 0 ustar 00root root 0000000 0000000 {% if obj.display %}
{% if is_own_page %}
{{ obj.id }}
{{ "=" * obj.id | length }}
{% endif %}
{% set visible_children = obj.children|selectattr("display")|list %}
{% set own_page_children = visible_children|selectattr("type", "in", own_page_types)|list %}
{% if is_own_page and own_page_children %}
.. toctree::
:hidden:
{% for child in own_page_children %}
{{ child.include_path }}
{% endfor %}
{% endif %}
.. py:{{ obj.type }}:: {% if is_own_page %}{{ obj.id }}{% else %}{{ obj.short_name }}{% endif %}{% if obj.args %}({{ obj.args }}){% endif %}
{% for (args, return_annotation) in obj.overloads %}
{{ " " * (obj.type | length) }} {{ obj.short_name }}{% if args %}({{ args }}){% endif %}
{% endfor %}
{% if obj.bases %}
{% if "show-inheritance" in autoapi_options %}
Bases: {% for base in obj.bases %}{{ base|link_objs }}{% if not loop.last %}, {% endif %}{% endfor %}
{% endif %}
{% if "show-inheritance-diagram" in autoapi_options and obj.bases != ["object"] %}
.. autoapi-inheritance-diagram:: {{ obj.obj["full_name"] }}
:parts: 1
{% if "private-members" in autoapi_options %}
:private-bases:
{% endif %}
{% endif %}
{% endif %}
{% if obj.docstring %}
{{ obj.docstring|indent(3) }}
{% endif %}
{% for obj_item in visible_children %}
{% if obj_item.type not in own_page_types %}
{{ obj_item.render()|indent(3) }}
{% endif %}
{% endfor %}
{% if is_own_page and own_page_children %}
{% set visible_attributes = own_page_children|selectattr("type", "equalto", "attribute")|list %}
{% if visible_attributes %}
Attributes
----------
.. autoapisummary::
{% for attribute in visible_attributes %}
{{ attribute.id }}
{% endfor %}
{% endif %}
{% set visible_exceptions = own_page_children|selectattr("type", "equalto", "exception")|list %}
{% if visible_exceptions %}
Exceptions
----------
.. autoapisummary::
{% for exception in visible_exceptions %}
{{ exception.id }}
{% endfor %}
{% endif %}
{% set visible_classes = own_page_children|selectattr("type", "equalto", "class")|list %}
{% if visible_classes %}
Classes
-------
.. autoapisummary::
{% for klass in visible_classes %}
{{ klass.id }}
{% endfor %}
{% endif %}
{% set visible_methods = own_page_children|selectattr("type", "equalto", "method")|list %}
{% if visible_methods %}
Methods
-------
.. autoapisummary::
{% for method in visible_methods %}
{{ method.id }}
{% endfor %}
{% endif %}
{% endif %}
{% endif %}
sphinx-autoapi-3.3.3/autoapi/templates/python/data.rst 0000664 0000000 0000000 00000001416 14707035566 0023134 0 ustar 00root root 0000000 0000000 {% if obj.display %}
{% if is_own_page %}
{{ obj.id }}
{{ "=" * obj.id | length }}
{% endif %}
.. py:{{ obj.type }}:: {% if is_own_page %}{{ obj.id }}{% else %}{{ obj.name }}{% endif %}
{% if obj.annotation is not none %}
:type: {% if obj.annotation %} {{ obj.annotation }}{% endif %}
{% endif %}
{% if obj.value is not none %}
{% if obj.value.splitlines()|count > 1 %}
:value: Multiline-String
.. raw:: html
Show Value
.. code-block:: python
{{ obj.value|indent(width=6,blank=true) }}
.. raw:: html
{% else %}
:value: {{ obj.value|truncate(100) }}
{% endif %}
{% endif %}
{% if obj.docstring %}
{{ obj.docstring|indent(3) }}
{% endif %}
{% endif %}
sphinx-autoapi-3.3.3/autoapi/templates/python/exception.rst 0000664 0000000 0000000 00000000041 14707035566 0024212 0 ustar 00root root 0000000 0000000 {% extends "python/class.rst" %}
sphinx-autoapi-3.3.3/autoapi/templates/python/function.rst 0000664 0000000 0000000 00000001307 14707035566 0024047 0 ustar 00root root 0000000 0000000 {% if obj.display %}
{% if is_own_page %}
{{ obj.id }}
{{ "=" * obj.id | length }}
{% endif %}
.. py:function:: {% if is_own_page %}{{ obj.id }}{% else %}{{ obj.short_name }}{% endif %}({{ obj.args }}){% if obj.return_annotation is not none %} -> {{ obj.return_annotation }}{% endif %}
{% for (args, return_annotation) in obj.overloads %}
{%+ if is_own_page %}{{ obj.id }}{% else %}{{ obj.short_name }}{% endif %}({{ args }}){% if return_annotation is not none %} -> {{ return_annotation }}{% endif %}
{% endfor %}
{% for property in obj.properties %}
:{{ property }}:
{% endfor %}
{% if obj.docstring %}
{{ obj.docstring|indent(3) }}
{% endif %}
{% endif %}
sphinx-autoapi-3.3.3/autoapi/templates/python/method.rst 0000664 0000000 0000000 00000001303 14707035566 0023476 0 ustar 00root root 0000000 0000000 {% if obj.display %}
{% if is_own_page %}
{{ obj.id }}
{{ "=" * obj.id | length }}
{% endif %}
.. py:method:: {% if is_own_page %}{{ obj.id }}{% else %}{{ obj.short_name }}{% endif %}({{ obj.args }}){% if obj.return_annotation is not none %} -> {{ obj.return_annotation }}{% endif %}
{% for (args, return_annotation) in obj.overloads %}
{%+ if is_own_page %}{{ obj.id }}{% else %}{{ obj.short_name }}{% endif %}({{ args }}){% if return_annotation is not none %} -> {{ return_annotation }}{% endif %}
{% endfor %}
{% for property in obj.properties %}
:{{ property }}:
{% endfor %}
{% if obj.docstring %}
{{ obj.docstring|indent(3) }}
{% endif %}
{% endif %}
sphinx-autoapi-3.3.3/autoapi/templates/python/module.rst 0000664 0000000 0000000 00000010325 14707035566 0023507 0 ustar 00root root 0000000 0000000 {% if obj.display %}
{% if is_own_page %}
{{ obj.id }}
{{ "=" * obj.id|length }}
.. py:module:: {{ obj.name }}
{% if obj.docstring %}
.. autoapi-nested-parse::
{{ obj.docstring|indent(3) }}
{% endif %}
{% block submodules %}
{% set visible_subpackages = obj.subpackages|selectattr("display")|list %}
{% set visible_submodules = obj.submodules|selectattr("display")|list %}
{% set visible_submodules = (visible_subpackages + visible_submodules)|sort %}
{% if visible_submodules %}
Submodules
----------
.. toctree::
:maxdepth: 1
{% for submodule in visible_submodules %}
{{ submodule.include_path }}
{% endfor %}
{% endif %}
{% endblock %}
{% block content %}
{% set visible_children = obj.children|selectattr("display")|list %}
{% if visible_children %}
{% set visible_attributes = visible_children|selectattr("type", "equalto", "data")|list %}
{% if visible_attributes %}
{% if "attribute" in own_page_types or "show-module-summary" in autoapi_options %}
Attributes
----------
{% if "attribute" in own_page_types %}
.. toctree::
:hidden:
{% for attribute in visible_attributes %}
{{ attribute.include_path }}
{% endfor %}
{% endif %}
.. autoapisummary::
{% for attribute in visible_attributes %}
{{ attribute.id }}
{% endfor %}
{% endif %}
{% endif %}
{% set visible_exceptions = visible_children|selectattr("type", "equalto", "exception")|list %}
{% if visible_exceptions %}
{% if "exception" in own_page_types or "show-module-summary" in autoapi_options %}
Exceptions
----------
{% if "exception" in own_page_types %}
.. toctree::
:hidden:
{% for exception in visible_exceptions %}
{{ exception.include_path }}
{% endfor %}
{% endif %}
.. autoapisummary::
{% for exception in visible_exceptions %}
{{ exception.id }}
{% endfor %}
{% endif %}
{% endif %}
{% set visible_classes = visible_children|selectattr("type", "equalto", "class")|list %}
{% if visible_classes %}
{% if "class" in own_page_types or "show-module-summary" in autoapi_options %}
Classes
-------
{% if "class" in own_page_types %}
.. toctree::
:hidden:
{% for klass in visible_classes %}
{{ klass.include_path }}
{% endfor %}
{% endif %}
.. autoapisummary::
{% for klass in visible_classes %}
{{ klass.id }}
{% endfor %}
{% endif %}
{% endif %}
{% set visible_functions = visible_children|selectattr("type", "equalto", "function")|list %}
{% if visible_functions %}
{% if "function" in own_page_types or "show-module-summary" in autoapi_options %}
Functions
---------
{% if "function" in own_page_types %}
.. toctree::
:hidden:
{% for function in visible_functions %}
{{ function.include_path }}
{% endfor %}
{% endif %}
.. autoapisummary::
{% for function in visible_functions %}
{{ function.id }}
{% endfor %}
{% endif %}
{% endif %}
{% set this_page_children = visible_children|rejectattr("type", "in", own_page_types)|list %}
{% if this_page_children %}
{{ obj.type|title }} Contents
{{ "-" * obj.type|length }}---------
{% for obj_item in this_page_children %}
{{ obj_item.render()|indent(0) }}
{% endfor %}
{% endif %}
{% endif %}
{% endblock %}
{% else %}
.. py:module:: {{ obj.name }}
{% if obj.docstring %}
.. autoapi-nested-parse::
{{ obj.docstring|indent(6) }}
{% endif %}
{% for obj_item in visible_children %}
{{ obj_item.render()|indent(3) }}
{% endfor %}
{% endif %}
{% endif %}
sphinx-autoapi-3.3.3/autoapi/templates/python/package.rst 0000664 0000000 0000000 00000000042 14707035566 0023610 0 ustar 00root root 0000000 0000000 {% extends "python/module.rst" %}
sphinx-autoapi-3.3.3/autoapi/templates/python/property.rst 0000664 0000000 0000000 00000000657 14707035566 0024115 0 ustar 00root root 0000000 0000000 {% if obj.display %}
{% if is_own_page %}
{{ obj.id }}
{{ "=" * obj.id | length }}
{% endif %}
.. py:property:: {% if is_own_page %}{{ obj.id}}{% else %}{{ obj.short_name }}{% endif %}
{% if obj.annotation %}
:type: {{ obj.annotation }}
{% endif %}
{% for property in obj.properties %}
:{{ property }}:
{% endfor %}
{% if obj.docstring %}
{{ obj.docstring|indent(3) }}
{% endif %}
{% endif %}
sphinx-autoapi-3.3.3/docs/ 0000775 0000000 0000000 00000000000 14707035566 0015436 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/docs/_static/ 0000775 0000000 0000000 00000000000 14707035566 0017064 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/docs/_static/overrides.css 0000664 0000000 0000000 00000000102 14707035566 0021571 0 ustar 00root root 0000000 0000000 .sd-card-title {
margin-bottom: 1em;
text-align: center;
} sphinx-autoapi-3.3.3/docs/changes/ 0000775 0000000 0000000 00000000000 14707035566 0017046 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/docs/changes/.gitkeep 0000664 0000000 0000000 00000000000 14707035566 0020465 0 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/docs/conf.py 0000664 0000000 0000000 00000005253 14707035566 0016742 0 ustar 00root root 0000000 0000000 # Configuration file for the Sphinx documentation builder.
#
# For the full list of built-in configuration values, see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
import re
from sphinx import addnodes
from sphinx.util.docfields import TypedField
import autoapi
# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
project = 'Sphinx AutoAPI'
copyright = '2023, Read the Docs'
author = 'Read the Docs'
version = ".".join(str(x) for x in autoapi.__version_info__[:2])
release = autoapi.__version__
# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
extensions = [
'autoapi.extension',
'sphinx.ext.intersphinx',
'sphinx.ext.napoleon',
'sphinx_design',
]
templates_path = ['_templates']
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', 'changes/*.rst']
# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
html_theme = 'furo'
html_static_path = ['_static']
html_css_files = ['overrides.css']
# -- Options for AutoAPI extension -------------------------------------------
autoapi_dirs = ['../autoapi']
autoapi_generate_api_docs = False
# -- Options for intersphinx extension ---------------------------------------
intersphinx_mapping = {
'jinja': ('https://jinja.palletsprojects.com/en/3.0.x/', None),
'sphinx': ('https://www.sphinx-doc.org/en/master/', None),
'python': ('https://docs.python.org/3/', None),
}
# -- Enable confval and event roles ------------------------------------------
event_sig_re = re.compile(r'([a-zA-Z-]+)\s*\((.*)\)')
def parse_event(env, sig, signode):
m = event_sig_re.match(sig)
if not m:
signode += addnodes.desc_name(sig, sig)
return sig
name, args = m.groups()
signode += addnodes.desc_name(name, name)
plist = addnodes.desc_parameterlist()
for arg in args.split(','):
arg = arg.strip()
plist += addnodes.desc_parameter(arg, arg)
signode += plist
return name
def setup(app):
app.add_object_type('confval', 'confval',
objname='configuration value',
indextemplate='pair: %s; configuration value')
fdesc = TypedField('parameter', label='Parameters',
names=('param',), typenames=('type',), can_collapse=True)
app.add_object_type('event', 'event', 'pair: %s; event', parse_event,
doc_field_types=[fdesc])
sphinx-autoapi-3.3.3/docs/how_to.rst 0000664 0000000 0000000 00000020117 14707035566 0017470 0 ustar 00root root 0000000 0000000 How-to Guides
=============
These guides will take you through the steps to perform common actions
or solve common problems in AutoAPI.
They will assume that you already have a Sphinx project with AutoAPI
set up already.
If you don't know how to do this then read the :doc:`tutorials`.
.. _customise-documented-api:
How to Customise What Gets Documented
-------------------------------------
With the default settings,
AutoAPI will document everything that is publicly accessible through the actual package
when loaded in Python.
For example if a function is imported from a submodule into a package
then that function is documented in both the submodule and the package.
.. note::
The one exception to this rule is that any object imported into a module
is not documented by default.
However there are multiple options available for controlling what AutoAPI will document.
Set ``__all__``
^^^^^^^^^^^^^^^
AutoAPI treats the definition of `__all__ `_
as the specification of what objects are public in a module or package, and which aren't.
In the following example, only ``func_a()`` and ``A`` would be documented.
.. code-block:: python
# mypackage/__init__.py
from . import B
__all__ = ("A", "func_a")
class A:
...
def func_a():
...
def func_b():
...
Configure :confval:`autoapi_options`
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The :confval:`autoapi_options` configuration value gives some high level control
over what is documented.
For example you could remove ``private-members`` from :confval:`autoapi_options`
and hide your object definitions in private modules.
.. code-block:: python
# package/__init__.py
from ._submodule import public_function
# package/_submodule.py
def public_function():
"""This public function will be documented only in ``package``."""
...
def private_function()
"""This private function won't be documented."""
...
As another example, you could remove ``undoc-members`` from :confval:`autoapi_options`
and only add docstrings for the modules and other entities that you want to be documented.
See :confval:`autoapi_options` for more information on how to use this option.
Connect to the :event:`autoapi-skip-member` event
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The :event:`autoapi-skip-member` event is emitted whenever
a template has to decide whether a member should be included in the documentation.
For example, to document only packages
-- in other words, to not document submodules --
you could implement an event handler in your conf.py like the following.
.. code-block:: python
def skip_submodules(app, what, name, obj, skip, options):
if what == "module":
skip = True
return skip
def setup(sphinx):
sphinx.connect("autoapi-skip-member", skip_submodules)
Customise the API Documentation Templates
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Finally, you can configure what gets rendered by customising the templates.
This is a rather heavy handed approach,
so it should only be necessary when the other options do not give you
the control the you need.
You can learn how to customise the templates in the next section:
:ref:`customise-templates`.
.. _customise-templates:
How to Customise Layout Through Templates
-----------------------------------------
.. warning::
Templates control a lot of behaviour,
so customising templates can mean that you lose out on new functionality
until you update your customised templates after a new release of AutoAPI.
You can customise the look of the documentation that AutoAPI generates
by changing the Jinja2 templates that it uses.
The default templates live in the ``autoapi/templates`` directory of the AutoAPI package.
Simply copy whichever templates you want to customise to a local directory
and edit them.
To get AutoAPI to use these templates,
point the :confval:`autoapi_template_dir` configuration option to your directory.
It can be absolute, or relative to the root of the documentation source directory
(ie the directory passed to ``sphinx-build``).
.. code-block:: python
autoapi_template_dir = '_autoapi_templates'
Your template directory must to follow the same layout as the default templates.
For example, to override the Python class and module templates:
.. code-block:: none
_autoapi_templates
└── python
├── class.rst
└── module.rst
.. _customise-index-page:
How to Customise the Index Page
-------------------------------
The index page that AutoAPI creates is generated using a template.
So customising the index page follows the same steps as customising a template.
Simply edit the ``autoapi/templates/index.rst`` template
with the same steps as :ref:`customising a template `.
How to Remove the Index Page
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
To remove the index page altogether,
turn off the :confval:`autoapi_add_toctree_entry` configuration option::
autoapi_add_toctree_entry = False
You will then need to include the generated documentation in the toctree yourself.
For example if you were generating documentation for a package called "example",
you would add the following toctree entry::
.. toctree::
autoapi/example/index
Note that ``autoapi/`` is the default location of documentation,
as configured by :confval:`autoapi_root`.
If you change :confval:`autoapi_root`,
then the entry that you need to add would change also.
How to Configure Where Documentation Appears in the TOC Tree
------------------------------------------------------------
The :confval:`autoapi_root` configuration option defines where generated documentation is output.
To change where documentation is output,
simply change this option to another directory relative to the documentation source directory:
.. code-block:: python
autoapi_root = 'technical/api'
How to Transition to Autodoc-Style Documentation
----------------------------------------------------
Once you have written some documentation with the :ref:`autodoc-directives`,
turning the automatic documentation generation off is as easy as
disabling the :confval:`autoapi_generate_api_docs` configuration option::
autoapi_generate_api_docs = False
How to Transition to Manual Documentation
-----------------------------------------
To start writing API documentation yourself,
you can get AutoAPI to keep its generated files around as a base to start from
using the :confval:`autoapi_keep_files` option::
autoapi_keep_files = True
Once you have built your documentation with this option turned on,
you can disable AutoAPI altogether from your project.
How to Include Type Annotations as Types in Rendered Docstrings
---------------------------------------------------------------
.. warning::
This feature is experimental and may change or be removed in future versions.
Since v3.0, :mod:`sphinx` has included an :mod:`sphinx.ext.autodoc.typehints`
extension that is capable of rendering type annotations as
parameter types and return types.
For example the following function:
.. code-block::
def _func(a: int, b: Optional[str]) -> bool
"""My function.
:param a: The first arg.
:param b: The second arg.
:returns: Something.
"""
would be rendered as:
.. py:function:: _func(a, b)
:noindex:
:param int a: The first arg.
:param b: The second arg.
:type b: Optional[str]
:returns: Something.
:rtype: bool
AutoAPI is capable of the same thing.
To enable this behaviour, load the :mod:`sphinx.ext.autodoc.typehints`
(or :mod:`sphinx.ext.autodoc`) extension in Sphinx's ``conf.py`` file
and set :confval:`autodoc_typehints` to ``description`` as normal::
extensions = ['sphinx.ext.autodoc', 'autoapi.extension']
autodoc_typehints = 'description'
.. note::
Unless :confval:`autodoc_typehints` is set to ``None``,
the type annotations of overloads will always be output in the signature
and never merged into the description
because it is impossible to represent all overloads as a list of parameters.
sphinx-autoapi-3.3.3/docs/index.rst 0000664 0000000 0000000 00000003454 14707035566 0017305 0 ustar 00root root 0000000 0000000 Sphinx AutoAPI
==============
Sphinx AutoAPI is a Sphinx extension for generating complete API documentation
without needing to load, run, or import the project being documented.
In contrast to the traditional `Sphinx autodoc `_,
which requires some manual authoring and uses code imports,
AutoAPI finds and generates documentation by parsing source code.
.. grid:: 2
:gutter: 3
.. grid-item-card:: Beginner Guides
New to AutoAPI? Check out the Tutorials.
They are a hands-on introduction for beginners.
+++
.. button-ref:: tutorials
:expand:
:color: secondary
:click-parent:
To the beginner guides
.. grid-item-card:: User Guides
The user guides are recipes for key tasks and common problems.
+++
.. button-ref:: how_to
:expand:
:color: secondary
:click-parent:
To the user guides
.. grid-item-card:: Reference Guide
The reference guide contains a detailed description of the
configuration options, directives, and templates included in AutoAPI.
+++
.. button-ref:: reference/index
:expand:
:color: secondary
:click-parent:
To the reference guide
.. grid-item-card:: Contributor Guides
Want to add to the codebase?
The contributing guidelines will guide you through the
process of improving AutoAPI.
+++
.. button-ref:: maintenance/index
:expand:
:color: secondary
:click-parent:
To the contributor guides
.. toctree::
:hidden:
tutorials
how_to
reference/index
maintenance/index
sphinx-autoapi-3.3.3/docs/maintenance/ 0000775 0000000 0000000 00000000000 14707035566 0017720 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/docs/maintenance/design.rst 0000664 0000000 0000000 00000010237 14707035566 0021726 0 ustar 00root root 0000000 0000000 Design Reference
================
Python
------
When choosing what to document,
AutoAPI aims to document anything that is publicly accessible through the actual package
when loaded in Python.
For example if a function is imported from a submodule into a package,
that function is documented in both the submodule and the package.
There are some exceptions to this rule:
* Anything that is imported into a module is not documented.
Usually a module is where implementations exist.
Therefore an import of something is usually for the usage of the implementation,
and not as something to be accessed publicly.
* When the module or package defines an ``__all__``,
only the members named in ``__all__`` are documented.
* When a configuration option indicates that private
or special members should also be documented.
Furthermore, AutoAPI follows the same docstring inheritance rules as :func:`inspect.getdoc`,
with some exceptions:
* The docstrings of the following methods are not inherited because they are usually redundant:
* :meth:`object.__init__`
* :meth:`object.__new__`
* :meth:`type.__init__`
* :meth:`type.__new__`
Introduction
------------
We are working with Sphinx,
which has an existing way of doing this.
Generally, you define a `Domain` which describes the various language structure,
a *Class* or *Method*, for example.
Then the user will write RST that uses these definitions,
and Sphinx will create output from that markup.
.. code-block:: rst
.. py:function:: spam(eggs)
Spam the foo.
The author of the documentation will have now told Sphinx that the *spam* function exists in the Python project that is being documented.
Autogenerated Output
~~~~~~~~~~~~~~~~~~~~
Sphinx then built a series of tools to make the generation of this markup easier and more automatic:
* `Autodoc `_
* `Autosummary `_
Autodoc is a Python-only solution that imports the author's code into memory, and then allows the author to more automatically document full objects. For example, you can document a whole class on a page.
.. code-block:: py
.. autoclass:: Noodle
This will generate output that looks like:
.. class:: Noodle
:noindex:
Noodle's docstring.
There are also options for it to include a full listing of the classes attributes, methods, and other things, automatically.
.. warning:: Remember, this depends on ``Noodle`` being importable by the Python interpreter running Sphinx.
Proposed Architecture
---------------------
The proposed architecture for this project is as follows:
* A parser will read the source files into an internal representation of the objects that can be documented.
* Take the internal representation and generate in-memory rst that corresponds to the Sphinx domain objects.
* Sphinx will output HTML based on the doctree generated from the in-memory rst.
In diagram form::
Code -> Internal Objects -> RST -> Sphinx -> HTML
File Structure vs. Hierarchy
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Specific ID's should have one specific detail representation.
This means that every internal object should only have one place that it is rendered with a ``.. :::`` canonical identifier.
All other places it is referenced should be in either:
* A reference
* A toctree (listing)
Sphinx Implementation
~~~~~~~~~~~~~~~~~~~~~
The user will run a normal `make html` as part of the experience.
The generation and loading will be done as an extension that can be configured.
There will be Sphinx configuration for how things get built:
.. code-block:: rst
autoapi_root = 'api' # Where HTML is generated
autoapi_dirs = ['yaml'] # Directory of YAML sources
We will then loop over all source files in the ``autoapi_dir`` and parse them.
They will then be output into ``autoapi_root`` inside the documentation.
Examples
--------
A nice example of Sphinx Python output similar to what we want:
* http://dta.googlecode.com/git/doc/_build/html/index.html
* Src: https://raw.githubusercontent.com/sfcta/dta/master/doc/index.rst
An example domain for Spec:
* https://subversion.xray.aps.anl.gov/bcdaext/specdomain/trunk/src/specdomain/sphinxcontrib/specdomain.py sphinx-autoapi-3.3.3/docs/maintenance/index.rst 0000664 0000000 0000000 00000000154 14707035566 0021561 0 ustar 00root root 0000000 0000000 ####################
Contributor's Guides
####################
.. toctree::
design
release-process sphinx-autoapi-3.3.3/docs/maintenance/release-process.rst 0000664 0000000 0000000 00000001416 14707035566 0023550 0 ustar 00root root 0000000 0000000 Release Process
===============
This page documents the steps to be taken to release a new version of Sphinx AutoAPI.
Pre-Checks
----------
1. Check that the dependencies of the package are correct.
2. Clean the ``.tox`` directory and run the tests.
3. Commit and push any changes needed to make the tests pass.
4. Check that the tests passed on github.
Preparation
-----------
1. Update the version numbers in ``autoapi/__init__.py``.
2. Run ``tox -e release_notes -- build``
3. Commit and push the changes.
4. Check that the tests passed on github.
Release
-------
Create a new release in github that tags the commit
and uses the built release notes as the description.
The tag created by the release will trigger the github actions to
build and upload the package to PyPI. sphinx-autoapi-3.3.3/docs/reference/ 0000775 0000000 0000000 00000000000 14707035566 0017374 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/docs/reference/config.rst 0000664 0000000 0000000 00000023354 14707035566 0021402 0 ustar 00root root 0000000 0000000 Configuration Options
=====================
.. confval:: autoapi_dirs
**Required**
Paths (relative or absolute) to the source code that you wish to generate your API documentation from.
The paths are searched recursively for files matching :confval:`autoapi_file_patterns`.
Relative paths should be relative to the source directory of your documentation.
For Python, if a package directory is specified,
the package directory itself will be included in the relative path of the children.
If an ordinary directory is specified,
that directory will not be included in the relative path.
.. confval:: autoapi_template_dir
Default: ``''``
A directory that has user-defined templates to override our default templates.
The path can either be absolute,
or relative to the source directory of your documentation files.
An path relative to where `sphinx-build` is run
is allowed for backwards compatibility only
and will be removed in a future version.
You can view the default templates in the
`autoapi/templates `_
directory of the package.
.. confval:: autoapi_file_patterns
Default: ``['*.py', '*.pyi']``
A list containing the file patterns to look for when generating documentation.
Patterns should be listed in order of preference.
For example,
if ``autoapi_file_patterns`` is set to the default value
and a `.py` file and a `.pyi` file are found,
then the `.py` will be read.
.. confval:: autoapi_generate_api_docs
Default: ``True``
Whether to generate API documentation.
If this is ``False``, documentation should be generated though the
:doc:`directives`.
Customisation Options
---------------------
.. confval:: autoapi_options
Default: [
``'members'``,
``'undoc-members'``,
``'private-members'``,
``'show-inheritance'``,
``'show-module-summary'``,
``'special-members'``,
``'imported-members'``,
]
Options for display of the generated documentation.
* ``members``: Display children of an object
* ``inherited-members``: Display children of an object
that have been inherited from a base class.
Members from standard library base classes are not included,
unless the base class is abstract.
* ``undoc-members``: Display objects that have no docstring
* ``private-members``: Display private objects (eg. ``_foo`` in Python)
* ``special-members``: Display special objects (eg. ``__foo__`` in Python)
* ``show-inheritance``: Display a list of base classes below the class signature.
* ``show-inheritance-diagram``: Display an inheritance diagram in
generated class documentation.
It makes use of the :mod:`sphinx.ext.inheritance_diagram` extension,
and requires `Graphviz `_ to be installed.
* ``show-module-summary``: Whether to include autosummary directives
in generated module documentation.
* ``imported-members``: For objects imported into a package,
display objects imported from the same top level package or module.
This option does not effect objects imported into a module.
.. confval:: autoapi_ignore
Default: ``['*migrations*']``
A list of patterns to ignore when finding files.
.. confval:: autoapi_root
Default: ``autoapi``
Path to output the generated AutoAPI files into,
including the generated index page.
This path must be relative to the source directory of your documentation files.
This can be used to place the generated documentation
anywhere in your documentation hierarchy.
.. confval:: autoapi_add_toctree_entry
Default: ``True``
Whether to insert the generated documentation into the TOC tree.
If this is ``False``, the default AutoAPI index page is not generated
and you will need to include the generated documentation
in a TOC tree entry yourself.
.. confval:: autoapi_python_class_content
Default: ``class``
Which docstring to insert into the content of a class.
* ``class``: Use only the class docstring.
* ``both``: Use the concatenation of the class docstring and the
``__init__`` docstring.
* ``init``: Use only the ``__init__`` docstring.
If the class does not have an ``__init__`` or the ``__init__``
docstring is empty and the class defines a ``__new__`` with a docstring,
the ``__new__`` docstring is used instead of the ``__init__`` docstring.
.. confval:: autoapi_member_order
Default: ``bysource``
The order to document members. This option can have the following values:
* ``alphabetical``: Order members by their name, case sensitively.
* ``bysource``: Order members by the order that they were defined in the source code.
* ``groupwise``: Order members by their type then alphabetically,
ordering the types as follows:
* Submodules and subpackages
* Attributes
* Exceptions
* Classes
* Functions
* Methods
.. confval:: autoapi_python_use_implicit_namespaces
Default: ``False``
This changes the package detection behaviour to be compatible with :pep:`420`,
but directories in :confval:`autoapi_dirs`
are no longer searched recursively for packages.
Instead, when this is ``True``,
:confval:`autoapi_dirs` should point directly to
the directories of implicit namespaces
and the directories of packages.
If searching is still required,
this should be done manually in the ``conf.py``.
.. confval:: autoapi_prepare_jinja_env
Default: ``None``
A callback that is called shortly after the Jinja environment is created.
The callback is passed the Jinja environment for editing before template rendering begins.
The callback should have the following signature:
.. py:function:: prepare_jinja_env(jinja_env: jinja2.Environment) -> None
:noindex:
.. confval:: autoapi_own_page_level
Default: ``'module'``
This configuration value specifies the level at which objects are rendered on
a single page. Valid levels, in descending order of hierarchy, are as
follows:
* ``module``: Packages, modules, subpackages, and submodules.
* ``class``: Classes, exceptions, and all object types mentioned above.
* ``function``: Functions, and all object types mentioned above.
* ``method``: Methods, and all object types mentioned above.
* ``attribute``: Class and module level attributes, properties,
and all object types mentioned above.
Events
~~~~~~
The following events allow you to control the behaviour of AutoAPI.
.. event:: autoapi-skip-member (app, what, name, obj, skip, options)
Emitted when a template has to decide whether a member should be included
in the documentation.
Usually the member is skipped if a handler returns ``True``,
and included otherwise.
Handlers should return ``None`` to fall back to the default skipping
behaviour of AutoAPI or another attached handler.
.. code-block:: python
:caption: Example conf.py
def skip_util_classes(app, what, name, obj, skip, options):
if what == "class" and "util" in name:
skip = True
return skip
def setup(sphinx):
sphinx.connect("autoapi-skip-member", skip_util_classes)
:param app: The Sphinx application object.
:param what: The type of the object which the docstring belongs to.
This can be one of:
``"attribute"``, ``"class"``, ``"data"``, ``"exception"``,
``"function"``, ``"method"``, ``"module"``, ``"package"``.
:type what: str
:param name: The fully qualified name of the object.
:type name: str
:param obj: The object itself.
:type obj: PythonPythonMapper
:param skip: Whether AutoAPI will skip this member if the handler
does not override the decision.
:type skip: bool
:param options: The options given to the directive.
Advanced Options
-----------------
.. confval:: autoapi_keep_files
Default: ``False``
Keep the AutoAPI generated files on the filesystem after the run.
Useful for debugging or transitioning to manual documentation.
Keeping files will also allow AutoAPI to use incremental builds.
Providing none of the source files have changed,
AutoAPI will skip parsing the source code and regenerating the API documentation.
Suppressing Warnings
---------------------
.. confval:: suppress_warnings
This is a sphinx builtin option that enables the granular filtering of AutoAPI
generated warnings.
Items in the ``suppress_warnings`` list are of the format ``"type.subtype"`` where
``".subtype"`` can be left out to cover all subtypes. To suppress all AutoAPI
warnings add the type ``"autoapi"`` to the list:
.. code-block:: python
suppress_warnings = ["autoapi"]
If narrower suppression is wanted, the available subtypes for AutoAPI are:
* ``python_import_resolution``:
Emitted if resolving references to objects in an imported module failed.
Potential reasons include cyclical imports and missing (parent) modules.
* ``not_readable``:
Emitted if processing (opening, parsing, ...) an input file failed.
* ``toc_reference``:
Emitted if a reference to an entry in a table of content cannot be resolved.
* ``nothing_rendered``:
Emitted if nothing was found to be documented.
Potential reasons include no files being found in :confval:`autoapi_dirs`
that match :confval:`autoapi_file_patterns`,
or all discovered modules and objects being excluded from rendering due to
:confval:`autoapi_options` or :ref:`other rendering exclusions `.
So if all AutoAPI warnings concerning unreadable sources and failing Python imports should be
filtered, but all other warnings should not, the option would be
.. code-block:: python
suppress_warnings = ["autoapi.python_import_resolution", "autoapi.not_readable"]
sphinx-autoapi-3.3.3/docs/reference/directives.rst 0000664 0000000 0000000 00000003747 14707035566 0022302 0 ustar 00root root 0000000 0000000 Directives
==========
.. _autodoc-directives:
Autodoc-Style Directives
------------------------
You can opt to write API documentation yourself using autodoc style directives.
These directives work similarly to autodoc,
but docstrings are retrieved through static analysis instead of through imports.
.. seealso::
When transitioning to autodoc-style documentation,
you may want to turn the :confval:`autoapi_generate_api_docs`
option off so that automatic API documentation is no longer generated.
To use these directives you will need to enable the autodoc extension
in your Sphinx project's ``conf.py``:
.. code:: python
extensions = ['sphinx.ext.autodoc', 'autoapi.extension']
For Python, all directives have an autodoc equivalent
and accept the same options.
The following directives are available:
.. rst:directive:: autoapimodule
autoapiclass
autoapiexception
Equivalent to :rst:dir:`automodule`, :rst:dir:`autoclass`,
and :rst:dir:`autoexception` respectively.
:confval:`autodoc_inherit_docstrings` does not currently work.
.. rst:directive:: autoapifunction
autoapidata
autoapimethod
autoapiattribute
Equivalent to :rst:dir:`autofunction`, :rst:dir:`autodata`,
:rst:dir:`automethod`, and :rst:dir:`autoattribute` respectively.
Inheritance Diagrams
--------------------
.. rst:directive:: autoapi-inheritance-diagram
This directive uses the :mod:`sphinx.ext.inheritance_diagram` extension
to create inheritance diagrams for classes.
For example:
.. autoapi-inheritance-diagram:: autoapi._objects.PythonModule autoapi._objects.PythonPackage
:parts: 1
:mod:`sphinx.ext.inheritance_diagram` makes use of the
:mod:`sphinx.ext.graphviz` extension,
and therefore it requires `Graphviz `_ to be installed.
The directive can be configured using the same options as
:mod:`sphinx.ext.inheritance_diagram`.
sphinx-autoapi-3.3.3/docs/reference/index.rst 0000664 0000000 0000000 00000000440 14707035566 0021233 0 ustar 00root root 0000000 0000000 ###############
Reference Guide
###############
The reference guide contains a detailed description of the
configuration options, directives, and templates included in AutoAPI.
To learn how to use AutoAPI, see the :doc:`/tutorials`.
.. toctree::
config
directives
templates sphinx-autoapi-3.3.3/docs/reference/templates.rst 0000664 0000000 0000000 00000005320 14707035566 0022124 0 ustar 00root root 0000000 0000000 Templates
=========
A lot of the power from AutoAPI comes from templates.
We are basically building a mapping from code to docs,
and templates let you highly customise the display of said docs.
Structure
---------
Every type of data structure has its own template.
It uses the form :samp:`python/{type}.rst` to find the template to render.
The full search path is:
* :samp:`python/{type}.rst`
So for a Python Class, this would resolve to:
* :samp:`python/class.rst`
We provide :samp:`base/base.rst` as an incredibly basic output of every object::
.. py:{type}:: {name}
Custom Filters, Tests, and Globals
----------------------------------
The :confval:`autoapi_prepare_jinja_env` configuration option allows you
to pass a callback that can edit the :class:`jinja2.Environment` object
before rendering begins.
This callback, among other things, can be used to add custom filters,
tests, and/or globals to the Jinja environment. For example:
.. code-block:: python
def autoapi_prepare_jinja_env(jinja_env):
jinja_env.filters["my_custom_filter"] = lambda value: value.upper()
Context
-------
Every template is given a set context that can be accessed in the templates.
This contains:
* ``autoapi_options``: The value of the :confval:`autoapi_options`
configuration option.
* ``include_summaries``: The value of the :confval:`autoapi_include_summaries`
configuration option.
* ``obj``: A Python object derived from :class:`PythonPythonMapper`.
* ``own_page_types``: A set of strings that contains the object types that
render on their own page.
* ``sphinx_version``: The contents of :attr:`sphinx.version_info`.
The object in ``obj`` has a number of standard attributes
that you can reliably access.
.. warning::
These classes should not be constructed manually.
They can be reliably accessed through templates
and :event:`autoapi-skip-member` only.
.. autoapiclass:: autoapi._objects.PythonPythonMapper
:members:
.. autoapiclass:: autoapi._objects.PythonFunction
:members:
:show-inheritance:
.. autoapiclass:: autoapi._objects.PythonMethod
:members:
:show-inheritance:
.. autoapiclass:: autoapi._objects.PythonProperty
:members:
:show-inheritance:
.. autoapiclass:: autoapi._objects.PythonData
:members:
:show-inheritance:
.. autoapiclass:: autoapi._objects.PythonAttribute
:members:
:show-inheritance:
.. autoapiclass:: autoapi._objects.TopLevelPythonPythonMapper
:members:
:show-inheritance:
.. autoapiclass:: autoapi._objects.PythonModule
:members:
:show-inheritance:
.. autoapiclass:: autoapi._objects.PythonPackage
:members:
:show-inheritance:
.. autoapiclass:: autoapi._objects.PythonClass
:members:
:show-inheritance:
.. autoapiclass:: autoapi._objects.PythonException
:members:
:show-inheritance: sphinx-autoapi-3.3.3/docs/tutorials.rst 0000664 0000000 0000000 00000007354 14707035566 0020227 0 ustar 00root root 0000000 0000000 Tutorials
=========
These tutorials will guide you through how to start using AutoAPI.
They will assume that you already have a basic Sphinx project set up.
If you are not sure how to do this,
you can follow the :doc:`sphinx:usage/quickstart` guide in the Sphinx documentation.
Setting up Automatic API Documentation Generation
-------------------------------------------------
The recommended way of installing AutoAPI is through a `virtualenv `_.
Once you have a virtualenv set up, you can install AutoAPI with the command:
.. code-block:: bash
pip install sphinx-autoapi
..
Validate this section with the following commands:
$ mkdir mypackage
$ cd mypackage
$ mkdir mypackage
$ echo -e 'from ._client import Client\nfrom ._server import Server' > mypackage/__init__.py
$ echo -e 'class Client:\n pass' > mypackage/_client.py
$ echo -e 'class Server:\n pass' > mypackage/_server.py
$ touch README.md
$ python -m venv .venv
$ .venv/bin/pip install /path/to/sphinx-autoapi
$ .venv/bin/sphinx-quickstart --no-sep --project mypackage --author me -v 0.1.0 --release 0.1.0 --language en --extensions autoapi.extension docs
$ echo 'autoapi_dirs = ["../mypackage"]' >> docs/conf.py
$ .venv/bin/sphinx-build -b html docs/ docs/_build
To enable the extension,
we need to add it to the list of extensions in Sphinx's ``conf.py`` file::
extensions = ['autoapi.extension']
There is only one required configuration option that we need to set.
:confval:`autoapi_dirs` tells AutoAPI which directories contain
the source code to document.
These can either be absolute, or relative to the source directory of
your documentation files.
For example, say we have a package and we have used ``sphinx-quickstart``
to create a Sphinx project in a ``docs/`` folder.
The directory structure might look like this:
.. code-block:: none
mypackage/
├── docs
│ ├── _build
│ ├── conf.py
│ ├── index.rst
│ ├── make.bat
│ ├── Makefile
│ ├── _static
│ └── _templates
├── mypackage
│ ├── _client.py
│ ├── __init__.py
│ └── _server.py
└── README.md
``sphinx-quickstart`` sets up the ``sphinx-build`` to run from
inside the ``docs/`` directory, and the source code is one level up.
So the value of our :confval:`autoapi_dirs` option would be::
autoapi_dirs = ['../mypackage']
If you are documenting many packages,
you can point AutoAPI to the directory that contains those packages.
For example if our source code was inside a ``src/`` directory:
.. code-block:: none
mypackage/
├── docs
│ ├── _build
│ ├── conf.py
│ ├── index.rst
│ ├── make.bat
│ ├── Makefile
│ ├── _static
│ └── _templates
├── README.md
└── src
└── mypackage
├── _client.py
├── __init__.py
└── _server.py
We can configure :confval:`autoapi_dirs` to be::
autoapi_dirs = ['../src']
Now that everything is configured,
AutoAPI will generate documentation when you run Sphinx!
.. code-block:: bash
cd docs/
sphinx-build -b html . _build
With the documentation successfully built you should now be able to open
the ``_build/index.html`` file in a web browser.
The page will have a table of contents with a link to API reference
documentation that has been generated by AutoAPI.
Next, you might want to :ref:`customise what gets documented `
or :ref:`customise or remove the API reference index page `. sphinx-autoapi-3.3.3/pyproject.toml 0000664 0000000 0000000 00000005542 14707035566 0017430 0 ustar 00root root 0000000 0000000 [build-system]
requires = ["flit_core >=3.2,<4"]
build-backend = "flit_core.buildapi"
[project]
name = "sphinx-autoapi"
authors = [{name = "Eric Holscher", email = "eric@ericholscher.com"}]
maintainers = [{name = "Ashley Whetter", email = "ashley@awhetter.co.uk"}]
description = "Sphinx API documentation generator"
license = {text = "LICENSE.rst"}
classifiers = [
"Development Status :: 5 - Production/Stable",
"Environment :: Plugins",
"Framework :: Sphinx :: Extension",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Natural Language :: English",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
]
requires-python = ">=3.8"
dependencies = [
'astroid>=2.7;python_version<"3.12"',
'astroid>=3.0.0a1;python_version>="3.12"',
"Jinja2",
"PyYAML",
"sphinx>=6.1.0",
'stdlib_list;python_version<"3.10"',
]
dynamic = ["version"]
[project.readme]
file = "README.rst"
content-type = "text/x-rst"
[project.urls]
Homepage = "http://github.com/readthedocs/sphinx-autoapi"
Documentation = "https://sphinx-autoapi.readthedocs.io/en/latest/"
[tool.flit.module]
name = "autoapi"
[tool.mypy]
# Start off with these
warn_unused_configs = true
warn_redundant_casts = true
warn_unused_ignores = true
# Getting these passing should be easy
strict_equality = true
# These shouldn't be too much additional work, but may be tricky to
# get passing if you use a lot of untyped libraries
disallow_subclassing_any = true
disallow_untyped_decorators = true
disallow_any_generics = true
# This one isn't too hard to get passing, but return on investment is lower
no_implicit_reexport = true
[[tool.mypy.overrides]]
module = "astroid.*"
ignore_missing_imports = true
[[tool.mypy.overrides]]
module = "autoapi.documenters"
ignore_errors = true
[[tool.mypy.overrides]]
module = "autoapi._astroid_utils"
# Strongly recommend enabling this one as soon as you can
check_untyped_defs = true
# These next few are various gradations of forcing use of type annotations
disallow_untyped_calls = true
disallow_incomplete_defs = true
disallow_untyped_defs = true
# This one can be tricky to get passing if you use a lot of untyped libraries
# Ignore until astroid is typed (https://github.com/pylint-dev/astroid/issues/2060)
warn_return_any = false
[tool.pytest.ini_options]
markers = [
"network: Tests that use network access.",
]
[tool.ruff.lint.pydocstyle]
convention = "google"
[tool.towncrier]
directory = "docs/changes"
filename = "CHANGELOG.rst"
package = "autoapi"
title_format = "v{version} ({project_date})"
underlines = ["-", "^", "\""]
sphinx-autoapi-3.3.3/tests/ 0000775 0000000 0000000 00000000000 14707035566 0015650 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/ 0000775 0000000 0000000 00000000000 14707035566 0017171 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/conftest.py 0000664 0000000 0000000 00000003237 14707035566 0021375 0 ustar 00root root 0000000 0000000 import os
import pathlib
import shutil
from bs4 import BeautifulSoup
import pytest
from sphinx.application import Sphinx
@pytest.fixture(scope="session")
def rebuild():
def _rebuild(confdir=".", **kwargs) -> int:
app = Sphinx(
srcdir=".",
confdir=confdir,
outdir="_build/html",
doctreedir="_build/.doctrees",
buildername="html",
pdb=True,
**kwargs,
)
app.build()
return app.statuscode
return _rebuild
@pytest.fixture(scope="class")
def builder(rebuild):
cwd = os.getcwd()
def build(test_dir, **kwargs) -> int:
if kwargs.get("warningiserror"):
# Add any warnings raised when using `Sphinx` more than once
# in a Python session.
confoverrides = kwargs.setdefault("confoverrides", {})
confoverrides.setdefault("suppress_warnings", [])
suppress = confoverrides["suppress_warnings"]
suppress.append("app.add_node")
suppress.append("app.add_directive")
suppress.append("app.add_role")
os.chdir(f"tests/python/{test_dir}")
return rebuild(**kwargs)
yield build
try:
shutil.rmtree("_build")
if (pathlib.Path("autoapi") / "index.rst").exists():
shutil.rmtree("autoapi")
finally:
os.chdir(cwd)
@pytest.fixture(scope="class")
def parse():
cache = {}
def parser(path):
if path not in cache:
with open(path, encoding="utf8") as file_handle:
cache[path] = BeautifulSoup(file_handle, features="html.parser")
return cache[path]
yield parser
sphinx-autoapi-3.3.3/tests/python/pep695/ 0000775 0000000 0000000 00000000000 14707035566 0020221 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pep695/conf.py 0000664 0000000 0000000 00000001055 14707035566 0021521 0 ustar 00root root 0000000 0000000 templates_path = ["_templates"]
source_suffix = ".rst"
master_doc = "index"
project = "pyexample"
copyright = "2015, readthedocs"
author = "readthedocs"
version = "0.1"
release = "0.1"
language = "en"
exclude_patterns = ["_build"]
pygments_style = "sphinx"
todo_include_todos = False
html_theme = "alabaster"
htmlhelp_basename = "pyexampledoc"
extensions = ["sphinx.ext.intersphinx", "sphinx.ext.autodoc", "autoapi.extension"]
intersphinx_mapping = {"python": ("https://docs.python.org/3.10", None)}
autoapi_dirs = ["example"]
autoapi_file_pattern = "*.py"
sphinx-autoapi-3.3.3/tests/python/pep695/example/ 0000775 0000000 0000000 00000000000 14707035566 0021654 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pep695/example/example.py 0000664 0000000 0000000 00000000154 14707035566 0023661 0 ustar 00root root 0000000 0000000 from typing import TypeAlias
MyTypeAliasA: TypeAlias = tuple[str, int]
type MyTypeAliasB = tuple[str, int]
sphinx-autoapi-3.3.3/tests/python/pep695/index.rst 0000664 0000000 0000000 00000000720 14707035566 0022061 0 ustar 00root root 0000000 0000000 .. pyexample documentation master file, created by
sphinx-quickstart on Fri May 29 13:34:37 2015.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to pyexample's documentation!
=====================================
.. toctree::
autoapi/index
Contents:
.. toctree::
:maxdepth: 2
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
sphinx-autoapi-3.3.3/tests/python/py310unionpipe/ 0000775 0000000 0000000 00000000000 14707035566 0021774 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/py310unionpipe/conf.py 0000664 0000000 0000000 00000001055 14707035566 0023274 0 ustar 00root root 0000000 0000000 templates_path = ["_templates"]
source_suffix = ".rst"
master_doc = "index"
project = "pyexample"
copyright = "2015, readthedocs"
author = "readthedocs"
version = "0.1"
release = "0.1"
language = "en"
exclude_patterns = ["_build"]
pygments_style = "sphinx"
todo_include_todos = False
html_theme = "alabaster"
htmlhelp_basename = "pyexampledoc"
extensions = ["sphinx.ext.intersphinx", "sphinx.ext.autodoc", "autoapi.extension"]
intersphinx_mapping = {"python": ("https://docs.python.org/3.10", None)}
autoapi_dirs = ["example"]
autoapi_file_pattern = "*.py"
sphinx-autoapi-3.3.3/tests/python/py310unionpipe/example/ 0000775 0000000 0000000 00000000000 14707035566 0023427 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/py310unionpipe/example/example.py 0000664 0000000 0000000 00000000411 14707035566 0025430 0 ustar 00root root 0000000 0000000 from pathlib import Path
from typing import Optional, Union
def simple(p: Path):
"""This is OK"""
def optional(p: Optional[Path]):
"""This is OK"""
def union(p: Union[Path, None]):
"""This is OK"""
def pipe(p: Path | None):
"""This is OK"""
sphinx-autoapi-3.3.3/tests/python/py310unionpipe/index.rst 0000664 0000000 0000000 00000000720 14707035566 0023634 0 ustar 00root root 0000000 0000000 .. pyexample documentation master file, created by
sphinx-quickstart on Fri May 29 13:34:37 2015.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to pyexample's documentation!
=====================================
.. toctree::
autoapi/index
Contents:
.. toctree::
:maxdepth: 2
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
sphinx-autoapi-3.3.3/tests/python/py38positionalparams/ 0000775 0000000 0000000 00000000000 14707035566 0023302 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/py38positionalparams/conf.py 0000664 0000000 0000000 00000000712 14707035566 0024601 0 ustar 00root root 0000000 0000000 templates_path = ["_templates"]
source_suffix = ".rst"
master_doc = "index"
project = "pyexample"
copyright = "2015, readthedocs"
author = "readthedocs"
version = "0.1"
release = "0.1"
language = "en"
exclude_patterns = ["_build"]
pygments_style = "sphinx"
todo_include_todos = False
html_theme = "alabaster"
htmlhelp_basename = "pyexampledoc"
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
autoapi_dirs = ["example"]
autoapi_file_pattern = "*.py"
sphinx-autoapi-3.3.3/tests/python/py38positionalparams/example/ 0000775 0000000 0000000 00000000000 14707035566 0024735 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/py38positionalparams/example/example.py 0000664 0000000 0000000 00000001345 14707035566 0026745 0 ustar 00root root 0000000 0000000 """Example module
This is a description
"""
from typing import Optional
def f_simple(a, b, /, c, d, *, e, f):
print(a, b, c, d, e, f)
def f_comment(a, b, /, c, d, *, e, f):
# type: (int, int, Optional[int], Optional[int], float, float) -> None
print(a, b, c, d, e, f)
def f_annotation(
a: int, b: int, /, c: Optional[int], d: Optional[int], *, e: float, f: float
) -> None:
print(a, b, c, d, e, f)
def f_arg_comment(
a, # type: int
b, # type: int
/,
c, # type: Optional[int]
d, # type: Optional[int]
*,
e, # type: float
f, # type: float
):
# type: (...) -> None
print(a, b, c, d, e, f)
def f_no_cd(a: int, b: int, /, *, e: float, f: float):
print(a, b, e, f)
sphinx-autoapi-3.3.3/tests/python/py38positionalparams/index.rst 0000664 0000000 0000000 00000000720 14707035566 0025142 0 ustar 00root root 0000000 0000000 .. pyexample documentation master file, created by
sphinx-quickstart on Fri May 29 13:34:37 2015.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to pyexample's documentation!
=====================================
.. toctree::
autoapi/index
Contents:
.. toctree::
:maxdepth: 2
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
sphinx-autoapi-3.3.3/tests/python/py3example/ 0000775 0000000 0000000 00000000000 14707035566 0021260 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/py3example/conf.py 0000664 0000000 0000000 00000001342 14707035566 0022557 0 ustar 00root root 0000000 0000000 templates_path = ["_templates"]
source_suffix = ".rst"
master_doc = "index"
project = "pyexample"
copyright = "2015, readthedocs"
author = "readthedocs"
version = "0.1"
release = "0.1"
language = "en"
exclude_patterns = ["_build"]
pygments_style = "sphinx"
todo_include_todos = False
html_theme = "alabaster"
htmlhelp_basename = "pyexampledoc"
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
autoapi_dirs = ["example"]
autoapi_python_class_content = "both"
autoapi_keep_files = True
autoapi_options = [
"members",
"undoc-members", # this is temporary until we add docstrings across the codebase
"show-inheritance",
"show-module-summary",
"special-members",
"imported-members",
"inherited-members",
]
sphinx-autoapi-3.3.3/tests/python/py3example/example/ 0000775 0000000 0000000 00000000000 14707035566 0022713 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/py3example/example/example.py 0000664 0000000 0000000 00000010140 14707035566 0024714 0 ustar 00root root 0000000 0000000 """Example module
This is a description
"""
import asyncio
import collections.abc
import typing
from typing import ClassVar, Dict, Iterable, Generic, List, TypeVar, Union, overload
from example2 import B
T = TypeVar("T")
U = TypeVar("U")
software = "sphin'x"
more_software = 'sphinx"autoapi'
interesting_string = "interesting\"fun'\\'string"
code_snippet = """The following is some code:
# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, print_function, unicode_literals
# from future.builtins.disabled import *
# from builtins import *
print("chunky o'block")
"""
max_rating: int = 10
is_valid: bool
if max_rating > 100:
is_valid = False
else:
is_valid = True
ratings: List[int] = [0, 1, 2, 3, 4, 5]
rating_names: Dict[int, str] = {0: "zero", 1: "one"}
def f(start: int, end: int) -> Iterable[int]:
"This is f"
i = start
while i < end:
yield i
i += 1
mixed_list: List[Union[str, int]] = [1, "two", 3]
"This is mixed"
def f2(not_yet_a: "A") -> int: ...
def f3(imported: B) -> B: ...
class MyGeneric(Generic[T, U]): ...
@overload
def overloaded_func(a: float) -> float: ...
@typing.overload
def overloaded_func(a: str) -> str: ...
def overloaded_func(a: Union[float, str]) -> Union[float, str]:
"""Overloaded function"""
return a * 2
@overload
def undoc_overloaded_func(a: str) -> str: ...
def undoc_overloaded_func(a: str) -> str:
return a * 2
class A:
"""class A"""
is_an_a: ClassVar[bool] = True
not_assigned_to: ClassVar[str]
def __init__(self):
self.instance_var: bool = True
"""This is an instance_var."""
self.subobject: object = object()
self.subobject.subobject_variable = 1
local_variable_typed: int = 0
local_variable_untyped = 2
async def async_method(self, wait: bool) -> int:
if wait:
await asyncio.sleep(1)
return 5
@property
def my_prop(self) -> str:
"""My property."""
return "prop"
def my_method(self) -> str:
"""My method."""
return "method"
@overload
def overloaded_method(self, a: float) -> float: ...
@typing.overload
def overloaded_method(self, a: str) -> str: ...
def overloaded_method(self, a: Union[float, str]) -> Union[float, str]:
"""Overloaded method"""
return a * 2
@overload
def undoc_overloaded_method(self, a: float) -> float: ...
def undoc_overloaded_method(self, a: float) -> float:
return a * 2
@typing.overload
@classmethod
def overloaded_class_method(cls, a: float) -> float: ...
@overload
@classmethod
def overloaded_class_method(cls, a: str) -> str: ...
@classmethod
def overloaded_class_method(cls, a: Union[float, str]) -> Union[float, str]:
"""Overloaded class method"""
return a * 2
class C:
@overload
def __init__(self, a: int) -> None: ...
@typing.overload
def __init__(self, a: float) -> None: ...
def __init__(self, a: str): ...
class D(C):
class Da: ...
class DB(Da): ...
...
async def async_function(wait: bool) -> int:
"""Blah.
Args:
wait: Blah
"""
if wait:
await asyncio.sleep(1)
return 5
global_a: A = A()
class SomeMetaclass(type): ...
class MyException(Exception):
pass
class My123(collections.abc.Sequence):
def __getitem__(self, i):
if i < len(self):
return i
raise IndexError(i)
def __len__(self):
return 3
class InheritBaseError(Exception):
"""The base exception."""
def __init__(self):
self.my_message = "one"
"""My message."""
super().__init__(self.my_message)
class InheritError(InheritBaseError):
"""The middle exception."""
def __init__(self):
self.my_other_message = "two"
"""My other message."""
super().__init__()
class SubInheritError(InheritError):
"""The last exception."""
class DuplicateInheritError(InheritBaseError):
"""Not the base exception."""
def __init__(self):
self.my_message = "three"
super().__init__()
sphinx-autoapi-3.3.3/tests/python/py3example/example/example2.py 0000664 0000000 0000000 00000000022 14707035566 0024774 0 ustar 00root root 0000000 0000000 class B:
pass
sphinx-autoapi-3.3.3/tests/python/py3example/index.rst 0000664 0000000 0000000 00000000717 14707035566 0023126 0 ustar 00root root 0000000 0000000 .. pyexample documentation master file, created by
sphinx-quickstart on Fri May 29 13:34:37 2015.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to pyexample's documentation!
=====================================
.. toctree::
autoapi/index
Contents:
.. toctree::
:maxdepth: 2
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
sphinx-autoapi-3.3.3/tests/python/py3implicitnamespace/ 0000775 0000000 0000000 00000000000 14707035566 0023314 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/py3implicitnamespace/conf.py 0000664 0000000 0000000 00000001005 14707035566 0024607 0 ustar 00root root 0000000 0000000 templates_path = ["_templates"]
source_suffix = ".rst"
master_doc = "index"
project = "pyexample"
copyright = "2015, readthedocs"
author = "readthedocs"
version = "0.1"
release = "0.1"
language = "en"
exclude_patterns = ["_build"]
pygments_style = "sphinx"
todo_include_todos = False
html_theme = "alabaster"
htmlhelp_basename = "py3implicitnamespacedoc"
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
autoapi_dirs = ["namespace"]
autoapi_file_pattern = "*.py"
autoapi_python_use_implicit_namespaces = True
sphinx-autoapi-3.3.3/tests/python/py3implicitnamespace/index.rst 0000664 0000000 0000000 00000000761 14707035566 0025161 0 ustar 00root root 0000000 0000000 .. py3implicitnamespace documentation master file, created by
sphinx-quickstart on Fri May 29 13:34:37 2015.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to py3implicitnamespace's documentation!
================================================
.. toctree::
autoapi/index
Contents:
.. toctree::
:maxdepth: 2
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
sphinx-autoapi-3.3.3/tests/python/py3implicitnamespace/namespace/ 0000775 0000000 0000000 00000000000 14707035566 0025250 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/py3implicitnamespace/namespace/example/ 0000775 0000000 0000000 00000000000 14707035566 0026703 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/py3implicitnamespace/namespace/example/__init__.py 0000664 0000000 0000000 00000000171 14707035566 0031013 0 ustar 00root root 0000000 0000000 from ..sibling import *
from ..sibling.sub_sibling import *
def example_method(foo):
"""Example method"""
pass
sphinx-autoapi-3.3.3/tests/python/py3implicitnamespace/namespace/sibling/ 0000775 0000000 0000000 00000000000 14707035566 0026677 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/py3implicitnamespace/namespace/sibling/__init__.py 0000664 0000000 0000000 00000000226 14707035566 0031010 0 ustar 00root root 0000000 0000000 def first_method():
"""First sibling package method."""
return 1
def second_method():
"""Second sibling package method."""
return 2
sphinx-autoapi-3.3.3/tests/python/py3implicitnamespace/namespace/sibling/sub_sibling.py 0000664 0000000 0000000 00000000241 14707035566 0031546 0 ustar 00root root 0000000 0000000 def first_sub_method():
"""First sub-sibling package method."""
return 1
def second_sub_method():
"""Second sub-subpackage method."""
return 2
sphinx-autoapi-3.3.3/tests/python/pyannotationcommentsexample/ 0000775 0000000 0000000 00000000000 14707035566 0025036 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pyannotationcommentsexample/conf.py 0000664 0000000 0000000 00000000744 14707035566 0026342 0 ustar 00root root 0000000 0000000 templates_path = ["_templates"]
source_suffix = ".rst"
master_doc = "index"
project = "pyexample"
copyright = "2015, readthedocs"
author = "readthedocs"
version = "0.1"
release = "0.1"
language = "en"
exclude_patterns = ["_build"]
pygments_style = "sphinx"
todo_include_todos = False
html_theme = "alabaster"
htmlhelp_basename = "pyexampledoc"
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
autoapi_dirs = ["example"]
autoapi_file_pattern = "*.py"
autoapi_keep_files = True
sphinx-autoapi-3.3.3/tests/python/pyannotationcommentsexample/example/ 0000775 0000000 0000000 00000000000 14707035566 0026471 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pyannotationcommentsexample/example/example.py 0000664 0000000 0000000 00000002312 14707035566 0030474 0 ustar 00root root 0000000 0000000 """Example module
This is a description
"""
from typing import ClassVar, Dict, Iterable, List, Union
max_rating = 10 # type: int
ratings = [0, 1, 2, 3, 4, 5] # type: List[int]
rating_names = {0: "zero", 1: "one"} # type: Dict[int, str]
def f(
start, # type: int
end, # type: int
): # type: (...) -> Iterable[int]
i = start
while i < end:
yield i
i += 1
mixed_list = [1, "two", 3] # type: List[Union[str, int]]
def f2(not_yet_a):
# type: (A) -> int
pass
class A:
is_an_a = True # type: ClassVar[bool]
def __init__(self):
self.instance_var = True # type: bool
"""This is an instance_var."""
global_a = A() # type: A
def f3(first_arg, **kwargs):
# type: (first_arg, Any) -> None
"""Annotation incorrectly leaves out `**`."""
class B:
"""Annotation keeps self/cls and shift all arg types"""
def __init__(self, a):
# type: (str) -> None
pass
def method(self, b):
# type: (list) -> None
pass
@classmethod
def class_method(cls, c):
# type: (int) -> None
pass
@staticmethod
def static_method(d):
# type: (float) -> Union[str,None]
pass
sphinx-autoapi-3.3.3/tests/python/pyannotationcommentsexample/index.rst 0000664 0000000 0000000 00000000720 14707035566 0026676 0 ustar 00root root 0000000 0000000 .. pyexample documentation master file, created by
sphinx-quickstart on Fri May 29 13:34:37 2015.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to pyexample's documentation!
=====================================
.. toctree::
autoapi/index
Contents:
.. toctree::
:maxdepth: 2
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
sphinx-autoapi-3.3.3/tests/python/pyautodoc_typehints/ 0000775 0000000 0000000 00000000000 14707035566 0023307 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pyautodoc_typehints/conf.py 0000664 0000000 0000000 00000001402 14707035566 0024603 0 ustar 00root root 0000000 0000000 templates_path = ["_templates"]
source_suffix = ".rst"
master_doc = "index"
project = "pyexample"
copyright = "2015, readthedocs"
author = "readthedocs"
version = "0.1"
release = "0.1"
language = "en"
exclude_patterns = ["_build"]
pygments_style = "sphinx"
todo_include_todos = False
html_theme = "alabaster"
htmlhelp_basename = "pyexampledoc"
extensions = ["sphinx.ext.autodoc", "autoapi.extension", "sphinx.ext.napoleon"]
autoapi_dirs = ["example"]
autoapi_python_class_content = "both"
autoapi_options = [
"members",
"undoc-members", # this is temporary until we add docstrings across the codebase
"show-inheritance",
"show-module-summary",
"special-members",
"imported-members",
"inherited-members",
]
autodoc_typehints = "description"
sphinx-autoapi-3.3.3/tests/python/pyautodoc_typehints/example/ 0000775 0000000 0000000 00000000000 14707035566 0024742 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pyautodoc_typehints/example/example.py 0000664 0000000 0000000 00000000206 14707035566 0026745 0 ustar 00root root 0000000 0000000 class A:
def test(self, a: int) -> bool:
"""Test.
Args:
a: Argument
"""
return False
sphinx-autoapi-3.3.3/tests/python/pyautodoc_typehints/example/example2.py 0000664 0000000 0000000 00000000206 14707035566 0027027 0 ustar 00root root 0000000 0000000 class B:
def test(self, a: int) -> bool:
"""Test.
Args:
a: Argument
"""
return False
sphinx-autoapi-3.3.3/tests/python/pyautodoc_typehints/index.rst 0000664 0000000 0000000 00000000717 14707035566 0025155 0 ustar 00root root 0000000 0000000 .. pyexample documentation master file, created by
sphinx-quickstart on Fri May 29 13:34:37 2015.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to pyexample's documentation!
=====================================
.. toctree::
autoapi/index
Contents:
.. toctree::
:maxdepth: 2
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
sphinx-autoapi-3.3.3/tests/python/pyemptyexample/ 0000775 0000000 0000000 00000000000 14707035566 0022254 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pyemptyexample/conf.py 0000664 0000000 0000000 00000001310 14707035566 0023546 0 ustar 00root root 0000000 0000000 templates_path = ["_templates"]
source_suffix = ".rst"
master_doc = "index"
project = "pyexample"
copyright = "2015, readthedocs"
author = "readthedocs"
version = "0.1"
release = "0.1"
language = "en"
exclude_patterns = ["_build"]
pygments_style = "sphinx"
todo_include_todos = False
html_theme = "alabaster"
htmlhelp_basename = "pyexampledoc"
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
autoapi_dirs = ["example"]
autoapi_python_class_content = "both"
autoapi_options = [
"members",
"undoc-members", # this is temporary until we add docstrings across the codebase
"show-inheritance",
"show-module-summary",
"special-members",
"imported-members",
"inherited-members",
]
sphinx-autoapi-3.3.3/tests/python/pyemptyexample/index.rst 0000664 0000000 0000000 00000000717 14707035566 0024122 0 ustar 00root root 0000000 0000000 .. pyexample documentation master file, created by
sphinx-quickstart on Fri May 29 13:34:37 2015.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to pyexample's documentation!
=====================================
.. toctree::
autoapi/index
Contents:
.. toctree::
:maxdepth: 2
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
sphinx-autoapi-3.3.3/tests/python/pyexample/ 0000775 0000000 0000000 00000000000 14707035566 0021175 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pyexample/conf.py 0000664 0000000 0000000 00000001012 14707035566 0022466 0 ustar 00root root 0000000 0000000 templates_path = ["_templates"]
source_suffix = ".rst"
master_doc = "index"
project = "pyexample"
copyright = "2015, readthedocs"
author = "readthedocs"
version = "0.1"
release = "0.1"
language = "en"
exclude_patterns = ["_build"]
pygments_style = "sphinx"
todo_include_todos = False
html_theme = "alabaster"
htmlhelp_basename = "pyexampledoc"
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
autoapi_dirs = ["example"]
autoapi_file_pattern = "*.py"
autoapi_python_class_content = "both"
autoapi_keep_files = True
sphinx-autoapi-3.3.3/tests/python/pyexample/example/ 0000775 0000000 0000000 00000000000 14707035566 0022630 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pyexample/example/example.py 0000664 0000000 0000000 00000007741 14707035566 0024646 0 ustar 00root root 0000000 0000000 """Example module
This is a description
"""
from dataclasses import dataclass
from functools import cached_property
A_TUPLE = ("a", "b")
"""A tuple to be rendered as a tuple."""
A_LIST = ["c", "d"]
"""A list to be rendered as a list."""
class Foo:
"""Can we parse arguments from the class docstring?
:param attr: Set an attribute.
:type attr: str
"""
class_var = 42 #: Class var docstring
another_class_var = 42
"""Another class var docstring"""
class Meta:
"""A nested class just to test things out"""
@classmethod
def foo():
"""The foo class method"""
return True
def __init__(self, attr):
"""Constructor docstring"""
self.attr = attr
self.attr2 = attr
"""This is the docstring of an instance attribute.
:type: str
"""
@property
def attr(self):
return 5
@attr.setter
def attr(self, value):
pass
@property
def property_simple(self) -> int:
"""This property should parse okay."""
return 42
@cached_property
def my_cached_property(self) -> int:
"""This cached property should be a property."""
return 42
def method_okay(self, foo=None, bar=None):
"""This method should parse okay"""
return True
def method_multiline(self, foo=None, bar=None, baz=None):
"""This is on multiple lines, but should parse okay too
pydocstyle gives us lines of source. Test if this means that multiline
definitions are covered in the way we're anticipating here
"""
return True
def method_tricky(self, foo=None, bar=dict(foo=1, bar=2)):
"""This will likely fail our argument testing
We parse naively on commas, so the nested dictionary will throw this off
"""
return True
def method_sphinx_docs(self, foo, bar=0):
"""This method is documented with sphinx style docstrings.
:param foo: The first argument.
:type foo: int
:param int bar: The second argument.
:returns: The sum of foo and bar.
:rtype: int
"""
return foo + bar
def method_google_docs(self, foo, bar=0):
"""This method is documented with google style docstrings.
Args:
foo (int): The first argument.
bar (int): The second argument.
Returns:
int: The sum of foo and bar.
"""
return foo + bar
def method_sphinx_unicode(self):
"""This docstring uses unicodé.
:returns: A string.
:rtype: str
"""
return "sphinx"
def method_google_unicode(self):
"""This docstring uses unicodé.
Returns:
str: A string.
"""
return "google"
Foo.bar = "dinglebop"
def decorator_okay(func):
"""This decorator should parse okay."""
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
class Bar(Foo):
def method_okay(self, foo=None, bar=None):
pass
class ClassWithNoInit:
pass
class One:
"""One."""
def __init__(self):
"""One __init__."""
super().__init__()
class MultilineOne(One):
"""This is a naughty summary line
that exists on two lines."""
class Two(One):
"""Two."""
class Three:
__init__ = Two.__init__
def fn_with_long_sig(
this,
*,
function=None,
has=True,
quite=True,
a,
long,
signature,
many,
keyword,
arguments,
):
"""A function with a long signature."""
TYPED_DATA: int = 1
"""This is TYPED_DATA."""
@dataclass
class TypedAttrs:
one: str
"""This is TypedAttrs.one."""
two: int = 1
"""This is TypedAttrs.two."""
class TypedClassInit:
"""This is TypedClassInit."""
def __init__(self, one: int = 1) -> None:
self._one = one
def typed_method(self, two: int) -> int:
"""This is TypedClassInit.typed_method."""
return self._one + two
sphinx-autoapi-3.3.3/tests/python/pyexample/index.rst 0000664 0000000 0000000 00000000645 14707035566 0023043 0 ustar 00root root 0000000 0000000 .. pyexample documentation master file, created by
sphinx-quickstart on Fri May 29 13:34:37 2015.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to pyexample's documentation!
=====================================
.. toctree::
:glob:
*
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
sphinx-autoapi-3.3.3/tests/python/pyexample/manualapi.rst 0000664 0000000 0000000 00000000215 14707035566 0023674 0 ustar 00root root 0000000 0000000 Autodoc Directives
==================
.. autoapimodule:: example
:members:
.. autoapidecorator:: example.decorator_okay
:noindex:
sphinx-autoapi-3.3.3/tests/python/pyexample/null.rst 0000664 0000000 0000000 00000000012 14707035566 0022672 0 ustar 00root root 0000000 0000000 Null
====
sphinx-autoapi-3.3.3/tests/python/pyiexample/ 0000775 0000000 0000000 00000000000 14707035566 0021346 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pyiexample/conf.py 0000664 0000000 0000000 00000000726 14707035566 0022652 0 ustar 00root root 0000000 0000000 templates_path = ["_templates"]
source_suffix = ".rst"
master_doc = "index"
project = "pyexample"
copyright = "2015, readthedocs"
author = "readthedocs"
version = "0.1"
release = "0.1"
language = "en"
exclude_patterns = ["_build"]
pygments_style = "sphinx"
todo_include_todos = False
html_theme = "alabaster"
htmlhelp_basename = "pyexampledoc"
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
autoapi_dirs = ["example"]
autoapi_file_patterns = ["*.pyi", "*.py"]
sphinx-autoapi-3.3.3/tests/python/pyiexample/example/ 0000775 0000000 0000000 00000000000 14707035566 0023001 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pyiexample/example/example.py 0000664 0000000 0000000 00000000076 14707035566 0025011 0 ustar 00root root 0000000 0000000 class DoNotFindThis:
"""pyi files should be preferred."""
sphinx-autoapi-3.3.3/tests/python/pyiexample/example/example.pyi 0000664 0000000 0000000 00000002105 14707035566 0025155 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
"""Example module
This is a description
"""
class Foo(object):
"""Can we parse arguments from the class docstring?
:param attr: Set an attribute.
:type attr: str
"""
class_var = 42 #: Class var docstring
another_class_var = 42
"""Another class var docstring"""
class_var_without_value = ...
"""A class var without a value."""
class Meta(object):
"""A nested class just to test things out"""
@classmethod
def foo():
"""The foo class method"""
...
def __init__(self, attr):
"""Constructor docstring"""
...
def method_okay(self, foo=None, bar=None):
"""This method should parse okay"""
...
def method_multiline(self, foo=None, bar=None, baz=None):
"""This is on multiple lines, but should parse okay too
pydocstyle gives us lines of source. Test if this means that multiline
definitions are covered in the way we're anticipating here
"""
...
def method_without_docstring(self): ...
sphinx-autoapi-3.3.3/tests/python/pyiexample/index.rst 0000664 0000000 0000000 00000000314 14707035566 0023205 0 ustar 00root root 0000000 0000000 Welcome to pyiexample's documentation!
======================================
.. toctree::
autoapi/index
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
sphinx-autoapi-3.3.3/tests/python/pyiexample2/ 0000775 0000000 0000000 00000000000 14707035566 0021430 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pyiexample2/conf.py 0000664 0000000 0000000 00000000654 14707035566 0022734 0 ustar 00root root 0000000 0000000 templates_path = ["_templates"]
source_suffix = ".rst"
master_doc = "index"
project = "pyexample"
copyright = "2015, readthedocs"
author = "readthedocs"
version = "0.1"
release = "0.1"
language = "en"
exclude_patterns = ["_build"]
pygments_style = "sphinx"
todo_include_todos = False
html_theme = "alabaster"
htmlhelp_basename = "pyexampledoc"
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
autoapi_dirs = ["example"]
sphinx-autoapi-3.3.3/tests/python/pyiexample2/example/ 0000775 0000000 0000000 00000000000 14707035566 0023063 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pyiexample2/example/example.py 0000664 0000000 0000000 00000000103 14707035566 0025062 0 ustar 00root root 0000000 0000000 """Example module
This is a description
"""
class Foo:
pass
sphinx-autoapi-3.3.3/tests/python/pyiexample2/example/example.pyi 0000664 0000000 0000000 00000000105 14707035566 0025235 0 ustar 00root root 0000000 0000000 class DoNotFindThis(object):
"""py files should be preferred."""
sphinx-autoapi-3.3.3/tests/python/pyiexample2/index.rst 0000664 0000000 0000000 00000000316 14707035566 0023271 0 ustar 00root root 0000000 0000000 Welcome to pyiexample2's documentation!
=======================================
.. toctree::
autoapi/index
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
sphinx-autoapi-3.3.3/tests/python/pyisubmoduleinit/ 0000775 0000000 0000000 00000000000 14707035566 0022576 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pyisubmoduleinit/conf.py 0000664 0000000 0000000 00000000672 14707035566 0024102 0 ustar 00root root 0000000 0000000 templates_path = ["_templates"]
source_suffix = ".rst"
master_doc = "index"
project = "pyisubmoduleinit"
copyright = "2015, readthedocs"
author = "readthedocs"
version = "0.1"
release = "0.1"
language = "en"
exclude_patterns = ["_build"]
pygments_style = "sphinx"
todo_include_todos = False
html_theme = "alabaster"
htmlhelp_basename = "pyisubmoduleinitdoc"
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
autoapi_dirs = ["example"]
sphinx-autoapi-3.3.3/tests/python/pyisubmoduleinit/example/ 0000775 0000000 0000000 00000000000 14707035566 0024231 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pyisubmoduleinit/example/example.py 0000664 0000000 0000000 00000000000 14707035566 0026224 0 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pyisubmoduleinit/example/submodule_foo/ 0000775 0000000 0000000 00000000000 14707035566 0027073 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pyisubmoduleinit/example/submodule_foo/__init__.pyi 0000664 0000000 0000000 00000000526 14707035566 0031360 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
"""Example __init__ in submodule foo
Documentation generated for this file
should be titled submodule_foo instead of __init__
This is a description
"""
class Foo(object):
"""
This is a description
"""
def bar(self, a: int) -> None:
"""
This is a description
"""
...
sphinx-autoapi-3.3.3/tests/python/pyisubmoduleinit/index.rst 0000664 0000000 0000000 00000000330 14707035566 0024433 0 ustar 00root root 0000000 0000000 Welcome to pyisubmoduleinit's documentation!
============================================
.. toctree::
autoapi/index
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
sphinx-autoapi-3.3.3/tests/python/pymovedconfpy/ 0000775 0000000 0000000 00000000000 14707035566 0022073 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pymovedconfpy/confpy/ 0000775 0000000 0000000 00000000000 14707035566 0023371 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pymovedconfpy/confpy/conf.py 0000777 0000000 0000000 00000000000 14707035566 0030614 2../../pyexample/conf.py ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pymovedconfpy/example 0000777 0000000 0000000 00000000000 14707035566 0027241 2../pyexample/example ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pymovedconfpy/index.rst 0000777 0000000 0000000 00000000000 14707035566 0030007 2../pyexample/index.rst ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pymovedconfpy/manualapi.rst 0000777 0000000 0000000 00000000000 14707035566 0031507 2../pyexample/manualapi.rst ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pynorender/ 0000775 0000000 0000000 00000000000 14707035566 0021356 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pynorender/conf.py 0000664 0000000 0000000 00000001050 14707035566 0022651 0 ustar 00root root 0000000 0000000 templates_path = ["_templates"]
source_suffix = ".rst"
master_doc = "index"
project = "pyexample"
copyright = "2015, readthedocs"
author = "readthedocs"
version = "0.1"
release = "0.1"
language = "en"
exclude_patterns = ["_build"]
pygments_style = "sphinx"
todo_include_todos = False
html_theme = "alabaster"
htmlhelp_basename = "pyexampledoc"
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
autoapi_dirs = ["example"]
autoapi_python_class_content = "both"
autoapi_options = [
"members",
"imported-members",
"inherited-members",
]
sphinx-autoapi-3.3.3/tests/python/pynorender/example/ 0000775 0000000 0000000 00000000000 14707035566 0023011 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pynorender/example/_example.py 0000664 0000000 0000000 00000000140 14707035566 0025150 0 ustar 00root root 0000000 0000000 def func() -> int:
"""Returns five."""
return 5
class Foo:
"""This is a class."""
sphinx-autoapi-3.3.3/tests/python/pynorender/index.rst 0000664 0000000 0000000 00000000717 14707035566 0023224 0 ustar 00root root 0000000 0000000 .. pyexample documentation master file, created by
sphinx-quickstart on Fri May 29 13:34:37 2015.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to pyexample's documentation!
=====================================
.. toctree::
autoapi/index
Contents:
.. toctree::
:maxdepth: 2
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
sphinx-autoapi-3.3.3/tests/python/pypackagecomplex/ 0000775 0000000 0000000 00000000000 14707035566 0022525 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pypackagecomplex/complex/ 0000775 0000000 0000000 00000000000 14707035566 0024174 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pypackagecomplex/complex/__init__.py 0000664 0000000 0000000 00000000362 14707035566 0026306 0 ustar 00root root 0000000 0000000 """
This heading will be removed
============================
"""
from .subpackage import public_chain
from .subpackage.submodule import public_multiple_imports
def module_level_function(foo, bar):
"""A module level method"""
pass
sphinx-autoapi-3.3.3/tests/python/pypackagecomplex/complex/_private_module.py 0000664 0000000 0000000 00000000344 14707035566 0027725 0 ustar 00root root 0000000 0000000 class PrivateClass:
"""A private class with public facing methods."""
def public_method():
"""This is public."""
return 5
def imported_function():
"""A function that gets imported."""
return 1
sphinx-autoapi-3.3.3/tests/python/pypackagecomplex/complex/binary_data.py 0000664 0000000 0000000 00000000027 14707035566 0027022 0 ustar 00root root 0000000 0000000 data = b"\xf0\xf0\xf0"
sphinx-autoapi-3.3.3/tests/python/pypackagecomplex/complex/foo.py 0000664 0000000 0000000 00000003346 14707035566 0025337 0 ustar 00root root 0000000 0000000 """Example module
This is a description
"""
from ._private_module import PrivateClass as PublicClass
from ._subpackage import module_level_function
__all__ = ["PublicClass", "Foo"]
class Foo:
class_var = 42 #: Class var docstring
another_class_var = 42
"""Another class var docstring"""
class Meta:
"""A nested class just to test things out"""
@classmethod
def foo():
"""The foo class method"""
return True
def method_okay(self, foo=None, bar=None):
"""This method should parse okay"""
return True
def method_multiline(self, foo=None, bar=None, baz=None):
"""This is on multiple lines, but should parse okay too
pydocstyle gives us lines of source. Test if this means that multiline
definitions are covered in the way we're anticipating here
"""
return True
def method_tricky(self, foo=None, bar=dict(foo=1, bar=2)):
"""This will likely fail our argument testing
We parse naively on commas, so the nested dictionary will throw this off
"""
return True
def method_sphinx_docs(self, foo, bar=0):
"""This method is documented with sphinx style docstrings.
:param foo: The first argument.
:type foo: int
:param int bar: The second argument.
:returns: The sum of foo and bar.
:rtype: int
"""
return foo + bar
def method_google_docs(self, foo, bar=0):
"""This method is documented with google style docstrings.
Args:
foo (int): The first argument.
bar (int): The second argument.
Returns:
int: The sum of foo and bar.
"""
return foo + bar
sphinx-autoapi-3.3.3/tests/python/pypackagecomplex/complex/submodule.py 0000664 0000000 0000000 00000000205 14707035566 0026542 0 ustar 00root root 0000000 0000000 from ._private_module import imported_function
def defined_function():
"""A function defined in the submodule."""
return 1
sphinx-autoapi-3.3.3/tests/python/pypackagecomplex/complex/subpackage/ 0000775 0000000 0000000 00000000000 14707035566 0026301 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pypackagecomplex/complex/subpackage/__init__.py 0000664 0000000 0000000 00000000346 14707035566 0030415 0 ustar 00root root 0000000 0000000 from .submodule import public_chain
from .submodule import _private_made_public as now_public_function
from .submodule import public_multiple_imports
def module_level_function(foo, bar):
"""A module level method"""
pass
sphinx-autoapi-3.3.3/tests/python/pypackagecomplex/complex/subpackage/submodule.py 0000664 0000000 0000000 00000000575 14707035566 0030661 0 ustar 00root root 0000000 0000000 """
This heading will be removed
============================
This docstring will not be removed.
"""
def public_chain():
"""Part of a public resolution chain."""
return 5
def _private_made_public():
"""A private function made public by import."""
return 5
def public_multiple_imports():
"""A public function imported in multiple places."""
return 5
sphinx-autoapi-3.3.3/tests/python/pypackagecomplex/complex/unicode_data.py 0000664 0000000 0000000 00000000101 14707035566 0027155 0 ustar 00root root 0000000 0000000 unicode_str = "αβγδεζηθικλμνξοπρςστυφχψ"
sphinx-autoapi-3.3.3/tests/python/pypackagecomplex/complex/wildall/ 0000775 0000000 0000000 00000000000 14707035566 0025624 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pypackagecomplex/complex/wildall/__init__.py 0000664 0000000 0000000 00000000026 14707035566 0027733 0 ustar 00root root 0000000 0000000 from .simple import *
sphinx-autoapi-3.3.3/tests/python/pypackagecomplex/complex/wildall/simple/ 0000775 0000000 0000000 00000000000 14707035566 0027115 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pypackagecomplex/complex/wildall/simple/__init__.py 0000664 0000000 0000000 00000000560 14707035566 0031227 0 ustar 00root root 0000000 0000000 from ...subpackage import *
__all__ = [
"SimpleClass",
"simple_function",
"public_chain",
"module_level_function",
"does_not_exist",
]
class SimpleClass:
def simple_method(self):
return 5
class NotAllClass:
def not_all_method(self):
return 5
def simple_function():
return 5
def not_all_function():
return 5
sphinx-autoapi-3.3.3/tests/python/pypackagecomplex/complex/wildcard/ 0000775 0000000 0000000 00000000000 14707035566 0025765 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pypackagecomplex/complex/wildcard/__init__.py 0000664 0000000 0000000 00000000033 14707035566 0030072 0 ustar 00root root 0000000 0000000 from ..subpackage import *
sphinx-autoapi-3.3.3/tests/python/pypackagecomplex/complex/wildchain/ 0000775 0000000 0000000 00000000000 14707035566 0026136 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pypackagecomplex/complex/wildchain/__init__.py 0000664 0000000 0000000 00000000121 14707035566 0030241 0 ustar 00root root 0000000 0000000 from ..wildcard import module_level_function
from ..wildcard import public_chain
sphinx-autoapi-3.3.3/tests/python/pypackagecomplex/complex/wildwildchain/ 0000775 0000000 0000000 00000000000 14707035566 0027016 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pypackagecomplex/complex/wildwildchain/__init__.py 0000664 0000000 0000000 00000000032 14707035566 0031122 0 ustar 00root root 0000000 0000000 from ..wildchain import *
sphinx-autoapi-3.3.3/tests/python/pypackagecomplex/conf.py 0000664 0000000 0000000 00000000702 14707035566 0024023 0 ustar 00root root 0000000 0000000 templates_path = ["_templates"]
source_suffix = ".rst"
master_doc = "index"
project = "pypackagecomplex"
copyright = "2015, readthedocs"
author = "readthedocs"
version = "0.1"
release = "0.1"
language = "en"
exclude_patterns = ["_build"]
pygments_style = "sphinx"
todo_include_todos = False
html_theme = "alabaster"
htmlhelp_basename = "pypackagecomplexdoc"
extensions = ["autoapi.extension"]
autoapi_dirs = ["complex"]
autoapi_file_pattern = "*.py"
sphinx-autoapi-3.3.3/tests/python/pypackagecomplex/index.rst 0000664 0000000 0000000 00000000744 14707035566 0024373 0 ustar 00root root 0000000 0000000 .. pypackagecomplex documentation master file, created by
sphinx-quickstart on Fri May 29 13:34:37 2015.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to pypackagecomplex's documentation!
============================================
.. toctree::
autoapi/index
Contents:
.. toctree::
:maxdepth: 2
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
sphinx-autoapi-3.3.3/tests/python/pypackageexample/ 0000775 0000000 0000000 00000000000 14707035566 0022511 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pypackageexample/conf.py 0000664 0000000 0000000 00000000734 14707035566 0024014 0 ustar 00root root 0000000 0000000 templates_path = ["_templates"]
source_suffix = ".rst"
master_doc = "index"
project = "pypackageexample"
copyright = "2015, readthedocs"
author = "readthedocs"
version = "0.1"
release = "0.1"
language = "en"
exclude_patterns = ["_build"]
pygments_style = "sphinx"
todo_include_todos = False
html_theme = "alabaster"
htmlhelp_basename = "pypackageexampledoc"
extensions = ["autoapi.extension"]
autoapi_dirs = ["package"]
autoapi_file_pattern = "*.py"
autoapi_keep_files = True
sphinx-autoapi-3.3.3/tests/python/pypackageexample/index.rst 0000664 0000000 0000000 00000000744 14707035566 0024357 0 ustar 00root root 0000000 0000000 .. pypackageexample documentation master file, created by
sphinx-quickstart on Fri May 29 13:34:37 2015.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to pypackageexample's documentation!
============================================
.. toctree::
autoapi/index
Contents:
.. toctree::
:maxdepth: 2
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
sphinx-autoapi-3.3.3/tests/python/pypackageexample/package/ 0000775 0000000 0000000 00000000000 14707035566 0024104 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pypackageexample/package/__init__.py 0000664 0000000 0000000 00000001430 14707035566 0026213 0 ustar 00root root 0000000 0000000 """This is a docstring."""
from . import submodule
from .subpackage.submodule import function as aliased_function
from .subpackage.submodule import not_in_all_function
__all__ = (
"aliased_function",
"Class",
"DATA",
"function",
"MyException",
)
DATA = 42
def function(foo, bar):
"""A module level function"""
class Class:
"""This is a class."""
class_var = 42
"""Class var docstring"""
class NestedClass:
"""A nested class just to test things out"""
@classmethod
def a_classmethod():
"""A class method"""
return True
def method_okay(self, foo=None, bar=None):
"""This method should parse okay"""
return True
class MyException(Exception):
"""This is an exception."""
sphinx-autoapi-3.3.3/tests/python/pypackageexample/package/_private_submodule.py 0000664 0000000 0000000 00000000223 14707035566 0030343 0 ustar 00root root 0000000 0000000 class PrivateClass:
"""A private class with public facing methods."""
def public_method():
"""This is public."""
return 5
sphinx-autoapi-3.3.3/tests/python/pypackageexample/package/_private_subpackage/ 0000775 0000000 0000000 00000000000 14707035566 0030102 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pypackageexample/package/_private_subpackage/__init__.py 0000664 0000000 0000000 00000000356 14707035566 0032217 0 ustar 00root root 0000000 0000000 """This is a docstring."""
from .submodule import function as aliased_function
from .submodule import not_in_all_function
__all__ = (
"aliased_function",
"function",
)
def function(foo, bar):
"""A module level function"""
sphinx-autoapi-3.3.3/tests/python/pypackageexample/package/_private_subpackage/submodule.py 0000664 0000000 0000000 00000001345 14707035566 0032456 0 ustar 00root root 0000000 0000000 """Example module
This is a description
"""
DATA = 42
def function(foo, bar):
"""A module level function"""
def _private_function():
"""A function that shouldn't get rendered."""
def not_in_all_function():
"""A function that doesn't exist in __all__ when imported."""
class Class:
"""This is a class."""
class_var = 42
"""Class var docstring"""
class NestedClass:
"""A nested class just to test things out"""
@classmethod
def a_classmethod():
"""A class method"""
return True
def method_okay(self, foo=None, bar=None):
"""This method should parse okay"""
return True
class MyException(Exception):
"""This is an exception."""
sphinx-autoapi-3.3.3/tests/python/pypackageexample/package/_private_subpackage/subpackage/ 0000775 0000000 0000000 00000000000 14707035566 0032207 5 ustar 00root root 0000000 0000000 __init__.py 0000664 0000000 0000000 00000000356 14707035566 0034245 0 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pypackageexample/package/_private_subpackage/subpackage """This is a docstring."""
from .submodule import function as aliased_function
from .submodule import not_in_all_function
__all__ = (
"aliased_function",
"function",
)
def function(foo, bar):
"""A module level function"""
submodule.py 0000664 0000000 0000000 00000001345 14707035566 0034504 0 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pypackageexample/package/_private_subpackage/subpackage """Example module
This is a description
"""
DATA = 42
def function(foo, bar):
"""A module level function"""
def _private_function():
"""A function that shouldn't get rendered."""
def not_in_all_function():
"""A function that doesn't exist in __all__ when imported."""
class Class:
"""This is a class."""
class_var = 42
"""Class var docstring"""
class NestedClass:
"""A nested class just to test things out"""
@classmethod
def a_classmethod():
"""A class method"""
return True
def method_okay(self, foo=None, bar=None):
"""This method should parse okay"""
return True
class MyException(Exception):
"""This is an exception."""
sphinx-autoapi-3.3.3/tests/python/pypackageexample/package/submodule.py 0000664 0000000 0000000 00000003650 14707035566 0026461 0 ustar 00root root 0000000 0000000 """Example module
This is a description
"""
from .subpackage.submodule import function as aliased_function
from .subpackage.submodule import not_in_all_function
__all__ = (
"aliased_function",
"Class",
"DATA",
"function",
"MyException",
)
DATA = 42
def function(foo, bar):
"""A module level function"""
class Class:
"""This is a class."""
class_var = 42
"""Class var docstring"""
class NestedClass:
"""A nested class just to test things out"""
@classmethod
def a_classmethod():
"""A class method"""
return True
def method_okay(self, foo=None, bar=None):
"""This method should parse okay"""
return True
def method_multiline(self, foo=None, bar=None, baz=None):
"""This is on multiple lines, but should parse okay too
pydocstyle gives us lines of source. Test if this means that multiline
definitions are covered in the way we're anticipating here
"""
return True
def method_tricky(self, foo=None, bar=dict(foo=1, bar=2)):
"""This will likely fail our argument testing
We parse naively on commas, so the nested dictionary will throw this off
"""
return True
def method_sphinx_docs(self, foo, bar=0):
"""This method is documented with sphinx style docstrings.
:param foo: The first argument.
:type foo: int
:param int bar: The second argument.
:returns: The sum of foo and bar.
:rtype: int
"""
return foo + bar
def method_google_docs(self, foo, bar=0):
"""This method is documented with google style docstrings.
Args:
foo (int): The first argument.
bar (int): The second argument.
Returns:
int: The sum of foo and bar.
"""
return foo + bar
class MyException(Exception):
"""This is an exception."""
sphinx-autoapi-3.3.3/tests/python/pypackageexample/package/subpackage/ 0000775 0000000 0000000 00000000000 14707035566 0026211 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pypackageexample/package/subpackage/__init__.py 0000664 0000000 0000000 00000000356 14707035566 0030326 0 ustar 00root root 0000000 0000000 """This is a docstring."""
from .submodule import function as aliased_function
from .submodule import not_in_all_function
__all__ = (
"aliased_function",
"function",
)
def function(foo, bar):
"""A module level function"""
sphinx-autoapi-3.3.3/tests/python/pypackageexample/package/subpackage/submodule.py 0000664 0000000 0000000 00000001345 14707035566 0030565 0 ustar 00root root 0000000 0000000 """Example module
This is a description
"""
DATA = 42
def function(foo, bar):
"""A module level function"""
def _private_function():
"""A function that shouldn't get rendered."""
def not_in_all_function():
"""A function that doesn't exist in __all__ when imported."""
class Class:
"""This is a class."""
class_var = 42
"""Class var docstring"""
class NestedClass:
"""A nested class just to test things out"""
@classmethod
def a_classmethod():
"""A class method"""
return True
def method_okay(self, foo=None, bar=None):
"""This method should parse okay"""
return True
class MyException(Exception):
"""This is an exception."""
sphinx-autoapi-3.3.3/tests/python/pyskipexample/ 0000775 0000000 0000000 00000000000 14707035566 0022064 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pyskipexample/conf.py 0000664 0000000 0000000 00000001405 14707035566 0023363 0 ustar 00root root 0000000 0000000 templates_path = ["_templates"]
source_suffix = ".rst"
master_doc = "index"
project = "pyexample"
copyright = "2015, readthedocs"
author = "readthedocs"
version = "0.1"
release = "0.1"
language = "en"
exclude_patterns = ["_build"]
pygments_style = "sphinx"
todo_include_todos = False
html_theme = "alabaster"
htmlhelp_basename = "pyexampledoc"
extensions = ["sphinx.ext.autodoc", "autoapi.extension"]
autoapi_dirs = ["example"]
autoapi_file_pattern = "*.py"
autoapi_options = ["members", "undoc-members", "special-members"]
SKIP = {"example.foo", "example.Bar", "example.Bar.m", "example.Baf.m", "example.baz"}
def maybe_skip_member(app, what, name, obj, skip, options):
return name in SKIP
def setup(app):
app.connect("autoapi-skip-member", maybe_skip_member)
sphinx-autoapi-3.3.3/tests/python/pyskipexample/example/ 0000775 0000000 0000000 00000000000 14707035566 0023517 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pyskipexample/example/example.py 0000664 0000000 0000000 00000000526 14707035566 0025527 0 ustar 00root root 0000000 0000000 """Example module
This is a description
"""
def foo():
"""foo doc"""
pass
class Bar:
"""bar doc"""
def m(self):
"""bar m doc"""
pass
class Baf:
"""baf doc"""
def m(self):
"""baf m doc"""
baz = 100
"""baz doc"""
anchor = "value"
"""must be in result document because not ignored"""
sphinx-autoapi-3.3.3/tests/python/pyskipexample/index.rst 0000664 0000000 0000000 00000000717 14707035566 0023732 0 ustar 00root root 0000000 0000000 .. pyexample documentation master file, created by
sphinx-quickstart on Fri May 29 13:34:37 2015.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to pyexample's documentation!
=====================================
.. toctree::
autoapi/index
Contents:
.. toctree::
:maxdepth: 2
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
sphinx-autoapi-3.3.3/tests/python/pystdlib/ 0000775 0000000 0000000 00000000000 14707035566 0021023 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pystdlib/conf.py 0000664 0000000 0000000 00000001110 14707035566 0022313 0 ustar 00root root 0000000 0000000 templates_path = ["_templates"]
source_suffix = ".rst"
master_doc = "index"
project = "pystdlib"
copyright = "2015, readthedocs"
author = "readthedocs"
version = "0.1"
release = "0.1"
language = "en"
exclude_patterns = ["_build"]
pygments_style = "sphinx"
todo_include_todos = False
html_theme = "alabaster"
htmlhelp_basename = "pystdlibdoc"
extensions = ["autoapi.extension"]
autoapi_dirs = ["stdlib"]
autoapi_file_pattern = "*.py"
autoapi_keep_files = True
autoapi_options = [
"members",
"undoc-members" "special-members",
"imported-members",
"inherited-members",
]
sphinx-autoapi-3.3.3/tests/python/pystdlib/index.rst 0000664 0000000 0000000 00000000744 14707035566 0022671 0 ustar 00root root 0000000 0000000 .. pypackageexample documentation master file, created by
sphinx-quickstart on Fri May 29 13:34:37 2015.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to pypackageexample's documentation!
============================================
.. toctree::
autoapi/index
Contents:
.. toctree::
:maxdepth: 2
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
sphinx-autoapi-3.3.3/tests/python/pystdlib/stdlib/ 0000775 0000000 0000000 00000000000 14707035566 0022304 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/python/pystdlib/stdlib/json.py 0000664 0000000 0000000 00000000256 14707035566 0023632 0 ustar 00root root 0000000 0000000 """json is the same name as a stdlib module."""
class JSONDecoder:
"""Do things with json."""
def decode(self, s):
"""Decode a string."""
return s
sphinx-autoapi-3.3.3/tests/python/pystdlib/stdlib/myast.py 0000664 0000000 0000000 00000000240 14707035566 0024007 0 ustar 00root root 0000000 0000000 """This is a docstring."""
import ast
class MyVisitor(ast.NodeVisitor):
"""My custom visitor."""
def my_visit(self):
"""My visit method."""
sphinx-autoapi-3.3.3/tests/python/pystdlib/stdlib/myjson.py 0000664 0000000 0000000 00000000262 14707035566 0024175 0 ustar 00root root 0000000 0000000 """This is a docstring."""
from json import JSONDecoder
class MyJSONDecoder(JSONDecoder):
"""This is a class."""
def my_method(self):
"""This is a method."""
sphinx-autoapi-3.3.3/tests/python/test_own_page_option.py 0000664 0000000 0000000 00000116723 14707035566 0024003 0 ustar 00root root 0000000 0000000 import os
import pytest
class TestModule:
@pytest.fixture(autouse=True, scope="class")
def built(self, builder):
builder(
"pypackageexample",
warningiserror=True,
confoverrides={
"autoapi_own_page_level": "module",
"autoapi_options": [
"members",
"undoc-members",
"show-inheritance",
"imported-members",
],
},
)
def test_package(self, parse):
package_path = "_build/html/autoapi/package/index.html"
package_file = parse(package_path)
docstring = package_file.find("p")
assert docstring.text == "This is a docstring."
# There should be links to the children with their own page
submodules = package_file.find(id="submodules")
assert submodules
assert submodules.find("a", string="package.subpackage")
assert submodules.find("a", string="package.submodule")
# There should not be links to the children without their own page
assert not package_file.find(id="attributes")
assert not package_file.find(id="exceptions")
assert not package_file.find(id="classes")
assert not package_file.find(id="functions")
# Children without their own page should be rendered on this page,
# and children with their own page should not be rendered on this page.
contents = package_file.find(id="package-contents")
assert contents.find(id="package.DATA")
assert contents.find(id="package.MyException")
assert contents.find(id="package.Class")
assert contents.find(id="package.Class.class_var")
assert contents.find(id="package.Class.NestedClass")
assert contents.find(id="package.Class.method_okay")
assert contents.find(id="package.Class.NestedClass")
assert contents.find(id="package.Class.NestedClass.a_classmethod")
assert contents.find(id="package.function")
assert contents.find(id="package.aliased_function")
# Hidden children are never rendered.
assert not contents.find(id="package.not_in_all_function")
def test_subpackage(self, parse):
subpackage_path = "_build/html/autoapi/package/subpackage/index.html"
subpackage_file = parse(subpackage_path)
docstring = subpackage_file.find("p")
assert docstring.text == "This is a docstring."
# There should be links to the children with their own page
submodules = subpackage_file.find(id="submodules")
assert submodules
assert submodules.find("a", string="package.subpackage.submodule")
# There should not be links to the children without their own page
assert not subpackage_file.find(id="attributes")
assert not subpackage_file.find(id="exceptions")
assert not subpackage_file.find(id="classes")
assert not subpackage_file.find(id="functions")
# Children without their own page should be rendered on this page,
# and children with their own page should not be rendered on this page.
contents = subpackage_file.find(id="package-contents")
assert contents.find(id="package.subpackage.function")
assert contents.find(id="package.subpackage.aliased_function")
# Hidden children are never rendered.
assert not contents.find(id="package.subpackage.not_in_all_function")
def test_module(self, parse):
submodule_path = "_build/html/autoapi/package/submodule/index.html"
submodule_file = parse(submodule_path)
docstring = submodule_file.find("p")
assert docstring.text == "Example module"
# There should be links to the children with their own page
pass # there are no children with their own page
# There should not be links to the children without their own page
assert not submodule_file.find(id="submodules")
assert not submodule_file.find(id="attributes")
assert not submodule_file.find(id="exceptions")
assert not submodule_file.find(id="classes")
assert not submodule_file.find(id="functions")
# Children without their own page should be rendered on this page,
# and children with their own page should not be rendered on this page.
contents = submodule_file.find(id="module-contents")
assert contents.find(id="package.submodule.DATA")
assert contents.find(id="package.submodule.MyException")
assert contents.find(id="package.submodule.Class")
assert contents.find(id="package.submodule.Class.class_var")
assert contents.find(id="package.submodule.Class.NestedClass")
assert contents.find(id="package.submodule.Class.method_okay")
assert contents.find(id="package.submodule.Class.NestedClass")
assert contents.find(id="package.submodule.Class.NestedClass.a_classmethod")
assert contents.find(id="package.submodule.function")
assert contents.find(id="package.submodule.aliased_function")
# Hidden children are never rendered.
assert not contents.find(id="package.submodule.not_in_all_function")
def test_rendered_only_expected_pages(self):
_, dirs, files = next(os.walk("_build/html/autoapi/package"))
assert sorted(dirs) == ["submodule", "subpackage"]
assert files == ["index.html"]
_, dirs, files = next(os.walk("_build/html/autoapi/package/submodule"))
assert not dirs
assert files == ["index.html"]
_, dirs, files = next(os.walk("_build/html/autoapi/package/subpackage"))
assert dirs == ["submodule"]
assert files == ["index.html"]
_, dirs, files = next(
os.walk("_build/html/autoapi/package/subpackage/submodule")
)
assert not dirs
assert files == ["index.html"]
def test_index(self, parse):
index_path = "_build/html/autoapi/index.html"
index_file = parse(index_path)
top_links = index_file.find_all(class_="toctree-l1")
top_hrefs = sorted(link.a["href"] for link in top_links)
assert top_hrefs == [
"#",
"package/index.html",
]
class TestClass:
@pytest.fixture(autouse=True, scope="class")
def built(self, builder):
builder(
"pypackageexample",
warningiserror=True,
confoverrides={
"autoapi_own_page_level": "class",
"autoapi_options": [
"members",
"undoc-members",
"show-inheritance",
"imported-members",
],
},
)
def test_package(self, parse):
package_path = "_build/html/autoapi/package/index.html"
package_file = parse(package_path)
docstring = package_file.find("p")
assert docstring.text == "This is a docstring."
# There should be links to the children with their own page
submodules = package_file.find(id="submodules")
assert submodules
assert submodules.find("a", string="package.subpackage")
assert submodules.find("a", string="package.submodule")
exceptions = package_file.find(id="exceptions")
assert exceptions
assert exceptions.find("a", title="package.MyException")
classes = package_file.find(id="classes")
assert classes
assert classes.find("a", title="package.Class")
assert not classes.find("a", title="package.Class.NestedClass")
# There should not be links to the children without their own page
assert not package_file.find(id="attributes")
assert not package_file.find(id="functions")
# Children without their own page should be rendered on this page,
# and children with their own page should not be rendered on this page.
contents = package_file.find(id="package-contents")
assert contents.find(id="package.DATA")
assert not contents.find(id="package.MyException")
assert not contents.find(id="package.Class")
assert not contents.find(id="package.Class.class_var")
assert not contents.find(id="package.Class.NestedClass")
assert not contents.find(id="package.Class.method_okay")
assert not contents.find(id="package.Class.NestedClass")
assert not contents.find(id="package.Class.NestedClass.a_classmethod")
assert contents.find(id="package.function")
assert contents.find(id="package.aliased_function")
# Hidden children are never rendered.
assert not contents.find(id="package.not_in_all_function")
def test_module(self, parse):
submodule_path = "_build/html/autoapi/package/submodule/index.html"
submodule_file = parse(submodule_path)
docstring = submodule_file.find("p")
assert docstring.text == "Example module"
# There should be links to the children with their own page
exceptions = submodule_file.find(id="exceptions")
assert exceptions
assert exceptions.find("a", title="package.submodule.MyException")
classes = submodule_file.find(id="classes")
assert classes
assert classes.find("a", title="package.submodule.Class")
assert not classes.find("a", title="package.submodule.Class.NestedClass")
# There should not be links to the children without their own page
assert not submodule_file.find(id="submodules")
assert not submodule_file.find(id="attributes")
assert not submodule_file.find(id="functions")
# Children without their own page should be rendered on this page,
# and children with their own page should not be rendered on this page.
contents = submodule_file.find(id="module-contents")
assert contents.find(id="package.submodule.DATA")
assert not contents.find(id="package.submodule.MyException")
assert not contents.find(id="package.submodule.Class")
assert not contents.find(id="package.submodule.Class.class_var")
assert not contents.find(id="package.submodule.Class.NestedClass")
assert not contents.find(id="package.submodule.Class.method_okay")
assert not contents.find(id="package.submodule.Class.NestedClass")
assert not contents.find(id="package.submodule.Class.NestedClass.a_classmethod")
assert contents.find(id="package.submodule.function")
assert contents.find(id="package.submodule.aliased_function")
# Hidden children are never rendered.
assert not contents.find(id="package.submodule.not_in_all_function")
def test_class(self, parse):
class_path = "_build/html/autoapi/package/Class.html"
class_file = parse(class_path)
class_sig = class_file.find(id="package.Class")
assert class_sig
class_ = class_sig.parent
docstring = class_.find_all("p")[0]
assert docstring.text == "This is a class."
# There should be links to the children with their own page
classes = class_file.find(id="classes")
assert classes
assert classes.find("a", title="package.Class.NestedClass")
# There should not be links to the children without their own page
assert not class_file.find(id="attributes")
assert not class_file.find(id="exceptions")
assert not class_file.find(id="methods")
# Children without their own page should be rendered on this page,
# and children with their own page should not be rendered on this page.
assert class_.find(id="package.Class.class_var")
assert class_.find(id="package.Class.method_okay")
nested_class_path = "_build/html/autoapi/package/Class.NestedClass.html"
nested_class_file = parse(nested_class_path)
nested_class_sig = nested_class_file.find(id="package.Class.NestedClass")
assert nested_class_sig
nested_class = nested_class_sig.parent
# There should be links to the children with their own page
pass # there are no children with their own page
# There should not be links to the children without their own page
assert not class_file.find(id="attributes")
assert not class_file.find(id="exceptions")
assert not class_file.find(id="methods")
# Children without their own page should be rendered on this page,
# and children with their own page should not be rendered on this page.
assert nested_class.find(id="package.Class.NestedClass.a_classmethod")
def test_exception(self, parse):
exception_path = "_build/html/autoapi/package/MyException.html"
exception_file = parse(exception_path)
exception_sig = exception_file.find(id="package.MyException")
assert exception_sig
exception = exception_sig.parent
docstring = exception.find_all("p")[1]
assert docstring.text == "This is an exception."
# There should be links to the children with their own page
pass # there are no children with their own page
# There should not be links to the children without their own page
assert not exception_file.find(id="attributes")
assert not exception_file.find(id="exceptions")
assert not exception_file.find(id="methods")
# Children without their own page should be rendered on this page,
# and children with their own page should not be rendered on this page.
pass # there are no children without their own page
def test_rendered_only_expected_pages(self):
_, dirs, files = next(os.walk("_build/html/autoapi/package"))
assert sorted(dirs) == ["submodule", "subpackage"]
assert sorted(files) == [
"Class.NestedClass.html",
"Class.html",
"MyException.html",
"index.html",
]
_, dirs, files = next(os.walk("_build/html/autoapi/package/submodule"))
assert not dirs
assert sorted(files) == [
"Class.NestedClass.html",
"Class.html",
"MyException.html",
"index.html",
]
_, dirs, files = next(os.walk("_build/html/autoapi/package/subpackage"))
assert dirs == ["submodule"]
assert files == ["index.html"]
_, dirs, files = next(
os.walk("_build/html/autoapi/package/subpackage/submodule")
)
assert not dirs
assert sorted(files) == [
"Class.NestedClass.html",
"Class.html",
"MyException.html",
"index.html",
]
def test_index(self, parse):
index_path = "_build/html/autoapi/index.html"
index_file = parse(index_path)
top_links = index_file.find_all(class_="toctree-l1")
top_hrefs = sorted(link.a["href"] for link in top_links)
assert top_hrefs == [
"#",
"package/index.html",
]
class TestFunction:
@pytest.fixture(autouse=True, scope="class")
def built(self, builder):
builder(
"pypackageexample",
warningiserror=True,
confoverrides={
"autoapi_own_page_level": "function",
"autoapi_options": [
"members",
"undoc-members",
"show-inheritance",
"imported-members",
],
},
)
def test_package(self, parse):
package_path = "_build/html/autoapi/package/index.html"
package_file = parse(package_path)
docstring = package_file.find("p")
assert docstring.text == "This is a docstring."
# There should be links to the children with their own page
submodules = package_file.find(id="submodules")
assert submodules
assert submodules.find("a", string="package.subpackage")
assert submodules.find("a", string="package.submodule")
classes = package_file.find(id="classes")
assert classes
assert classes.find("a", title="package.Class")
exceptions = package_file.find(id="exceptions")
assert exceptions
assert exceptions.find("a", title="package.MyException")
functions = package_file.find(id="functions")
assert functions
assert functions.find("a", title="package.function")
# There should not be links to the children without their own page
assert not package_file.find(id="attributes")
# Children without their own page should be rendered on this page,
# and children with their own page should not be rendered on this page.
contents = package_file.find(id="package-contents")
assert contents.find(id="package.DATA")
assert not contents.find(id="package.MyException")
assert not contents.find(id="package.Class")
assert not contents.find(id="package.Class.class_var")
assert not contents.find(id="package.Class.NestedClass")
assert not contents.find(id="package.Class.method_okay")
assert not contents.find(id="package.Class.NestedClass")
assert not contents.find(id="package.Class.NestedClass.a_classmethod")
assert not contents.find(id="package.function")
assert not contents.find(id="package.aliased_function")
# Hidden children are never rendered.
assert not contents.find(id="package.not_in_all_function")
def test_module(self, parse):
submodule_path = "_build/html/autoapi/package/submodule/index.html"
submodule_file = parse(submodule_path)
docstring = submodule_file.find("p")
assert docstring.text == "Example module"
# There should be links to the children with their own page
exceptions = submodule_file.find(id="exceptions")
assert exceptions
assert exceptions.find("a", title="package.submodule.MyException")
classes = submodule_file.find(id="classes")
assert classes
assert classes.find("a", title="package.submodule.Class")
assert not classes.find("a", title="package.submodule.Class.NestedClass")
functions = submodule_file.find(id="functions")
assert functions
assert functions.find("a", title="package.submodule.function")
# There should not be links to the children without their own page
assert not submodule_file.find(id="submodules")
assert not submodule_file.find(id="attributes")
# Children without their own page should be rendered on this page,
# and children with their own page should not be rendered on this page.
contents = submodule_file.find(id="module-contents")
assert contents.find(id="package.submodule.DATA")
assert not contents.find(id="package.submodule.MyException")
assert not contents.find(id="package.submodule.Class")
assert not contents.find(id="package.submodule.Class.class_var")
assert not contents.find(id="package.submodule.Class.NestedClass")
assert not contents.find(id="package.submodule.Class.method_okay")
assert not contents.find(id="package.submodule.Class.NestedClass")
assert not contents.find(id="package.submodule.Class.NestedClass.a_classmethod")
assert not contents.find(id="package.submodule.function")
assert not contents.find(id="package.submodule.aliased_function")
# Hidden children are never rendered.
assert not contents.find(id="package.submodule.not_in_all_function")
def test_class(self, parse):
class_path = "_build/html/autoapi/package/Class.html"
class_file = parse(class_path)
class_sig = class_file.find(id="package.Class")
assert class_sig
class_ = class_sig.parent
docstring = class_.find_all("p")[0]
assert docstring.text == "This is a class."
# There should be links to the children with their own page
classes = class_file.find(id="classes")
assert classes
assert classes.find("a", title="package.Class.NestedClass")
# There should not be links to the children without their own page
assert not class_file.find(id="attributes")
assert not class_file.find(id="exceptions")
assert not class_file.find(id="methods")
# Children without their own page should be rendered on this page,
# and children with their own page should not be rendered on this page.
assert class_.find(id="package.Class.class_var")
assert class_.find(id="package.Class.method_okay")
def test_function(self, parse):
function_path = "_build/html/autoapi/package/function.html"
function_file = parse(function_path)
function_sig = function_file.find(id="package.function")
assert function_sig
function_path = "_build/html/autoapi/package/submodule/function.html"
function_file = parse(function_path)
assert function_file.find(id="package.submodule.function")
def test_rendered_only_expected_pages(self):
_, dirs, files = next(os.walk("_build/html/autoapi/package"))
assert sorted(dirs) == ["submodule", "subpackage"]
assert sorted(files) == [
"Class.NestedClass.html",
"Class.html",
"MyException.html",
"aliased_function.html",
"function.html",
"index.html",
]
_, dirs, files = next(os.walk("_build/html/autoapi/package/submodule"))
assert not dirs
assert sorted(files) == [
"Class.NestedClass.html",
"Class.html",
"MyException.html",
"aliased_function.html",
"function.html",
"index.html",
]
_, dirs, files = next(os.walk("_build/html/autoapi/package/subpackage"))
assert dirs == ["submodule"]
assert sorted(files) == ["aliased_function.html", "function.html", "index.html"]
_, dirs, files = next(
os.walk("_build/html/autoapi/package/subpackage/submodule")
)
assert not dirs
assert sorted(files) == [
"Class.NestedClass.html",
"Class.html",
"MyException.html",
"function.html",
"index.html",
"not_in_all_function.html",
]
def test_index(self, parse):
index_path = "_build/html/autoapi/index.html"
index_file = parse(index_path)
top_links = index_file.find_all(class_="toctree-l1")
top_hrefs = sorted(link.a["href"] for link in top_links)
assert top_hrefs == [
"#",
"package/index.html",
]
class TestMethod:
@pytest.fixture(autouse=True, scope="class")
def built(self, builder):
builder(
"pypackageexample",
warningiserror=True,
confoverrides={
"autoapi_own_page_level": "method",
"autoapi_options": [
"members",
"undoc-members",
"show-inheritance",
"imported-members",
],
},
)
def test_package(self, parse):
package_path = "_build/html/autoapi/package/index.html"
package_file = parse(package_path)
docstring = package_file.find("p")
assert docstring.text == "This is a docstring."
# There should be links to the children with their own page
submodules = package_file.find(id="submodules")
assert submodules
assert submodules.find("a", string="package.subpackage")
assert submodules.find("a", string="package.submodule")
classes = package_file.find(id="classes")
assert classes
assert classes.find("a", title="package.Class")
exceptions = package_file.find(id="exceptions")
assert exceptions
assert exceptions.find("a", title="package.MyException")
functions = package_file.find(id="functions")
assert functions
assert functions.find("a", title="package.function")
# There should not be links to the children without their own page
assert not package_file.find(id="attributes")
# Children without their own page should be rendered on this page,
# and children with their own page should not be rendered on this page.
contents = package_file.find(id="package-contents")
assert contents.find(id="package.DATA")
assert not contents.find(id="package.MyException")
assert not contents.find(id="package.Class")
assert not contents.find(id="package.Class.class_var")
assert not contents.find(id="package.Class.NestedClass")
assert not contents.find(id="package.Class.method_okay")
assert not contents.find(id="package.Class.NestedClass")
assert not contents.find(id="package.Class.NestedClass.a_classmethod")
assert not contents.find(id="package.function")
assert not contents.find(id="package.aliased_function")
# Hidden children are never rendered.
assert not contents.find(id="package.not_in_all_function")
def test_module(self, parse):
submodule_path = "_build/html/autoapi/package/submodule/index.html"
submodule_file = parse(submodule_path)
docstring = submodule_file.find("p")
assert docstring.text == "Example module"
# There should be links to the children with their own page
exceptions = submodule_file.find(id="exceptions")
assert exceptions
assert exceptions.find("a", title="package.submodule.MyException")
classes = submodule_file.find(id="classes")
assert classes
assert classes.find("a", title="package.submodule.Class")
assert not classes.find("a", title="package.submodule.Class.NestedClass")
functions = submodule_file.find(id="functions")
assert functions
assert functions.find("a", title="package.submodule.function")
# There should not be links to the children without their own page
assert not submodule_file.find(id="submodules")
assert not submodule_file.find(id="attributes")
# Children without their own page should be rendered on this page,
# and children with their own page should not be rendered on this page.
contents = submodule_file.find(id="module-contents")
assert contents.find(id="package.submodule.DATA")
assert not contents.find(id="package.submodule.MyException")
assert not contents.find(id="package.submodule.Class")
assert not contents.find(id="package.submodule.Class.class_var")
assert not contents.find(id="package.submodule.Class.NestedClass")
assert not contents.find(id="package.submodule.Class.method_okay")
assert not contents.find(id="package.submodule.Class.NestedClass")
assert not contents.find(id="package.submodule.Class.NestedClass.a_classmethod")
assert not contents.find(id="package.submodule.function")
assert not contents.find(id="package.submodule.aliased_function")
# Hidden children are never rendered.
assert not contents.find(id="package.submodule.not_in_all_function")
def test_class(self, parse):
class_path = "_build/html/autoapi/package/Class.html"
class_file = parse(class_path)
class_sig = class_file.find(id="package.Class")
assert class_sig
class_ = class_sig.parent
docstring = class_.find_all("p")[0]
assert docstring.text == "This is a class."
# There should be links to the children with their own page
classes = class_file.find(id="classes")
assert classes
assert classes.find("a", title="package.Class.NestedClass")
methods = class_file.find(id="methods")
assert methods
assert methods.find("a", title="package.Class.method_okay")
# There should not be links to the children without their own page
assert not class_file.find(id="attributes")
assert not class_file.find(id="exceptions")
# Children without their own page should be rendered on this page,
# and children with their own page should not be rendered on this page.
assert class_.find(id="package.Class.class_var")
assert not class_.find(id="package.Class.method_okay")
def test_function(self, parse):
function_path = "_build/html/autoapi/package/function.html"
function_file = parse(function_path)
function_sig = function_file.find(id="package.function")
assert function_sig
function_path = "_build/html/autoapi/package/submodule/function.html"
function_file = parse(function_path)
assert function_file.find(id="package.submodule.function")
def test_method(self, parse):
method_path = "_build/html/autoapi/package/Class.method_okay.html"
method_file = parse(method_path)
method_sig = method_file.find(id="package.Class.method_okay")
assert method_sig
method_path = "_build/html/autoapi/package/submodule/Class.method_okay.html"
method_file = parse(method_path)
assert method_file.find(id="package.submodule.Class.method_okay")
def test_rendered_only_expected_pages(self):
_, dirs, files = next(os.walk("_build/html/autoapi/package"))
assert sorted(dirs) == ["submodule", "subpackage"]
assert sorted(files) == [
"Class.NestedClass.a_classmethod.html",
"Class.NestedClass.html",
"Class.html",
"Class.method_okay.html",
"MyException.html",
"aliased_function.html",
"function.html",
"index.html",
]
_, dirs, files = next(os.walk("_build/html/autoapi/package/submodule"))
assert not dirs
assert sorted(files) == [
"Class.NestedClass.a_classmethod.html",
"Class.NestedClass.html",
"Class.html",
"Class.method_google_docs.html",
"Class.method_multiline.html",
"Class.method_okay.html",
"Class.method_sphinx_docs.html",
"Class.method_tricky.html",
"MyException.html",
"aliased_function.html",
"function.html",
"index.html",
]
_, dirs, files = next(os.walk("_build/html/autoapi/package/subpackage"))
assert dirs == ["submodule"]
assert sorted(files) == ["aliased_function.html", "function.html", "index.html"]
_, dirs, files = next(
os.walk("_build/html/autoapi/package/subpackage/submodule")
)
assert not dirs
assert sorted(files) == [
"Class.NestedClass.a_classmethod.html",
"Class.NestedClass.html",
"Class.html",
"Class.method_okay.html",
"MyException.html",
"function.html",
"index.html",
"not_in_all_function.html",
]
def test_index(self, parse):
index_path = "_build/html/autoapi/index.html"
index_file = parse(index_path)
top_links = index_file.find_all(class_="toctree-l1")
top_hrefs = sorted(link.a["href"] for link in top_links)
assert top_hrefs == [
"#",
"package/index.html",
]
class TestAttribute:
@pytest.fixture(autouse=True, scope="class")
def built(self, builder):
builder(
"pypackageexample",
warningiserror=True,
confoverrides={
"autoapi_own_page_level": "attribute",
"autoapi_options": [
"members",
"undoc-members",
"show-inheritance",
"imported-members",
],
},
)
# TODO: Include a test for a property
def test_package(self, parse):
package_path = "_build/html/autoapi/package/index.html"
package_file = parse(package_path)
docstring = package_file.find("p")
assert docstring.text == "This is a docstring."
# There should be links to the children with their own page
submodules = package_file.find(id="submodules")
assert submodules
assert submodules.find("a", string="package.subpackage")
assert submodules.find("a", string="package.submodule")
classes = package_file.find(id="classes")
assert classes
assert classes.find("a", title="package.Class")
exceptions = package_file.find(id="exceptions")
assert exceptions
assert exceptions.find("a", title="package.MyException")
functions = package_file.find(id="functions")
assert functions
assert functions.find("a", title="package.function")
attributes = package_file.find(id="attributes")
assert attributes
assert attributes.find("a", title="package.DATA")
# There should not be links to the children without their own page
pass # there are no children without their own page
# Children without their own page should be rendered on this page,
# and children with their own page should not be rendered on this page.
# Hidden children are never rendered.
assert not package_file.find(id="package-contents")
def test_module(self, parse):
submodule_path = "_build/html/autoapi/package/submodule/index.html"
submodule_file = parse(submodule_path)
docstring = submodule_file.find("p")
assert docstring.text == "Example module"
# There should be links to the children with their own page
exceptions = submodule_file.find(id="exceptions")
assert exceptions
assert exceptions.find("a", title="package.submodule.MyException")
classes = submodule_file.find(id="classes")
assert classes
assert classes.find("a", title="package.submodule.Class")
assert not classes.find("a", title="package.submodule.Class.NestedClass")
functions = submodule_file.find(id="functions")
assert functions
assert functions.find("a", title="package.submodule.function")
attributes = submodule_file.find(id="attributes")
assert attributes
assert attributes.find("a", title="package.submodule.DATA")
# There should not be links to the children without their own page
assert not submodule_file.find(id="submodules")
# Children without their own page should be rendered on this page,
# and children with their own page should not be rendered on this page.
# Hidden children are never rendered.
assert not submodule_file.find(id="module-contents")
def test_class(self, parse):
class_path = "_build/html/autoapi/package/Class.html"
class_file = parse(class_path)
class_sig = class_file.find(id="package.Class")
assert class_sig
class_ = class_sig.parent
docstring = class_.find_all("p")[0]
assert docstring.text == "This is a class."
# There should be links to the children with their own page
classes = class_file.find(id="classes")
assert classes
assert classes.find("a", title="package.Class.NestedClass")
methods = class_file.find(id="methods")
assert methods
assert methods.find("a", title="package.Class.method_okay")
attributes = class_file.find(id="attributes")
assert attributes
assert attributes.find("a", title="package.Class.class_var")
# There should not be links to the children without their own page
assert not class_file.find(id="exceptions")
# Children without their own page should be rendered on this page,
# and children with their own page should not be rendered on this page.
assert not class_.find(id="package.Class.class_var")
assert not class_.find(id="package.Class.method_okay")
def test_function(self, parse):
function_path = "_build/html/autoapi/package/function.html"
function_file = parse(function_path)
function_sig = function_file.find(id="package.function")
assert function_sig
function_path = "_build/html/autoapi/package/submodule/function.html"
function_file = parse(function_path)
assert function_file.find(id="package.submodule.function")
def test_method(self, parse):
method_path = "_build/html/autoapi/package/Class.method_okay.html"
method_file = parse(method_path)
method_sig = method_file.find(id="package.Class.method_okay")
assert method_sig
method_path = "_build/html/autoapi/package/submodule/Class.method_okay.html"
method_file = parse(method_path)
assert method_file.find(id="package.submodule.Class.method_okay")
def test_data(self, parse):
data_path = "_build/html/autoapi/package/DATA.html"
data_file = parse(data_path)
data_sig = data_file.find(id="package.DATA")
assert data_sig
def test_attribute(self, parse):
attribute_path = "_build/html/autoapi/package/Class.class_var.html"
attribute_file = parse(attribute_path)
attribute_sig = attribute_file.find(id="package.Class.class_var")
assert attribute_sig
def test_rendered_only_expected_pages(self):
_, dirs, files = next(os.walk("_build/html/autoapi/package"))
assert sorted(dirs) == ["submodule", "subpackage"]
assert sorted(files) == [
"Class.NestedClass.a_classmethod.html",
"Class.NestedClass.html",
"Class.class_var.html",
"Class.html",
"Class.method_okay.html",
"DATA.html",
"MyException.html",
"aliased_function.html",
"function.html",
"index.html",
]
_, dirs, files = next(os.walk("_build/html/autoapi/package/submodule"))
assert not dirs
assert sorted(files) == [
"Class.NestedClass.a_classmethod.html",
"Class.NestedClass.html",
"Class.class_var.html",
"Class.html",
"Class.method_google_docs.html",
"Class.method_multiline.html",
"Class.method_okay.html",
"Class.method_sphinx_docs.html",
"Class.method_tricky.html",
"DATA.html",
"MyException.html",
"aliased_function.html",
"function.html",
"index.html",
]
_, dirs, files = next(os.walk("_build/html/autoapi/package/subpackage"))
assert dirs == ["submodule"]
assert sorted(files) == ["aliased_function.html", "function.html", "index.html"]
_, dirs, files = next(
os.walk("_build/html/autoapi/package/subpackage/submodule")
)
assert not dirs
assert sorted(files) == [
"Class.NestedClass.a_classmethod.html",
"Class.NestedClass.html",
"Class.class_var.html",
"Class.html",
"Class.method_okay.html",
"DATA.html",
"MyException.html",
"function.html",
"index.html",
"not_in_all_function.html",
]
def test_index(self, parse):
index_path = "_build/html/autoapi/index.html"
index_file = parse(index_path)
top_links = index_file.find_all(class_="toctree-l1")
top_hrefs = sorted(link.a["href"] for link in top_links)
assert top_hrefs == [
"#",
"package/index.html",
]
@pytest.mark.parametrize(
"value", ["package", "exception", "property", "data", "not_a_value"]
)
def test_invalid_values(builder, value):
"""Test failure when autoapi_own_page_level is invalid."""
with pytest.raises(ValueError):
builder(
"pypackageexample",
confoverrides={
"autoapi_own_page_level": value,
},
)
sphinx-autoapi-3.3.3/tests/python/test_parser.py 0000664 0000000 0000000 00000007253 14707035566 0022105 0 ustar 00root root 0000000 0000000 """Test Python parser"""
import astroid
from autoapi._parser import Parser
class TestPythonParser:
def parse(self, source):
node = astroid.extract_node(source)
return Parser().parse(node)
def test_parses_basic_file(self):
source = """
def foo(bar):
pass
"""
data = self.parse(source)[0]
assert data["name"] == "foo"
assert data["type"] == "function"
def test_parses_all(self):
source = """
__all__ = ['Foo', 5.0]
"""
data = self.parse(source)[0]
assert data["name"] == "__all__"
assert data["value"] == "['Foo', 5.0]"
def test_parses_all_multiline(self):
source = """
__all__ = [
'foo',
'bar',
]
"""
data = self.parse(source)[0]
assert data["value"] == "['foo', 'bar']"
def test_parses_name(self):
source = "foo.bar"
assert self.parse(source) == []
def test_parses_list(self):
name = "__all__"
value = "[1, 2, 3, 4]"
source = f"{name} = {value}"
data = self.parse(source)[0]
assert data["name"] == name
assert data["value"] == value
def test_parses_nested_list(self):
name = "__all__"
value = "[[1, 2], [3, 4]]"
source = f"{name} = {value}"
data = self.parse(source)[0]
assert data["name"] == name
assert data["value"] == value
def test_arguments(self):
"""Argument parsing of source"""
source = (
"def foobar(self, bar, baz=42, foo=True,\n"
" *args, **kwargs):\n"
' "This is a docstring"\n'
" return True\n"
)
data = self.parse(source)[0]
expected = [
(None, "self", None, None),
(None, "bar", None, None),
(None, "baz", None, "42"),
(None, "foo", None, "True"),
("*", "args", None, None),
("**", "kwargs", None, None),
]
assert data["args"] == expected
def test_advanced_arguments(self):
"""Advanced argument parsing"""
source = (
'def foobar(self, a, b, c=42, d="string", e=(1,2),\n'
' f={"a": True}, g=None, h=[1,2,3,4],\n'
" i=dict(a=True), j=False, *args, **kwargs):\n"
' "This is a docstring"\n'
" return True\n"
)
data = self.parse(source)[0]
expected = [
(None, "self", None, None),
(None, "a", None, None),
(None, "b", None, None),
(None, "c", None, "42"),
(None, "d", None, "'string'"),
(None, "e", None, "(1, 2)"),
(None, "f", None, "{'a': True}"),
(None, "g", None, "None"),
(None, "h", None, "[1, 2, 3, 4]"),
(None, "i", None, "dict(a=True)"),
(None, "j", None, "False"),
("*", "args", None, None),
("**", "kwargs", None, None),
]
assert data["args"] == expected
def test_dict_key_assignment(self):
"""Ignore assignment to dictionary entries."""
source = """
MY_DICT = {} #@
if condition:
MY_DICT['key'] = 'value'
MY_DICT['key2'] = 'value2'
"""
data = self.parse(source)[0]
assert data["name"] == "MY_DICT"
def test_list_index_assignment(self):
"""Ignore assignment to indexes."""
source = """
COLOUR = [255, 128, 0] #@
if condition:
COLOUR[1] = 255
COLOUR[2] = 255
"""
data = self.parse(source)[0]
assert data["name"] == "COLOUR"
sphinx-autoapi-3.3.3/tests/python/test_pyintegration.py 0000664 0000000 0000000 00000143362 14707035566 0023507 0 ustar 00root root 0000000 0000000 import logging
import os
import pathlib
import sys
from unittest.mock import Mock, call
import autoapi.settings
from autoapi._objects import (
PythonClass,
PythonData,
PythonFunction,
PythonMethod,
PythonModule,
)
from packaging import version
import pytest
import sphinx
from sphinx.application import Sphinx
from sphinx.errors import ExtensionError
import sphinx.util.logging
sphinx_version = version.parse(sphinx.__version__).release
class TestSimpleModule:
@pytest.fixture(autouse=True, scope="class")
def built(self, builder):
builder(
"pyexample",
warningiserror=True,
confoverrides={"exclude_patterns": ["manualapi.rst"]},
)
def test_integration(self, parse):
self.check_integration(parse, "_build/html/autoapi/example/index.html")
index_file = parse("_build/html/index.html")
toctree = index_file.select("li > a")
assert any(item.text == "API Reference" for item in toctree)
def check_integration(self, parse, example_path):
example_file = parse(example_path)
foo_sig = example_file.find(id="example.Foo")
assert foo_sig
assert foo_sig.find(class_="sig-name").text == "Foo"
assert foo_sig.find(class_="sig-param").text == "attr"
# Check that nested classes are documented
foo = foo_sig.parent
assert foo.find(id="example.Foo.Meta")
# Check that class attributes are documented
attr = foo.find(id="example.Foo.attr")
assert attr
assert attr.find(class_="pre").text.strip() == "property"
attr2 = foo.find(id="example.Foo.attr2")
assert "attr2" in attr2.text
# Check that attribute docstrings are used
assert attr2.parent.find("dd").text.startswith(
"This is the docstring of an instance attribute."
)
method_okay = foo.find(id="example.Foo.method_okay")
assert method_okay
args = method_okay.find_all(class_="sig-param")
assert len(args) == 2
assert args[0].text == "foo=None"
assert args[1].text == "bar=None"
method_multiline = foo.find(id="example.Foo.method_multiline")
assert method_multiline
args = method_multiline.find_all(class_="sig-param")
assert len(args) == 3
assert args[0].text == "foo=None"
assert args[1].text == "bar=None"
assert args[2].text == "baz=None"
method_tricky = foo.find(id="example.Foo.method_tricky")
assert method_tricky
args = method_tricky.find_all(class_="sig-param")
assert len(args) == 2
assert args[0].text == "foo=None"
assert args[1].text == "bar=dict(foo=1, bar=2)"
# Are constructor arguments from the class docstring parsed?
init_args = foo.parent.find_next(class_="field-list")
assert "Set an attribute" in init_args.text
# "self" should not be included in constructor arguments
assert len(foo_sig.find_all(class_="sig-param")) == 1
property_simple = foo.find(id="example.Foo.property_simple")
assert property_simple
assert (
property_simple.parent.find("dd").text.strip()
== "This property should parse okay."
)
my_cached_property = foo.find(id="example.Foo.my_cached_property")
assert my_cached_property
assert my_cached_property.find(class_="pre").text.strip() == "property"
# Overridden methods without their own docstring
# should inherit the parent's docstring
bar_method_okay = example_file.find(id="example.Bar.method_okay")
assert (
bar_method_okay.parent.find("dd").text.strip()
== "This method should parse okay"
)
assert not os.path.exists("_build/html/autoapi/method_multiline")
# Inherited constructor docstrings should be included in a merged
# (autoapi_python_class_content="both") class docstring only once.
two = example_file.find(id="example.Two")
assert two.parent.find("dd").text.count("One __init__") == 1
# Tuples should be rendered as tuples, not lists
a_tuple = example_file.find(id="example.A_TUPLE")
assert a_tuple.find(class_="property").text.endswith("('a', 'b')")
# Lists should be rendered as lists, not tuples
a_list = example_file.find(id="example.A_LIST")
assert a_list.find(class_="property").text.endswith("['c', 'd']")
# Assigning a class level attribute at the module level
# should not get documented as a module level attribute.
assert "dinglebop" not in example_file.text
index_file = parse("_build/html/index.html")
toctree = index_file.select("li > a")
assert any(item.text == "Foo" for item in toctree)
assert any(item.text == "Foo.Meta" for item in toctree)
def test_napoleon_integration_not_loaded(self, parse):
example_file = parse("_build/html/autoapi/example/index.html")
# Check that docstrings are not transformed without napoleon loaded
method_google = example_file.find(id="example.Foo.method_google_docs")
assert "Args" in method_google.parent.find("dd").text
assert "Returns" in method_google.parent.find("dd").text
def test_show_inheritance(self, parse):
example_file = parse("_build/html/autoapi/example/index.html")
bar = example_file.find(id="example.Bar")
bar_docstring = bar.parent.find("dd").contents[0]
assert bar_docstring.text.startswith("Bases:")
def test_long_signature(self, parse):
example_file = parse("_build/html/autoapi/example/index.html")
summary_row = example_file.find_all(class_="autosummary")[-1].find_all("tr")[-1]
assert summary_row
cells = summary_row.find_all("td")
assert (
cells[0].text.replace("\xa0", " ")
== "fn_with_long_sig(this, *[, function, has, quite])"
)
assert cells[1].text.strip() == "A function with a long signature."
class TestSimpleModuleManual:
@pytest.fixture(autouse=True, scope="class")
def built(self, builder):
builder(
"pyexample",
warningiserror=True,
confoverrides={
"autoapi_generate_api_docs": False,
"autoapi_add_toctree_entry": False,
},
)
def test_manual_directives(self, parse):
example_file = parse("_build/html/manualapi.html")
assert example_file.find(id="example.decorator_okay")
def test_dataclass(self, parse):
example_file = parse("_build/html/manualapi.html")
typedattrs_sig = example_file.find(id="example.TypedAttrs")
assert typedattrs_sig
typedattrs = typedattrs_sig.parent
one = typedattrs.find(id="example.TypedAttrs.one")
assert one
one_value = one.find_all(class_="property")
assert one_value[0].text == ": str"
one_docstring = one.parent.find("dd").contents[0].text
assert one_docstring.strip() == "This is TypedAttrs.one."
two = typedattrs.find(id="example.TypedAttrs.two")
assert two
two_value = two.find_all(class_="property")
assert two_value[0].text == ": int"
assert two_value[1].text == " = 1"
two_docstring = two.parent.find("dd").contents[0].text
assert two_docstring.strip() == "This is TypedAttrs.two."
def test_data(self, parse):
example_file = parse("_build/html/manualapi.html")
typed_data = example_file.find(id="example.TYPED_DATA")
assert typed_data
typed_data_value = typed_data.find_all(class_="property")
assert typed_data_value[0].text == ": int"
assert typed_data_value[1].text == " = 1"
typed_data_docstring = typed_data.parent.find("dd").contents[0].text
assert typed_data_docstring.strip() == "This is TYPED_DATA."
def test_class(self, parse):
example_file = parse("_build/html/manualapi.html")
typed_cls = example_file.find(id="example.TypedClassInit")
assert typed_cls
arg = typed_cls.find(class_="sig-param")
assert arg.text == "one: int = 1"
typed_cls_docstring = typed_cls.parent.find("dd").contents[0].text
assert typed_cls_docstring.strip() == "This is TypedClassInit."
typed_method = example_file.find(id="example.TypedClassInit.typed_method")
assert typed_method
arg = typed_method.find(class_="sig-param")
assert arg.text == "two: int"
return_type = typed_method.find(class_="sig-return-typehint")
assert return_type.text == "int"
typed_method_docstring = typed_method.parent.find("dd").contents[0].text
assert typed_method_docstring.strip() == "This is TypedClassInit.typed_method."
def test_property(self, parse):
example_file = parse("_build/html/manualapi.html")
foo_sig = example_file.find(id="example.Foo")
assert foo_sig
foo = foo_sig.parent
property_simple = foo.find(id="example.Foo.property_simple")
assert property_simple
property_simple_value = property_simple.find_all(class_="property")
assert property_simple_value[-1].text == ": int"
property_simple_docstring = property_simple.parent.find("dd").text.strip()
assert property_simple_docstring == "This property should parse okay."
class TestMovedConfPy(TestSimpleModule):
@pytest.fixture(autouse=True, scope="class")
def built(self, builder):
builder(
"pymovedconfpy",
confdir="confpy",
warningiserror=True,
confoverrides={"exclude_patterns": ["manualapi.rst"]},
)
class TestSimpleModuleDifferentPrimaryDomain(TestSimpleModule):
@pytest.fixture(autouse=True, scope="class")
def built(self, builder):
builder(
"pyexample",
warningiserror=True,
confoverrides={
"exclude_patterns": ["manualapi.rst"],
"primary_domain": "cpp",
},
)
class TestSimpleStubModule:
@pytest.fixture(autouse=True, scope="class")
def built(self, builder):
builder("pyiexample", warningiserror=True)
def test_integration(self, parse):
example_file = parse("_build/html/autoapi/example/index.html")
# Are pyi files preferred
assert "DoNotFindThis" not in example_file
foo_sig = example_file.find(id="example.Foo")
assert foo_sig
foo = foo_sig.parent
assert foo.find(id="example.Foo.Meta")
class_var = foo.find(id="example.Foo.another_class_var")
class_var_docstring = class_var.parent.find("dd").contents[0].text
assert class_var_docstring.strip() == "Another class var docstring"
class_var = foo.find(id="example.Foo.class_var_without_value")
class_var_docstring = class_var.parent.find("dd").contents[0].text
assert class_var_docstring.strip() == "A class var without a value."
method_okay = foo.find(id="example.Foo.method_okay")
assert method_okay
method_multiline = foo.find(id="example.Foo.method_multiline")
assert method_multiline
method_without_docstring = foo.find(id="example.Foo.method_without_docstring")
assert method_without_docstring
# Are constructor arguments from the class docstring parsed?
init_args = foo.parent.find_next(class_="field-list")
assert "Set an attribute" in init_args.text
class TestSimpleStubModuleNotPreferred:
@pytest.fixture(autouse=True, scope="class")
def built(self, builder):
builder("pyiexample2", warningiserror=True)
def test_integration(self, parse):
example_file = parse("_build/html/autoapi/example/index.html")
# Are py files preferred
assert "DoNotFindThis" not in example_file
foo_sig = example_file.find(id="example.Foo")
assert foo_sig
class TestStubInitModuleInSubmodule:
@pytest.fixture(autouse=True, scope="class")
def built(self, builder):
builder("pyisubmoduleinit", warningiserror=True)
def test_integration(self, parse):
example_file = parse("_build/html/autoapi/example/index.html")
# Documentation should list
# submodule_foo instead of __init__
assert example_file.find(title="submodule_foo")
assert not example_file.find(title="__init__")
class TestPy3Module:
@pytest.fixture(autouse=True, scope="class")
def built(self, builder):
builder("py3example")
def test_integration(self, parse):
example_file = parse("_build/html/autoapi/example/index.html")
assert "Initialize self" not in example_file
assert "a new type" not in example_file
def test_inheritance(self, parse):
example_file = parse("_build/html/autoapi/example/index.html")
# Test that members are not inherited from standard library classes.
assert example_file.find(id="example.MyException")
assert not example_file.find(id="example.MyException.args")
# With the exception of abstract base classes.
assert example_file.find(id="example.My123")
assert example_file.find(id="example.My123.__contains__")
assert example_file.find(id="example.My123.index")
# Test that classes inherit instance attributes
exc = example_file.find(id="example.InheritError")
assert exc
message = example_file.find(id="example.InheritError.my_message")
assert message
message_docstring = message.parent.find("dd").text.strip()
assert message_docstring == "My message."
# Test that classes inherit from the whole mro
exc = example_file.find(id="example.SubInheritError")
assert exc
message = example_file.find(id="example.SubInheritError.my_message")
message_docstring = message.parent.find("dd").text.strip()
assert message_docstring == "My message."
message = example_file.find(id="example.SubInheritError.my_other_message")
assert message
message_docstring = message.parent.find("dd").text.strip()
assert message_docstring == "My other message."
# Test that inherited instance attributes include the docstring
exc = example_file.find(id="example.DuplicateInheritError")
assert exc
message = example_file.find(id="example.DuplicateInheritError.my_message")
assert message
message_docstring = message.parent.find("dd").text.strip()
assert message_docstring == "My message."
def test_annotations(self, parse):
example_file = parse("_build/html/autoapi/example/index.html")
software = example_file.find(id="example.software")
assert software
software_value = software.find(class_="property").contents[-1]
assert software_value.text.endswith('''"sphin'x"''')
more_software = example_file.find(id="example.more_software")
assert more_software
more_software_value = more_software.find(class_="property").contents[-1]
assert more_software_value.text.endswith("""'sphinx"autoapi'""")
interesting = example_file.find(id="example.interesting_string")
assert interesting
interesting_value = interesting.find(class_="property").contents[-1]
assert interesting_value.text.endswith("'interesting\"fun\\'\\\\\\'string'")
code_snippet = example_file.find(id="example.code_snippet")
assert code_snippet
code_snippet_value = code_snippet.find(class_="property").contents[-1]
assert code_snippet_value.text == "Multiline-String"
max_rating = example_file.find(id="example.max_rating")
assert max_rating
max_rating_value = max_rating.find_all(class_="property")
assert max_rating_value[0].text == ": int"
assert max_rating_value[1].text == " = 10"
# TODO: This should either not have a value
# or should display the value as part of the type declaration.
# This prevents setting warningiserror.
assert example_file.find(id="example.is_valid")
ratings = example_file.find(id="example.ratings")
assert ratings
ratings_value = ratings.find_all(class_="property")
assert "List[int]" in ratings_value[0].text
rating_names = example_file.find(id="example.rating_names")
assert rating_names
rating_names_value = rating_names.find_all(class_="property")
assert "Dict[int, str]" in rating_names_value[0].text
f = example_file.find(id="example.f")
assert f
assert f.find(class_="sig-param").text == "start: int"
assert f.find(class_="sig-return-typehint").text == "Iterable[int]"
mixed_list = example_file.find(id="example.mixed_list")
assert mixed_list
mixed_list_value = mixed_list.find_all(class_="property")
if sphinx_version >= (6,):
assert "List[str | int]" in mixed_list_value[0].text
else:
assert "List[Union[str, int]]" in mixed_list_value[0].text
f2 = example_file.find(id="example.f2")
assert f2
arg = f2.find(class_="sig-param")
assert arg.contents[0].text == "not_yet_a"
assert arg.find("a").text == "A"
f3 = example_file.find(id="example.f3")
assert f3
arg = f3.find(class_="sig-param")
assert arg.contents[0].text == "imported"
assert arg.find("a").text == "example2.B"
returns = f3.find(class_="sig-return-typehint")
assert returns.find("a").text == "example2.B"
is_an_a = example_file.find(id="example.A.is_an_a")
assert is_an_a
is_an_a_value = is_an_a.find_all(class_="property")
assert "ClassVar" in is_an_a_value[0].text
assert example_file.find(id="example.A.instance_var")
# Locals are excluded
assert not example_file.find(id="example.A.local_variable_typed")
assert not example_file.find(id="example.A.local_variable_untyped")
# Assignments to subobjects are excluded
assert not example_file.find(id="example.A.subobject_variable")
global_a = example_file.find(id="example.global_a")
assert global_a
global_a_value = global_a.find_all(class_="property")
assert global_a_value[0].text == ": A"
assert example_file.find(id="example.SomeMetaclass")
def test_overload(self, parse):
example_file = parse("_build/html/autoapi/example/index.html")
overloaded_func = example_file.find(id="example.overloaded_func")
assert overloaded_func
arg = overloaded_func.find(class_="sig-param")
assert arg.text == "a: float"
overloaded_func = overloaded_func.next_sibling.next_sibling
arg = overloaded_func.find(class_="sig-param")
assert arg.text == "a: str"
docstring = overloaded_func.next_sibling.next_sibling
assert docstring.tag != "dt"
assert docstring.text.strip() == "Overloaded function"
overloaded_method = example_file.find(id="example.A.overloaded_method")
assert overloaded_method
arg = overloaded_method.find(class_="sig-param")
assert arg.text == "a: float"
overloaded_method = overloaded_method.next_sibling.next_sibling
arg = overloaded_method.find(class_="sig-param")
assert arg.text == "a: str"
docstring = overloaded_method.next_sibling.next_sibling
assert docstring.tag != "dt"
assert docstring.text.strip() == "Overloaded method"
overloaded_class_method = example_file.find(
id="example.A.overloaded_class_method"
)
assert overloaded_class_method
arg = overloaded_class_method.find(class_="sig-param")
assert arg.text == "a: float"
overloaded_class_method = overloaded_class_method.next_sibling.next_sibling
arg = overloaded_class_method.find(class_="sig-param")
assert arg.text == "a: str"
docstring = overloaded_class_method.next_sibling.next_sibling
assert docstring.tag != "dt"
assert docstring.text.strip() == "Overloaded class method"
assert example_file.find(id="example.undoc_overloaded_func")
assert example_file.find(id="example.A.undoc_overloaded_method")
c = example_file.find(id="example.C")
assert c
arg = c.find(class_="sig-param")
assert arg.text == "a: int"
c = c.next_sibling.next_sibling
arg = c.find(class_="sig-param")
assert arg.text == "a: float"
docstring = c.next_sibling.next_sibling
assert docstring.tag != "dt"
# D inherits overloaded constructor
d = example_file.find(id="example.D")
assert d
arg = d.find(class_="sig-param")
assert arg.text == "a: int"
d = d.next_sibling.next_sibling
arg = d.find(class_="sig-param")
assert arg.text == "a: float"
docstring = d.next_sibling.next_sibling
assert docstring.tag != "dt"
def test_async(self, parse):
example_file = parse("_build/html/autoapi/example/index.html")
async_method = example_file.find(id="example.A.async_method")
assert async_method.find(class_="property").text.strip() == "async"
async_function = example_file.find(id="example.async_function")
assert async_function.find(class_="property").text.strip() == "async"
def test_py3_hiding_undoc_overloaded_members(builder, parse):
confoverrides = {"autoapi_options": ["members", "special-members"]}
builder("py3example", confoverrides=confoverrides)
example_file = parse("_build/html/autoapi/example/index.html")
overloaded_func = example_file.find(id="example.overloaded_func")
assert overloaded_func
overloaded_method = example_file.find(id="example.A.overloaded_method")
assert overloaded_method
assert not example_file.find(id="example.undoc_overloaded_func")
assert not example_file.find(id="example.A.undoc_overloaded_method")
class TestAnnotationCommentsModule:
@pytest.fixture(autouse=True, scope="class")
def built(self, builder):
builder("pyannotationcommentsexample", warningiserror=True)
def test_integration(self, parse):
example_file = parse("_build/html/autoapi/example/index.html")
max_rating = example_file.find(id="example.max_rating")
assert max_rating
max_rating_value = max_rating.find_all(class_="property")
assert max_rating_value[0].text == ": int"
assert max_rating_value[1].text == " = 10"
ratings = example_file.find(id="example.ratings")
assert ratings
ratings_value = ratings.find_all(class_="property")
assert "List[int]" in ratings_value[0].text
rating_names = example_file.find(id="example.rating_names")
assert rating_names
rating_names_value = rating_names.find_all(class_="property")
assert "Dict[int, str]" in rating_names_value[0].text
f = example_file.find(id="example.f")
assert f
assert f.find(class_="sig-param").text == "start: int"
assert f.find(class_="sig-return-typehint").text == "Iterable[int]"
mixed_list = example_file.find(id="example.mixed_list")
assert mixed_list
mixed_list_value = mixed_list.find_all(class_="property")
if sphinx_version >= (6,):
assert "List[str | int]" in mixed_list_value[0].text
else:
assert "List[Union[str, int]]" in mixed_list_value[0].text
f2 = example_file.find(id="example.f2")
assert f2
arg = f2.find(class_="sig-param")
assert arg.contents[0].text == "not_yet_a"
assert arg.find("a").text == "A"
is_an_a = example_file.find(id="example.A.is_an_a")
assert is_an_a
is_an_a_value = is_an_a.find_all(class_="property")
assert "ClassVar" in is_an_a_value[0].text
assert example_file.find(id="example.A.instance_var")
global_a = example_file.find(id="example.global_a")
assert global_a
global_a_value = global_a.find_all(class_="property")
assert global_a_value[0].text == ": A"
@pytest.mark.skipif(
sys.version_info < (3, 8), reason="Positional only arguments need Python >=3.8"
)
class TestPositionalOnlyArgumentsModule:
@pytest.fixture(autouse=True, scope="class")
def built(self, builder):
builder("py38positionalparams", warningiserror=True)
def test_integration(self, parse):
example_file = parse("_build/html/autoapi/example/index.html")
f_simple = example_file.find(id="example.f_simple")
assert "f_simple(a, b, /, c, d, *, e, f)" in f_simple.text
if sphinx_version >= (6,):
f_comment = example_file.find(id="example.f_comment")
assert (
"f_comment(a: int, b: int, /, c: int | None, d: int | None, *, e: float, f: float)"
in f_comment.text
)
f_annotation = example_file.find(id="example.f_annotation")
assert (
"f_annotation(a: int, b: int, /, c: int | None, d: int | None, *, e: float, f: float)"
in f_annotation.text
)
f_arg_comment = example_file.find(id="example.f_arg_comment")
assert (
"f_arg_comment(a: int, b: int, /, c: int | None, d: int | None, *, e: float, f: float)"
in f_arg_comment.text
)
else:
f_comment = example_file.find(id="example.f_comment")
assert (
"f_comment(a: int, b: int, /, c: Optional[int], d: Optional[int], *, e: float, f: float)"
in f_comment.text
)
f_annotation = example_file.find(id="example.f_annotation")
assert (
"f_annotation(a: int, b: int, /, c: Optional[int], d: Optional[int], *, e: float, f: float)"
in f_annotation.text
)
f_arg_comment = example_file.find(id="example.f_arg_comment")
assert (
"f_arg_comment(a: int, b: int, /, c: Optional[int], d: Optional[int], *, e: float, f: float)"
in f_arg_comment.text
)
f_no_cd = example_file.find(id="example.f_no_cd")
assert "f_no_cd(a: int, b: int, /, *, e: float, f: float)" in f_no_cd.text
@pytest.mark.network
@pytest.mark.skipif(
sys.version_info < (3, 10), reason="Union pipe syntax requires Python >=3.10"
)
class TestPipeUnionModule:
@pytest.fixture(autouse=True, scope="class")
def built(self, builder):
builder("py310unionpipe", warningiserror=True)
def test_integration(self, parse):
example_file = parse("_build/html/autoapi/example/index.html")
simple = example_file.find(id="example.simple")
args = simple.find_all(class_="sig-param")
assert len(args) == 1
links = args[0].select("span > a")
assert len(links) == 1
assert links[0].text == "pathlib.Path"
optional = example_file.find(id="example.optional")
args = optional.find_all(class_="sig-param")
assert len(args) == 1
links = args[0].select("span > a")
assert len(links) == 2
assert links[0].text == "pathlib.Path"
assert links[1].text == "None"
union = example_file.find(id="example.union")
args = union.find_all(class_="sig-param")
assert len(args) == 1
links = args[0].select("span > a")
assert len(links) == 2
assert links[0].text == "pathlib.Path"
assert links[1].text == "None"
pipe = example_file.find(id="example.pipe")
args = pipe.find_all(class_="sig-param")
assert len(args) == 1
links = args[0].select("span > a")
assert len(links) == 2
assert links[0].text == "pathlib.Path"
assert links[1].text == "None"
@pytest.mark.network
@pytest.mark.skipif(
sys.version_info < (3, 12), reason="PEP-695 support requires Python >=3.12"
)
class TestPEP695:
@pytest.fixture(autouse=True, scope="class")
def built(self, builder):
builder("pep695", warningiserror=True)
def test_integration(self, parse):
example_file = parse("_build/html/autoapi/example/index.html")
alias = example_file.find(id="example.MyTypeAliasA")
properties = alias.find_all(class_="property")
assert len(properties) == 2
annotation = properties[0].text
assert annotation == ": TypeAlias"
value = properties[1].text
assert value == " = tuple[str, int]"
alias = example_file.find(id="example.MyTypeAliasB")
properties = alias.find_all(class_="property")
assert len(properties) == 2
annotation = properties[0].text
assert annotation == ": TypeAlias"
value = properties[1].text
assert value == " = tuple[str, int]"
def test_napoleon_integration_loaded(builder, parse):
confoverrides = {
"exclude_patterns": ["manualapi.rst"],
"extensions": [
"autoapi.extension",
"sphinx.ext.autodoc",
"sphinx.ext.napoleon",
],
}
builder("pyexample", warningiserror=True, confoverrides=confoverrides)
example_file = parse("_build/html/autoapi/example/index.html")
method_google = example_file.find(id="example.Foo.method_google_docs")
params, returns, return_type = method_google.parent.select(".field-list > dt")
assert params.text == "Parameters:"
assert returns.text == "Returns:"
assert return_type.text == "Return type:"
class TestSimplePackage:
@pytest.fixture(autouse=True, scope="class")
def built(self, builder):
builder("pypackageexample", warningiserror=True)
def test_integration_with_package(self, parse):
example_file = parse("_build/html/autoapi/package/index.html")
entries = example_file.find_all(class_="toctree-l1")
assert any(entry.text == "package.submodule" for entry in entries)
assert example_file.find(id="package.function")
example_foo_file = parse("_build/html/autoapi/package/submodule/index.html")
submodule = example_foo_file.find(id="package.submodule.Class")
assert submodule
method_okay = submodule.parent.find(id="package.submodule.Class.method_okay")
assert method_okay
index_file = parse("_build/html/index.html")
toctree = index_file.select("li > a")
assert any(item.text == "API Reference" for item in toctree)
assert any(item.text == "package.submodule" for item in toctree)
assert any(item.text == "Class" for item in toctree)
assert any(item.text == "function()" for item in toctree)
def test_simple_no_false_warnings(builder, caplog):
logger = sphinx.util.logging.getLogger("autoapi")
logger.logger.addHandler(caplog.handler)
builder("pypackageexample", warningiserror=True)
assert "Cannot resolve" not in caplog.text
def _test_class_content(builder, parse, class_content):
confoverrides = {
"autoapi_python_class_content": class_content,
"exclude_patterns": ["manualapi.rst"],
}
builder("pyexample", warningiserror=True, confoverrides=confoverrides)
example_file = parse("_build/html/autoapi/example/index.html")
foo = example_file.find(id="example.Foo").parent.find("dd")
if class_content == "init":
assert "Can we parse arguments" not in foo.text
else:
assert "Can we parse arguments" in foo.text
if class_content not in ("both", "init"):
assert "Constructor docstring" not in foo.text
else:
assert "Constructor docstring" in foo.text
def test_class_class_content(builder, parse):
_test_class_content(builder, parse, "class")
def test_both_class_content(builder, parse):
_test_class_content(builder, parse, "both")
def test_init_class_content(builder, parse):
_test_class_content(builder, parse, "init")
def test_hiding_private_members(builder, parse):
confoverrides = {"autoapi_options": ["members", "undoc-members", "special-members"]}
builder("pypackageexample", warningiserror=True, confoverrides=confoverrides)
example_file = parse("_build/html/autoapi/package/index.html")
entries = example_file.find_all(class_="toctree-l1")
assert all("private" not in entry.text for entry in entries)
assert not pathlib.Path(
"_build/html/autoapi/package/_private_module/index.html"
).exists()
def test_hiding_inheritance(builder, parse):
confoverrides = {
"autoapi_options": ["members", "undoc-members", "special-members"],
"exclude_patterns": ["manualapi.rst"],
}
builder("pyexample", warningiserror=True, confoverrides=confoverrides)
example_file = parse("_build/html/autoapi/example/index.html")
assert "Bases:" not in example_file.find(id="example.Foo").parent.find("dd").text
def test_hiding_imported_members(builder, parse):
confoverrides = {"autoapi_options": ["members", "undoc-members"]}
builder("pypackagecomplex", confoverrides=confoverrides)
subpackage_file = parse("_build/html/autoapi/complex/subpackage/index.html")
assert not subpackage_file.find(id="complex.subpackage.public_chain")
package_file = parse("_build/html/autoapi/complex/index.html")
assert not package_file.find(id="complex.public_chain")
submodule_file = parse("_build/html/autoapi/complex/subpackage/index.html")
assert not submodule_file.find(id="complex.subpackage.now_public_function")
def test_imports_into_modules_always_hidden(builder, parse):
confoverrides = {
"autoapi_options": ["members", "undoc-members", "imported-members"]
}
builder("pypackagecomplex", confoverrides=confoverrides)
submodule_file = parse("_build/html/autoapi/complex/submodule/index.html")
assert not submodule_file.find(id="complex.submodule.imported_function")
def test_inherited_members(builder, parse):
confoverrides = {
"autoapi_options": ["members", "inherited-members", "undoc-members"],
"exclude_patterns": ["manualapi.rst"],
}
builder("pyexample", warningiserror=True, confoverrides=confoverrides)
example_file = parse("_build/html/autoapi/example/index.html")
bar = example_file.find(id="example.Bar")
assert bar
assert bar.parent.find(id="example.Bar.method_okay")
def test_skipping_members(builder, parse):
builder("pyskipexample", warningiserror=True)
example_file = parse("_build/html/autoapi/example/index.html")
assert not example_file.find(id="example.foo")
assert not example_file.find(id="example.Bar")
assert not example_file.find(id="example.Bar.m")
assert example_file.find(id="example.Baf")
assert not example_file.find(id="example.Baf.m")
assert not example_file.find(id="example.baz")
assert example_file.find(id="example.anchor")
@pytest.mark.parametrize(
"value,order",
[
("bysource", ["Foo", "decorator_okay", "Bar"]),
("alphabetical", ["Bar", "Foo", "decorator_okay"]),
("groupwise", ["Bar", "Foo", "decorator_okay"]),
],
)
def test_order_members(builder, parse, value, order):
confoverrides = {
"autoapi_member_order": value,
"exclude_patterns": ["manualapi.rst"],
}
builder("pyexample", warningiserror=True, confoverrides=confoverrides)
example_file = parse("_build/html/autoapi/example/index.html")
indexes = [example_file.find(id=f"example.{name}").sourceline for name in order]
assert indexes == sorted(indexes)
class _CompareInstanceType:
def __init__(self, type_):
self.type = type_
def __eq__(self, other):
return self.type is type(other)
def __repr__(self):
return f""
def test_skip_members_hook(builder):
os.chdir("tests/python/pyskipexample")
emit_firstresult_patch = None
class MockSphinx(Sphinx):
def __init__(self, *args, **kwargs):
nonlocal emit_firstresult_patch
emit_firstresult_patch = Mock(wraps=self.emit_firstresult)
self.emit_firstresult = emit_firstresult_patch
super().__init__(*args, **kwargs)
app = MockSphinx(
srcdir=".",
confdir=".",
outdir="_build/html",
doctreedir="_build/.doctrees",
buildername="html",
warningiserror=True,
confoverrides={
"suppress_warnings": [
"app.add_node",
"app.add_directive",
"app.add_role",
]
},
)
app.build()
options = ["members", "undoc-members", "special-members"]
mock_calls = [
call(
"autoapi-skip-member",
"module",
"example",
_CompareInstanceType(PythonModule),
False,
options,
),
call(
"autoapi-skip-member",
"function",
"example.foo",
_CompareInstanceType(PythonFunction),
False,
options,
),
call(
"autoapi-skip-member",
"class",
"example.Bar",
_CompareInstanceType(PythonClass),
False,
options,
),
call(
"autoapi-skip-member",
"class",
"example.Baf",
_CompareInstanceType(PythonClass),
False,
options,
),
call(
"autoapi-skip-member",
"data",
"example.baz",
_CompareInstanceType(PythonData),
False,
options,
),
call(
"autoapi-skip-member",
"data",
"example.anchor",
_CompareInstanceType(PythonData),
False,
options,
),
call(
"autoapi-skip-member",
"method",
"example.Baf.m",
_CompareInstanceType(PythonMethod),
False,
options,
),
]
for mock_call in mock_calls:
assert mock_call in emit_firstresult_patch.mock_calls
class TestComplexPackage:
@pytest.fixture(autouse=True, scope="class")
def built(self, builder):
# We don't set warningiserror=True because we test that invalid imports
# do not fail the build
builder("pypackagecomplex")
def test_public_chain_resolves(self, parse):
submodule_file = parse(
"_build/html/autoapi/complex/subpackage/submodule/index.html"
)
assert submodule_file.find(id="complex.subpackage.submodule.public_chain")
subpackage_file = parse("_build/html/autoapi/complex/subpackage/index.html")
assert subpackage_file.find(id="complex.subpackage.public_chain")
package_file = parse("_build/html/autoapi/complex/index.html")
assert package_file.find(id="complex.public_chain")
def test_private_made_public(self, parse):
submodule_file = parse("_build/html/autoapi/complex/subpackage/index.html")
assert submodule_file.find(id="complex.subpackage.now_public_function")
def test_multiple_import_locations(self, parse):
submodule_file = parse(
"_build/html/autoapi/complex/subpackage/submodule/index.html"
)
assert submodule_file.find(
id="complex.subpackage.submodule.public_multiple_imports"
)
subpackage_file = parse("_build/html/autoapi/complex/subpackage/index.html")
assert subpackage_file.find(id="complex.subpackage.public_multiple_imports")
package_file = parse("_build/html/autoapi/complex/index.html")
assert package_file.find(id="complex.public_multiple_imports")
def test_simple_wildcard_imports(self, parse):
wildcard_file = parse("_build/html/autoapi/complex/wildcard/index.html")
assert wildcard_file.find(id="complex.wildcard.public_chain")
assert wildcard_file.find(id="complex.wildcard.now_public_function")
assert wildcard_file.find(id="complex.wildcard.public_multiple_imports")
assert wildcard_file.find(id="complex.wildcard.module_level_function")
def test_wildcard_all_imports(self, parse):
wildcard_file = parse("_build/html/autoapi/complex/wildall/index.html")
assert not wildcard_file.find(id="complex.wildall.not_all")
assert not wildcard_file.find(id="complex.wildall.NotAllClass")
assert not wildcard_file.find(id="complex.wildall.does_not_exist")
assert wildcard_file.find(id="complex.wildall.SimpleClass")
assert wildcard_file.find(id="complex.wildall.simple_function")
assert wildcard_file.find(id="complex.wildall.public_chain")
assert wildcard_file.find(id="complex.wildall.module_level_function")
def test_no_imports_in_module_with_all(self, parse):
foo_file = parse("_build/html/autoapi/complex/foo/index.html")
assert not foo_file.find(id="complex.foo.module_level_function")
def test_all_overrides_import_in_module_with_all(self, parse):
foo_file = parse("_build/html/autoapi/complex/foo/index.html")
assert foo_file.find(id="complex.foo.PublicClass")
def test_parses_unicode_file(self, parse):
foo_file = parse("_build/html/autoapi/complex/unicode_data/index.html")
assert foo_file.find(id="complex.unicode_data.unicode_str")
def test_nested_parse_directive(self, parse):
package_file = parse("_build/html/autoapi/complex/index.html")
complex = package_file.find(id="complex")
assert "This heading will be removed" not in complex.parent.text
assert complex.parent.find("section")["id"] != "this-heading-will-be-removed"
class TestComplexPackageParallel(TestComplexPackage):
@pytest.fixture(autouse=True, scope="class")
def built(self, builder):
builder("pypackagecomplex", parallel=2)
def test_caching(builder, rebuild):
mtimes = (0, 0)
def record_mtime():
nonlocal mtimes
mtime = 0
for root, _, files in os.walk("_build/html/autoapi"):
for name in files:
this_mtime = os.path.getmtime(os.path.join(root, name))
mtime = max(mtime, this_mtime)
mtimes = (*mtimes[1:], mtime)
builder("pypackagecomplex", confoverrides={"autoapi_keep_files": True})
record_mtime()
rebuild(confoverrides={"autoapi_keep_files": True})
record_mtime()
assert mtimes[1] == mtimes[0]
# Check that adding a file rebuilds the docs
extra_file = "complex/new.py"
with open(extra_file, "w") as out_f:
out_f.write("\n")
try:
rebuild(confoverrides={"autoapi_keep_files": True})
finally:
os.remove(extra_file)
record_mtime()
assert mtimes[1] != mtimes[0]
# Removing a file also rebuilds the docs
rebuild(confoverrides={"autoapi_keep_files": True})
record_mtime()
assert mtimes[1] != mtimes[0]
# Changing not keeping files always builds
rebuild()
record_mtime()
assert mtimes[1] != mtimes[0]
class TestImplicitNamespacePackage:
@pytest.fixture(autouse=True, scope="class")
def built(self, builder):
# TODO: Cannot set warningiserror=True because namespaces are not added
# to the toctree automatically.
builder("py3implicitnamespace")
def test_sibling_import_from_namespace(self, parse):
example_file = parse("_build/html/autoapi/namespace/example/index.html")
assert example_file.find(id="namespace.example.first_method")
def test_sub_sibling_import_from_namespace(self, parse):
example_file = parse("_build/html/autoapi/namespace/example/index.html")
assert example_file.find(id="namespace.example.second_sub_method")
def test_custom_jinja_filters(builder, parse, tmp_path):
py_templates = tmp_path / "python"
py_templates.mkdir()
orig_py_templates = pathlib.Path(autoapi.settings.TEMPLATE_DIR) / "python"
orig_template = (orig_py_templates / "class.rst").read_text()
(py_templates / "class.rst").write_text(
orig_template.replace("obj.docstring", "obj.docstring|prepare_docstring")
)
confoverrides = {
"autoapi_prepare_jinja_env": (
lambda jinja_env: jinja_env.filters.update(
{
"prepare_docstring": (
lambda docstring: "This is using custom filters.\n"
)
}
)
),
"autoapi_template_dir": str(tmp_path),
"exclude_patterns": ["manualapi.rst"],
}
builder("pyexample", warningiserror=True, confoverrides=confoverrides)
example_file = parse("_build/html/autoapi/example/index.html")
foo = example_file.find(id="example.Foo").parent.find("dd")
assert "This is using custom filters." in foo.text
def test_string_module_attributes(builder):
"""Test toggle for multi-line string attribute values (GitHub #267)."""
keep_rst = {
"autoapi_keep_files": True,
}
builder("py3example", confoverrides=keep_rst)
example_path = os.path.join("autoapi", "example", "index.rst")
with open(example_path, encoding="utf8") as example_handle:
example_file = example_handle.read()
code_snippet_contents = [
".. py:data:: code_snippet",
" :value: Multiline-String",
"",
" .. raw:: html",
"",
" Show Value
",
"",
" .. code-block:: python",
"",
' """The following is some code:',
" ", # <--- Line array monstrosity to preserve these leading spaces
" # -*- coding: utf-8 -*-",
" from __future__ import absolute_import, division, print_function, unicode_literals",
" # from future.builtins.disabled import *",
" # from builtins import *",
" ",
""" print("chunky o'block")""",
' """',
"",
" .. raw:: html",
"",
" ",
]
assert "\n".join(code_snippet_contents) in example_file
class TestAutodocTypehintsPackage:
"""Test integrations with the autodoc.typehints extension."""
@pytest.fixture(autouse=True, scope="class")
def built(self, builder):
builder("pyautodoc_typehints", warningiserror=True)
def test_renders_typehint(self, parse):
example_file = parse("_build/html/autoapi/example/index.html")
test = example_file.find(id="example.A.test")
args = test.parent.select(".field-list > dd")
assert args[0].text.startswith("a (int)")
def test_renders_typehint_in_second_module(self, parse):
example2_file = parse("_build/html/autoapi/example2/index.html")
test = example2_file.find(id="example2.B.test")
args = test.parent.select(".field-list > dd")
assert args[0].text.startswith("a (int)")
def test_no_files_found(builder):
"""Test that building does not fail when no sources files are found."""
with pytest.raises(ExtensionError) as exc_info:
builder("pyemptyexample")
assert os.path.dirname(__file__) in str(exc_info.value)
class TestMdSource:
@pytest.fixture(autouse=True, scope="class")
def built(self, builder):
builder(
"pyexample",
warningiserror=True,
confoverrides={"source_suffix": ["md"]},
)
class TestMemberOrder:
@pytest.fixture(autouse=True, scope="class")
def built(self, builder):
builder(
"pyexample",
warningiserror=True,
confoverrides={
"autodoc_member_order": "bysource",
"autoapi_generate_api_docs": False,
"autoapi_add_toctree_entry": False,
},
)
def test_line_number_order(self, parse):
example_file = parse("_build/html/manualapi.html")
method_tricky = example_file.find(id="example.Foo.method_tricky")
method_sphinx_docs = example_file.find(id="example.Foo.method_sphinx_docs")
assert method_tricky.sourceline < method_sphinx_docs.sourceline
def test_nothing_to_render_raises_warning(builder, caplog):
caplog.set_level(logging.WARNING, logger="autoapi._mapper")
if sphinx_version >= (8, 1):
status = builder("pynorender", warningiserror=True)
assert status
else:
with pytest.raises(sphinx.errors.SphinxWarning):
builder("pynorender", warningiserror=True)
assert any(
"No modules were rendered" in record.message for record in caplog.records
)
class TestStdLib:
"""Check that modules with standard library names are still documented."""
@pytest.fixture(autouse=True)
def built(self, builder):
builder("pystdlib")
def test_integration(self, parse):
json_file = parse("_build/html/autoapi/json/index.html")
json_mod = json_file.find(id="json")
assert "json is the same name" in json_mod.parent.text
assert json_file.find(id="json.JSONDecoder")
decode = json_file.find(id="json.JSONDecoder.decode")
assert decode
wrap_docstring = decode.parent.find("dd").text.strip()
assert wrap_docstring == "Decode a string."
myjson_file = parse("_build/html/autoapi/myjson/index.html")
# Find members that are not inherited from local standard library classes.
ctx = myjson_file.find(id="myjson.MyJSONDecoder")
assert ctx
meth = myjson_file.find(id="myjson.MyJSONDecoder.my_method")
assert meth
meth_docstring = meth.parent.find("dd").text.strip()
assert meth_docstring == "This is a method."
# Find members that are inherited from local standard library classes.
decode = myjson_file.find(id="myjson.MyJSONDecoder.decode")
assert decode
myast_file = parse("_build/html/autoapi/myast/index.html")
# Find members that are not inherited from standard library classes.
visitor = myast_file.find(id="myast.MyVisitor")
assert visitor
meth = myast_file.find(id="myast.MyVisitor.my_visit")
assert meth
meth_docstring = meth.parent.find("dd").text.strip()
assert meth_docstring == "My visit method."
# Find members that are inherited from standard library classes.
meth = myast_file.find(id="myast.MyVisitor.visit")
assert not meth
sphinx-autoapi-3.3.3/tests/templateexample/ 0000775 0000000 0000000 00000000000 14707035566 0021037 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/templateexample/conf.py 0000664 0000000 0000000 00000001053 14707035566 0022335 0 ustar 00root root 0000000 0000000 templates_path = ["_templates"]
source_suffix = ".rst"
master_doc = "index"
project = "pyexample"
copyright = "2015, readthedocs"
author = "readthedocs"
version = "0.1"
release = "0.1"
language = "en"
exclude_patterns = ["_build"]
pygments_style = "sphinx"
todo_include_todos = False
html_theme = "alabaster"
html_static_path = ["_static"]
htmlhelp_basename = "pyexampledoc"
extensions = ["autoapi.extension"]
autoapi_dirs = ["example"]
autoapi_file_pattern = "*.py"
autoapi_template_dir = "template_overrides"
exclude_patterns += [autoapi_template_dir]
sphinx-autoapi-3.3.3/tests/templateexample/example/ 0000775 0000000 0000000 00000000000 14707035566 0022472 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/templateexample/example/example.py 0000664 0000000 0000000 00000000215 14707035566 0024475 0 ustar 00root root 0000000 0000000 __author__ = "swenson"
import math
def example_function(x):
"""Compute the square root of x and return it."""
return math.sqrt(x)
sphinx-autoapi-3.3.3/tests/templateexample/index.rst 0000664 0000000 0000000 00000000720 14707035566 0022677 0 ustar 00root root 0000000 0000000 .. pyexample documentation master file, created by
sphinx-quickstart on Fri May 29 13:34:37 2015.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to pyexample's documentation!
=====================================
.. toctree::
autoapi/index
Contents:
.. toctree::
:maxdepth: 2
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
sphinx-autoapi-3.3.3/tests/templateexample/template_overrides/ 0000775 0000000 0000000 00000000000 14707035566 0024734 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/templateexample/template_overrides/python/ 0000775 0000000 0000000 00000000000 14707035566 0026255 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/templateexample/template_overrides/python/function.rst 0000664 0000000 0000000 00000000045 14707035566 0030633 0 ustar 00root root 0000000 0000000 This is a function template override! sphinx-autoapi-3.3.3/tests/test_astroid_utils.py 0000664 0000000 0000000 00000017167 14707035566 0022162 0 ustar 00root root 0000000 0000000 import sys
import astroid
from autoapi import _astroid_utils
from autoapi import _objects
import pytest
def generate_module_names():
for i in range(1, 5):
yield ".".join(f"module{j}" for j in range(i))
yield "package.repeat.repeat"
def imported_basename_cases():
for module_name in generate_module_names():
import_ = f"import {module_name}"
basename = f"{module_name}.ImportedClass"
expected = basename
yield (import_, basename, expected)
import_ = f"import {module_name} as aliased"
basename = "aliased.ImportedClass"
yield (import_, basename, expected)
if "." in module_name:
from_name, attribute = module_name.rsplit(".", 1)
import_ = f"from {from_name} import {attribute}"
basename = f"{attribute}.ImportedClass"
yield (import_, basename, expected)
import_ += " as aliased"
basename = "aliased.ImportedClass"
yield (import_, basename, expected)
import_ = f"from {module_name} import ImportedClass"
basename = "ImportedClass"
yield (import_, basename, expected)
import_ = f"from {module_name} import ImportedClass as AliasedClass"
basename = "AliasedClass"
yield (import_, basename, expected)
def generate_args():
for i in range(5):
yield ", ".join(f"arg{j}" for j in range(i))
def imported_call_cases():
for args in generate_args():
for import_, basename, expected in imported_basename_cases():
basename += f"({args})"
expected += "()"
yield import_, basename, expected
class TestAstroidUtils:
@pytest.mark.parametrize(
("import_", "basename", "expected"), list(imported_basename_cases())
)
def test_can_get_full_imported_basename(self, import_, basename, expected):
source = """
{}
class ThisClass({}): #@
pass
""".format(
import_, basename
)
node = astroid.extract_node(source)
basenames = _astroid_utils.resolve_qualname(node.bases[0], node.basenames[0])
assert basenames == expected
@pytest.mark.parametrize(
("import_", "basename", "expected"), list(imported_call_cases())
)
def test_can_get_full_function_basename(self, import_, basename, expected):
source = """
{}
class ThisClass({}): #@
pass
""".format(
import_, basename
)
node = astroid.extract_node(source)
basenames = _astroid_utils.resolve_qualname(node.bases[0], node.basenames[0])
assert basenames == expected
@pytest.mark.parametrize(
("source", "expected"),
[
('a = "a"', ("a", "'a'")),
("a = 1", ("a", "1")),
("a, b, c = (1, 2, 3)", None),
("a = b = 1", None),
("a = [1, 2, [3, 4]]", ("a", "[1, 2, [3, 4]]")),
("a = [1, 2, variable[subscript]]", ("a", None)),
('a = """multiline\nstring"""', ("a", '"""multiline\nstring"""')),
('a = ["""multiline\nstring"""]', ("a", None)),
("a = (1, 2, 3)", ("a", "(1, 2, 3)")),
("a = (1, 'two', 3)", ("a", "(1, 'two', 3)")),
("a = None", ("a", "None")),
],
)
def test_can_get_assign_values(self, source, expected):
node = astroid.extract_node(source)
value = _astroid_utils.get_assign_value(node)
assert value == expected
@pytest.mark.parametrize(
"signature,expected",
[
(
"a: bool, b: int = 5",
[(None, "a", "bool", None), (None, "b", "int", "5")],
),
pytest.param(
"a: bool, /, b: int, *, c: str",
[
(None, "a", "bool", None),
("/", None, None, None),
(None, "b", "int", None),
("*", None, None, None),
(None, "c", "str", None),
],
marks=pytest.mark.skipif(
sys.version_info[:2] < (3, 8), reason="Uses Python 3.8+ syntax"
),
),
pytest.param(
"a: bool, /, b: int, *args, c: str, **kwargs",
[
(None, "a", "bool", None),
("/", None, None, None),
(None, "b", "int", None),
("*", "args", None, None),
(None, "c", "str", None),
("**", "kwargs", None, None),
],
marks=pytest.mark.skipif(
sys.version_info[:2] < (3, 8), reason="Uses Python 3.8+ syntax"
),
),
pytest.param(
"a: int, *args, b: str, **kwargs",
[
(None, "a", "int", None),
("*", "args", None, None),
(None, "b", "str", None),
("**", "kwargs", None, None),
],
marks=pytest.mark.skipif(
sys.version_info[:2] < (3, 8), reason="Uses Python 3.8+ syntax"
),
),
],
)
def test_parse_annotations(self, signature, expected):
node = astroid.extract_node(
"""
def func({}) -> str: #@
pass
""".format(
signature
)
)
annotations = _astroid_utils.get_args_info(node.args)
assert annotations == expected
def test_parse_split_type_comments(self):
node = astroid.extract_node(
"""
def func(
a, # type: int
b, # type: int
): # type: (...) -> str
pass
"""
)
annotations = _astroid_utils.get_args_info(node.args)
expected = [
(None, "a", "int", None),
(None, "b", "int", None),
]
assert annotations == expected
@pytest.mark.parametrize(
"signature,expected",
[
("a: bool, b: int = 5, c='hi'", "a: bool, b: int = 5, c='hi'"),
pytest.param(
"a: bool, /, b: int, *, c: str",
"a: bool, /, b: int, *, c: str",
marks=pytest.mark.skipif(
sys.version_info[:2] < (3, 8), reason="Uses Python 3.8+ syntax"
),
),
pytest.param(
"a: bool, /, b: int, *args, c: str, **kwargs",
"a: bool, /, b: int, *args, c: str, **kwargs",
marks=pytest.mark.skipif(
sys.version_info[:2] < (3, 8), reason="Uses Python 3.8+ syntax"
),
),
pytest.param(
"*, a: int, b: int",
"*, a: int, b: int",
marks=pytest.mark.skipif(
sys.version_info[:2] < (3, 8), reason="Uses Python 3.8+ syntax"
),
),
("a: int, *args, b: str, **kwargs", "a: int, *args, b: str, **kwargs"),
("a: 'A'", "a: A"),
("a: Literal[1]", "a: Literal[1]"),
("a: Literal['x']", "a: Literal['x']"),
("a: Literal['x', 'y', 'z']", "a: Literal['x', 'y', 'z']"),
],
)
def test_format_args(self, signature, expected):
node = astroid.extract_node(
"""
def func({}) -> str: #@
pass
""".format(
signature
)
)
args_info = _astroid_utils.get_args_info(node.args)
formatted = _objects._format_args(args_info)
assert formatted == expected
sphinx-autoapi-3.3.3/tests/test_integration.py 0000664 0000000 0000000 00000003032 14707035566 0021602 0 ustar 00root root 0000000 0000000 import io
import os
import shutil
from contextlib import contextmanager
from sphinx.application import Sphinx
@contextmanager
def sphinx_build(test_dir, confoverrides=None):
os.chdir(f"tests/{test_dir}")
try:
app = Sphinx(
srcdir=".",
confdir=".",
outdir="_build/text",
doctreedir="_build/.doctrees",
buildername="text",
confoverrides=confoverrides,
)
app.build(force_all=True)
yield
finally:
if os.path.exists("_build"):
shutil.rmtree("_build")
os.chdir("../..")
class LanguageIntegrationTests:
def _run_test(self, test_dir, test_file, test_string):
with sphinx_build(test_dir):
with open(test_file, encoding="utf8") as fin:
text = fin.read().strip()
assert test_string in text
class TestIntegration(LanguageIntegrationTests):
def test_template_overrides(self):
self._run_test(
"templateexample",
"_build/text/autoapi/example/index.txt",
"This is a function template override",
)
class TestTOCTree(LanguageIntegrationTests):
def test_toctree_overrides(self):
self._run_test("toctreeexample", "_build/text/index.txt", "API Reference")
def test_toctree_domain_insertion(self):
"""
Test that the example_function gets added to the TOC Tree
"""
self._run_test(
"toctreeexample", "_build/text/index.txt", '* "example_function()"'
)
sphinx-autoapi-3.3.3/tests/toctreeexample/ 0000775 0000000 0000000 00000000000 14707035566 0020671 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/toctreeexample/conf.py 0000664 0000000 0000000 00000000723 14707035566 0022172 0 ustar 00root root 0000000 0000000 templates_path = ["_templates"]
source_suffix = ".rst"
master_doc = "index"
project = "pyexample"
copyright = "2015, readthedocs"
author = "readthedocs"
version = "0.1"
release = "0.1"
language = "en"
exclude_patterns = ["_build"]
pygments_style = "sphinx"
todo_include_todos = False
html_theme = "alabaster"
html_static_path = ["_static"]
htmlhelp_basename = "pyexampledoc"
extensions = ["autoapi.extension"]
autoapi_dirs = ["example"]
autoapi_file_pattern = "*.py"
sphinx-autoapi-3.3.3/tests/toctreeexample/example/ 0000775 0000000 0000000 00000000000 14707035566 0022324 5 ustar 00root root 0000000 0000000 sphinx-autoapi-3.3.3/tests/toctreeexample/example/example.py 0000664 0000000 0000000 00000000215 14707035566 0024327 0 ustar 00root root 0000000 0000000 __author__ = "swenson"
import math
def example_function(x):
"""Compute the square root of x and return it."""
return math.sqrt(x)
sphinx-autoapi-3.3.3/tests/toctreeexample/index.rst 0000664 0000000 0000000 00000000140 14707035566 0022525 0 ustar 00root root 0000000 0000000 Welcome to pyexample's documentation!
=====================================
.. toctree::
sphinx-autoapi-3.3.3/tox.ini 0000664 0000000 0000000 00000001761 14707035566 0016026 0 ustar 00root root 0000000 0000000 [tox]
isolated_build = true
envlist =
# Keep this in sync with .github/workflows/main.yml
py{38,39,310,311,312,313}
format
typecheck
lint
doc
release_notes
[gh-actions]
python =
3.8: py38
3.9: py39
3.10: py310
3.11: py311
3.12: py312, format, typecheck, lint, doc, release_notes
3.13: py313
[testenv]
usedevelop = True
deps =
beautifulsoup4
pytest
commands =
pytest {posargs}
[testenv:format]
skip_install = true
deps =
black
commands =
black --check --diff autoapi tests
[testenv:lint]
skip_install = true
deps =
ruff
commands =
ruff check {posargs:autoapi}
[testenv:typecheck]
deps =
mypy
types-docutils
types-PyYAML
commands =
mypy {posargs:autoapi}
[testenv:doc]
deps =
furo
sphinx
sphinx_design
changedir = {toxinidir}/docs
commands =
sphinx-build -b html -d {envtmpdir}/doctrees . {envtmpdir}/html
[testenv:release_notes]
deps =
towncrier
commands =
towncrier {posargs:check}