├── .gitattributes ├── .github ├── dependabot.yml └── workflows │ └── main.yml ├── .gitignore ├── .pre-commit-config.yaml ├── .readthedocs.yml ├── LICENSE ├── README.md ├── docs ├── apidocs │ ├── aiida │ │ ├── aiida.cmdline.rst │ │ ├── aiida.common.rst │ │ ├── aiida.engine.rst │ │ ├── aiida.manage.rst │ │ ├── aiida.orm.rst │ │ ├── aiida.parsers.rst │ │ ├── aiida.plugins.rst │ │ ├── aiida.repository.rst │ │ ├── aiida.rst │ │ ├── aiida.schedulers.rst │ │ ├── aiida.tools.rst │ │ └── aiida.transports.rst │ ├── autodoc2 │ │ ├── autodoc2.analysis.rst │ │ ├── autodoc2.astroid_utils.rst │ │ ├── autodoc2.cli.rst │ │ ├── autodoc2.config.rst │ │ ├── autodoc2.db.md │ │ ├── autodoc2.render.base.rst │ │ ├── autodoc2.render.myst_.rst │ │ ├── autodoc2.render.rst │ │ ├── autodoc2.render.rst_.rst │ │ ├── autodoc2.resolve_all.rst │ │ ├── autodoc2.rst │ │ ├── autodoc2.sphinx.autodoc.rst │ │ ├── autodoc2.sphinx.docstring.rst │ │ ├── autodoc2.sphinx.extension.rst │ │ ├── autodoc2.sphinx.rst │ │ ├── autodoc2.sphinx.summary.rst │ │ ├── autodoc2.sphinx.utils.rst │ │ └── autodoc2.utils.rst │ └── index.rst ├── autodoc.md ├── autodoc_diff.md ├── conf.py ├── config.md ├── docstrings.md ├── index.md ├── quickstart.md └── summary.md ├── pyproject.toml ├── src └── autodoc2 │ ├── __init__.py │ ├── analysis.py │ ├── astroid_utils.py │ ├── cli.py │ ├── config.py │ ├── db.py │ ├── py.typed │ ├── render │ ├── __init__.py │ ├── base.py │ ├── myst_.py │ └── rst_.py │ ├── resolve_all.py │ ├── sphinx │ ├── __init__.py │ ├── autodoc.py │ ├── docstring.py │ ├── extension.py │ ├── summary.py │ └── utils.py │ └── utils.py └── tests ├── test_analyse_module.py ├── test_analyse_module ├── test_basic_assign_annotation_.yml ├── test_basic_assign_annotation_union_.yml ├── test_basic_assign_bytes_.yml ├── test_basic_assign_class_.yml ├── test_basic_assign_dict_.yml ├── test_basic_assign_float_.yml ├── test_basic_assign_int_.yml ├── test_basic_assign_list_.yml ├── test_basic_assign_set_.yml ├── test_basic_assign_string_.yml ├── test_basic_assign_tuple_.yml ├── test_basic_assign_with_docstring_.yml ├── test_basic_class_abstractmethod_basic_.yml ├── test_basic_class_attribute_.yml ├── test_basic_class_attribute_with_docstring_.yml ├── test_basic_class_basic_.yml ├── test_basic_class_classmethod_basic_.yml ├── test_basic_class_docstring_.yml ├── test_basic_class_inherit_.yml ├── test_basic_class_inherit_generic_.yml ├── test_basic_class_inherit_multi_.yml ├── test_basic_class_inherited_.yml ├── test_basic_class_inherited_with_docstring_.yml ├── test_basic_class_method_basic_.yml ├── test_basic_class_property_basic_.yml ├── test_basic_class_staticmethod_basic_.yml ├── test_basic_func_1arg_.yml ├── test_basic_func_1kwarg_.yml ├── test_basic_func_args_.yml ├── test_basic_func_async_.yml ├── test_basic_func_basic_.yml ├── test_basic_func_docstring_.yml ├── test_basic_func_kwargs_.yml ├── test_basic_module_all_.yml ├── test_basic_module_docstring_.yml ├── test_basic_overload_basic_.yml └── test_package.yml ├── test_database.py ├── test_database └── test_all_resolution.yml ├── test_render.py └── test_render ├── test_basic_myst_.md ├── test_basic_rst_.rst ├── test_config_options_myst_.md ├── test_config_options_rst_.rst └── test_sphinx_build_directives.xml /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: github-actions 9 | directory: / 10 | commit-message: 11 | prefix: ⬆️ 12 | schedule: 13 | interval: monthly 14 | - package-ecosystem: pip 15 | directory: / 16 | commit-message: 17 | prefix: ⬆️ 18 | schedule: 19 | interval: monthly 20 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: tests 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | tags: 7 | - "v[0-9]+.[0-9]+.[0-9]+*" 8 | pull_request: 9 | 10 | jobs: 11 | 12 | pre-commit: 13 | 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v4 18 | - name: Set up Python 3.9 19 | uses: actions/setup-python@v5 20 | with: 21 | python-version: "3.9" 22 | - uses: pre-commit/action@v3.0.1 23 | 24 | tests: 25 | 26 | name: Pytest (${{ matrix.platform }}, Python ${{ matrix.python-version }}) 27 | 28 | strategy: 29 | fail-fast: false 30 | matrix: 31 | python-version: ["3.8", "3.9", "3.10", "3.11"] 32 | platform: [ubuntu-latest] 33 | include: 34 | - python-version: "3.8" 35 | platform: "windows-latest" 36 | 37 | runs-on: ${{ matrix.platform }} 38 | 39 | steps: 40 | - uses: actions/checkout@v4 41 | - name: Set up Python ${{ matrix.python-version }} 42 | uses: actions/setup-python@v5 43 | with: 44 | python-version: ${{ matrix.python-version }} 45 | - name: Install dependencies 46 | run: | 47 | python -m pip install --upgrade pip 48 | pip install -e .[testing] 49 | - name: Run tests 50 | run: pytest 51 | 52 | # https://github.com/marketplace/actions/alls-green#why 53 | check: # This job does nothing and is only used for the branch protection 54 | 55 | if: always() 56 | 57 | needs: 58 | - pre-commit 59 | - tests 60 | 61 | runs-on: ubuntu-latest 62 | 63 | steps: 64 | - name: Decide whether the needed jobs succeeded or failed 65 | uses: re-actors/alls-green@release/v1 66 | with: 67 | jobs: ${{ toJSON(needs) }} 68 | 69 | publish: 70 | 71 | name: Publish to PyPI 72 | needs: 73 | - check 74 | if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags') 75 | runs-on: ubuntu-latest 76 | steps: 77 | - name: Checkout source 78 | uses: actions/checkout@v4 79 | - name: Set up Python 3.8 80 | uses: actions/setup-python@v5 81 | with: 82 | python-version: "3.8" 83 | - name: install flit 84 | run: | 85 | pip install flit~=3.4 86 | - name: Build and publish 87 | run: | 88 | flit publish 89 | env: 90 | FLIT_USERNAME: __token__ 91 | FLIT_PASSWORD: ${{ secrets.PYPI_TOKEN }} 92 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # poetry 98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 102 | #poetry.lock 103 | 104 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 105 | __pypackages__/ 106 | 107 | # Celery stuff 108 | celerybeat-schedule 109 | celerybeat.pid 110 | 111 | # SageMath parsed files 112 | *.sage.py 113 | 114 | # Environments 115 | .env 116 | .venv 117 | env/ 118 | venv/ 119 | ENV/ 120 | env.bak/ 121 | venv.bak/ 122 | 123 | # Spyder project settings 124 | .spyderproject 125 | .spyproject 126 | 127 | # Rope project settings 128 | .ropeproject 129 | 130 | # mkdocs documentation 131 | /site 132 | 133 | # mypy 134 | .mypy_cache/ 135 | .dmypy.json 136 | dmypy.json 137 | 138 | # Pyre type checker 139 | .pyre/ 140 | 141 | # pytype static type analyzer 142 | .pytype/ 143 | 144 | # Cython debug symbols 145 | cython_debug/ 146 | 147 | # PyCharm 148 | # JetBrains specific template is maintainted in a separate JetBrains.gitignore that can 149 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 150 | # and can be added to the global gitignore or merged into this file. For a more nuclear 151 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 152 | #.idea/ 153 | .vscode/ 154 | docs/_build/ 155 | _autodoc/ 156 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | # See https://pre-commit.com for more information 2 | # See https://pre-commit.com/hooks.html for more hooks 3 | 4 | exclude: ^tests/.*\.md|tests/.*\.rst|tests/.*\.xml|docs/apidocs/.* 5 | 6 | repos: 7 | - repo: https://github.com/pre-commit/pre-commit-hooks 8 | rev: v4.6.0 9 | hooks: 10 | - id: trailing-whitespace 11 | - id: end-of-file-fixer 12 | - id: check-yaml 13 | 14 | - repo: https://github.com/astral-sh/ruff-pre-commit 15 | rev: v0.4.4 16 | hooks: 17 | - id: ruff 18 | args: [--fix] 19 | - id: ruff-format 20 | 21 | - repo: https://github.com/pre-commit/mirrors-mypy 22 | rev: v1.10.0 23 | hooks: 24 | - id: mypy 25 | args: [--config-file=pyproject.toml] 26 | additional_dependencies: ["sphinx~=7.3", "typer[all]"] 27 | exclude: ^tests/.*\.py$ 28 | -------------------------------------------------------------------------------- /.readthedocs.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | build: 4 | os: ubuntu-22.04 5 | tools: 6 | python: "3.8" 7 | 8 | python: 9 | install: 10 | - method: pip 11 | path: . 12 | extra_requirements: 13 | - docs 14 | 15 | sphinx: 16 | builder: html 17 | fail_on_warning: true 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2023 Chris Sewell 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sphinx-autodoc2 2 | 3 | `sphinx-autodoc2` is a Sphinx extension that automatically generates API documentation for your Python packages. 4 | 5 | [![GitHub Repo stars](https://img.shields.io/github/stars/chrisjsewell/sphinx-autodoc2?label=Like%20and%20Share%21&style=social)](https://github.com/chrisjsewell/sphinx-autodoc2) 6 | [![PyPI](https://img.shields.io/pypi/v/sphinx-autodoc2?label=PyPI&logo=pypi&style=social)](https://pypi.org/project/sphinx-autodoc2/) 7 | 8 | Static analysis of Python code 9 | 10 | : There is no need to install your package to generate the documentation, and `sphinx-autodoc2` will correctly handle `if TYPE_CHECKING` blocks and other typing only features. 11 | : You can even document packages from outside the project (via `git clone`)! 12 | 13 | Optimized for rebuilds 14 | 15 | : Analysis of packages and file rendering are cached, so you can use `sphinx-autodoc2` in your development workflow. 16 | 17 | Support for `__all__` 18 | 19 | : `sphinx-autodoc2` can follow `__all__` variable, to only document the public API. 20 | 21 | Support for both `rst` and `md` docstrings 22 | 23 | : `sphinx-autodoc2` supports both `rst` and `md` ([MyST](https://myst-parser.readthedocs.io)) docstrings, which can be mixed within the same project. 24 | 25 | Highly configurable 26 | 27 | : `sphinx-autodoc2` is highly configurable, with many options to control the analysis and output of the documentation. 28 | 29 | Decoupled analysis and rendering 30 | 31 | : The analysis and rendering of the documentation are decoupled, and not dependent on Sphinx. 32 | : This means that you can use `sphinx-autodoc2` to generate documentation outside of Sphinx (see the `autodoc2` command line tool). 33 | 34 | See the documentation for more information! 35 | 36 | ## Design and comparison to sphinx-autoapi 37 | 38 | I wanted an extension with the following goals: 39 | 40 | - Static analysis of Python code, so things like `if TYPE_CHECKING` were handled correctly 41 | - Support for MyST docstrings (see ) 42 | - Also support for transitioning from `rst` to `md`, i.e. mixing docstrings 43 | - Make it simple and minimise the amount of configuration and rebuilds necessary 44 | - Support for building public API via `__all__` variable 45 | 46 | I am not looking to support other languages tha Python (at least for now). 47 | 48 | [sphinx-autoapi](https://github.com/readthedocs/sphinx-autoapi) was a good candidate, but it had a few issues: 49 | 50 | - It does not support MyST docstrings: 51 | - It does not support the `__all__` very well: 52 | - The analysis and rendering are coupled, making it difficult to test, modify and use outside of Sphinx 53 | 54 | I've use a lot of their code, for the `astroid` static analysis, but I've made a number of "improvements": 55 | 56 | - separating concerns: analysis and template writing 57 | - type annotations for code base 58 | - fixed `a | b` annotations inference 59 | - added analysis of `functools.singledispatch` and their registers 60 | - handling of `__all__` 61 | - docstrings (and summaries) are now parsed with the correct source/line, i.e. warnings point to the correct location in the source file 62 | - added `:canonical:` to `py` directives 63 | - Moved away from using jinja templates, to using python functions 64 | - IMO the templates were too complex and hard to read, 65 | plus they do not benefit from any form of type checking, linting, etc. 66 | - uses `list-table`, instead of `auto-summary` directive 67 | 68 | ## Development 69 | 70 | All configuration is mainly in `pyproject.toml`. 71 | 72 | Use [tox](https://tox.readthedocs.io/en/latest/) to run the tests. 73 | 74 | ```bash 75 | pipx install tox 76 | tox -av 77 | ``` 78 | 79 | Use [pre-commit](https://pre-commit.com/) to run the linters and formatters. 80 | 81 | ```bash 82 | pipx install pre-commit 83 | pre-commit run --all-files 84 | # pre-commit install 85 | ``` 86 | 87 | [flit](https://flit.readthedocs.io/en/latest/) is used to build the package. 88 | 89 | ```bash 90 | pipx install flit 91 | flit build 92 | ``` 93 | -------------------------------------------------------------------------------- /docs/apidocs/aiida/aiida.parsers.rst: -------------------------------------------------------------------------------- 1 | :py:mod:`aiida.parsers` 2 | ======================= 3 | 4 | .. py:module:: aiida.parsers 5 | 6 | .. autodoc2-docstring:: aiida.parsers 7 | :allowtitles: 8 | 9 | Package Contents 10 | ---------------- 11 | 12 | Classes 13 | ~~~~~~~ 14 | 15 | .. list-table:: 16 | :class: autosummary longtable 17 | :align: left 18 | 19 | * - :py:obj:`Parser ` 20 | - .. autodoc2-docstring:: aiida.parsers.parser.Parser 21 | :summary: 22 | 23 | API 24 | ~~~ 25 | 26 | .. py:class:: Parser(node: aiida.orm.CalcJobNode) 27 | :canonical: aiida.parsers.parser.Parser 28 | 29 | Bases: :py:obj:`abc.ABC` 30 | 31 | .. autodoc2-docstring:: aiida.parsers.parser.Parser 32 | 33 | .. rubric:: Initialization 34 | 35 | .. autodoc2-docstring:: aiida.parsers.parser.Parser.__init__ 36 | 37 | .. py:property:: logger 38 | :canonical: aiida.parsers.parser.Parser.logger 39 | 40 | .. autodoc2-docstring:: aiida.parsers.parser.Parser.logger 41 | 42 | .. py:property:: node 43 | :canonical: aiida.parsers.parser.Parser.node 44 | :type: aiida.orm.CalcJobNode 45 | 46 | .. autodoc2-docstring:: aiida.parsers.parser.Parser.node 47 | 48 | .. py:property:: exit_codes 49 | :canonical: aiida.parsers.parser.Parser.exit_codes 50 | :type: aiida.engine.ExitCodesNamespace 51 | 52 | .. autodoc2-docstring:: aiida.parsers.parser.Parser.exit_codes 53 | 54 | .. py:property:: retrieved 55 | :canonical: aiida.parsers.parser.Parser.retrieved 56 | :type: aiida.orm.FolderData 57 | 58 | .. autodoc2-docstring:: aiida.parsers.parser.Parser.retrieved 59 | 60 | .. py:property:: outputs 61 | :canonical: aiida.parsers.parser.Parser.outputs 62 | 63 | .. autodoc2-docstring:: aiida.parsers.parser.Parser.outputs 64 | 65 | .. py:method:: out(link_label: str, node: aiida.orm.Data) -> None 66 | :canonical: aiida.parsers.parser.Parser.out 67 | 68 | .. autodoc2-docstring:: aiida.parsers.parser.Parser.out 69 | 70 | .. py:method:: get_outputs_for_parsing() 71 | :canonical: aiida.parsers.parser.Parser.get_outputs_for_parsing 72 | 73 | .. autodoc2-docstring:: aiida.parsers.parser.Parser.get_outputs_for_parsing 74 | 75 | .. py:method:: parse_from_node(node: aiida.orm.CalcJobNode, store_provenance=True, retrieved_temporary_folder=None) -> typing.Tuple[typing.Optional[typing.Dict[str, typing.Any]], aiida.orm.CalcFunctionNode] 76 | :canonical: aiida.parsers.parser.Parser.parse_from_node 77 | :classmethod: 78 | 79 | .. autodoc2-docstring:: aiida.parsers.parser.Parser.parse_from_node 80 | 81 | .. py:method:: parse(**kwargs) -> typing.Optional[aiida.engine.ExitCode] 82 | :canonical: aiida.parsers.parser.Parser.parse 83 | :abstractmethod: 84 | 85 | .. autodoc2-docstring:: aiida.parsers.parser.Parser.parse 86 | -------------------------------------------------------------------------------- /docs/apidocs/aiida/aiida.plugins.rst: -------------------------------------------------------------------------------- 1 | :py:mod:`aiida.plugins` 2 | ======================= 3 | 4 | .. py:module:: aiida.plugins 5 | 6 | .. autodoc2-docstring:: aiida.plugins 7 | :allowtitles: 8 | 9 | Package Contents 10 | ---------------- 11 | 12 | Classes 13 | ~~~~~~~ 14 | 15 | .. list-table:: 16 | :class: autosummary longtable 17 | :align: left 18 | 19 | * - :py:obj:`PluginVersionProvider ` 20 | - .. autodoc2-docstring:: aiida.plugins.utils.PluginVersionProvider 21 | :summary: 22 | 23 | Functions 24 | ~~~~~~~~~ 25 | 26 | .. list-table:: 27 | :class: autosummary longtable 28 | :align: left 29 | 30 | * - :py:obj:`BaseFactory ` 31 | - .. autodoc2-docstring:: aiida.plugins.factories.BaseFactory 32 | :summary: 33 | * - :py:obj:`CalcJobImporterFactory ` 34 | - .. autodoc2-docstring:: aiida.plugins.factories.CalcJobImporterFactory 35 | :summary: 36 | * - :py:obj:`CalculationFactory ` 37 | - .. autodoc2-docstring:: aiida.plugins.factories.CalculationFactory 38 | :summary: 39 | * - :py:obj:`DataFactory ` 40 | - .. autodoc2-docstring:: aiida.plugins.factories.DataFactory 41 | :summary: 42 | * - :py:obj:`DbImporterFactory ` 43 | - .. autodoc2-docstring:: aiida.plugins.factories.DbImporterFactory 44 | :summary: 45 | * - :py:obj:`GroupFactory ` 46 | - .. autodoc2-docstring:: aiida.plugins.factories.GroupFactory 47 | :summary: 48 | * - :py:obj:`OrbitalFactory ` 49 | - .. autodoc2-docstring:: aiida.plugins.factories.OrbitalFactory 50 | :summary: 51 | * - :py:obj:`ParserFactory ` 52 | - .. autodoc2-docstring:: aiida.plugins.factories.ParserFactory 53 | :summary: 54 | * - :py:obj:`SchedulerFactory ` 55 | - .. autodoc2-docstring:: aiida.plugins.factories.SchedulerFactory 56 | :summary: 57 | * - :py:obj:`StorageFactory ` 58 | - .. autodoc2-docstring:: aiida.plugins.factories.StorageFactory 59 | :summary: 60 | * - :py:obj:`TransportFactory ` 61 | - .. autodoc2-docstring:: aiida.plugins.factories.TransportFactory 62 | :summary: 63 | * - :py:obj:`WorkflowFactory ` 64 | - .. autodoc2-docstring:: aiida.plugins.factories.WorkflowFactory 65 | :summary: 66 | * - :py:obj:`get_entry_points ` 67 | - .. autodoc2-docstring:: aiida.plugins.entry_point.get_entry_points 68 | :summary: 69 | * - :py:obj:`load_entry_point ` 70 | - .. autodoc2-docstring:: aiida.plugins.entry_point.load_entry_point 71 | :summary: 72 | * - :py:obj:`load_entry_point_from_string ` 73 | - .. autodoc2-docstring:: aiida.plugins.entry_point.load_entry_point_from_string 74 | :summary: 75 | * - :py:obj:`parse_entry_point ` 76 | - .. autodoc2-docstring:: aiida.plugins.entry_point.parse_entry_point 77 | :summary: 78 | 79 | API 80 | ~~~ 81 | 82 | .. py:function:: BaseFactory(group: str, name: str, load: bool = True) -> typing.Union[importlib_metadata.EntryPoint, typing.Any] 83 | :canonical: aiida.plugins.factories.BaseFactory 84 | 85 | .. autodoc2-docstring:: aiida.plugins.factories.BaseFactory 86 | 87 | .. py:function:: CalcJobImporterFactory(entry_point_name: str, load: bool = True) -> typing.Union[importlib_metadata.EntryPoint, typing.Type[aiida.engine.CalcJobImporter]] 88 | :canonical: aiida.plugins.factories.CalcJobImporterFactory 89 | 90 | .. autodoc2-docstring:: aiida.plugins.factories.CalcJobImporterFactory 91 | 92 | .. py:function:: CalculationFactory(entry_point_name: str, load: bool = True) -> typing.Union[importlib_metadata.EntryPoint, typing.Type[aiida.engine.CalcJob], typing.Callable] 93 | :canonical: aiida.plugins.factories.CalculationFactory 94 | 95 | .. autodoc2-docstring:: aiida.plugins.factories.CalculationFactory 96 | 97 | .. py:function:: DataFactory(entry_point_name: str, load: bool = True) -> typing.Union[importlib_metadata.EntryPoint, typing.Type[aiida.orm.Data]] 98 | :canonical: aiida.plugins.factories.DataFactory 99 | 100 | .. autodoc2-docstring:: aiida.plugins.factories.DataFactory 101 | 102 | .. py:function:: DbImporterFactory(entry_point_name: str, load: bool = True) -> typing.Union[importlib_metadata.EntryPoint, typing.Type[aiida.tools.dbimporters.DbImporter]] 103 | :canonical: aiida.plugins.factories.DbImporterFactory 104 | 105 | .. autodoc2-docstring:: aiida.plugins.factories.DbImporterFactory 106 | 107 | .. py:function:: GroupFactory(entry_point_name: str, load: bool = True) -> typing.Union[importlib_metadata.EntryPoint, typing.Type[aiida.orm.Group]] 108 | :canonical: aiida.plugins.factories.GroupFactory 109 | 110 | .. autodoc2-docstring:: aiida.plugins.factories.GroupFactory 111 | 112 | .. py:function:: OrbitalFactory(entry_point_name: str, load: bool = True) -> typing.Union[importlib_metadata.EntryPoint, typing.Type[aiida.tools.data.orbital.Orbital]] 113 | :canonical: aiida.plugins.factories.OrbitalFactory 114 | 115 | .. autodoc2-docstring:: aiida.plugins.factories.OrbitalFactory 116 | 117 | .. py:function:: ParserFactory(entry_point_name: str, load: bool = True) -> typing.Union[importlib_metadata.EntryPoint, typing.Type[aiida.parsers.Parser]] 118 | :canonical: aiida.plugins.factories.ParserFactory 119 | 120 | .. autodoc2-docstring:: aiida.plugins.factories.ParserFactory 121 | 122 | .. py:class:: PluginVersionProvider() 123 | :canonical: aiida.plugins.utils.PluginVersionProvider 124 | 125 | .. autodoc2-docstring:: aiida.plugins.utils.PluginVersionProvider 126 | 127 | .. rubric:: Initialization 128 | 129 | .. autodoc2-docstring:: aiida.plugins.utils.PluginVersionProvider.__init__ 130 | 131 | .. py:property:: logger 132 | :canonical: aiida.plugins.utils.PluginVersionProvider.logger 133 | :type: logging.Logger 134 | 135 | .. autodoc2-docstring:: aiida.plugins.utils.PluginVersionProvider.logger 136 | 137 | .. py:method:: get_version_info(plugin: str | type) -> dict[typing.Any, dict[typing.Any, typing.Any]] 138 | :canonical: aiida.plugins.utils.PluginVersionProvider.get_version_info 139 | 140 | .. autodoc2-docstring:: aiida.plugins.utils.PluginVersionProvider.get_version_info 141 | 142 | .. py:function:: SchedulerFactory(entry_point_name: str, load: bool = True) -> typing.Union[importlib_metadata.EntryPoint, typing.Type[aiida.schedulers.Scheduler]] 143 | :canonical: aiida.plugins.factories.SchedulerFactory 144 | 145 | .. autodoc2-docstring:: aiida.plugins.factories.SchedulerFactory 146 | 147 | .. py:function:: StorageFactory(entry_point_name: str, load: bool = True) -> typing.Union[importlib_metadata.EntryPoint, typing.Type[aiida.orm.implementation.StorageBackend]] 148 | :canonical: aiida.plugins.factories.StorageFactory 149 | 150 | .. autodoc2-docstring:: aiida.plugins.factories.StorageFactory 151 | 152 | .. py:function:: TransportFactory(entry_point_name: str, load: bool = True) -> typing.Union[importlib_metadata.EntryPoint, typing.Type[aiida.transports.Transport]] 153 | :canonical: aiida.plugins.factories.TransportFactory 154 | 155 | .. autodoc2-docstring:: aiida.plugins.factories.TransportFactory 156 | 157 | .. py:function:: WorkflowFactory(entry_point_name: str, load: bool = True) -> typing.Union[importlib_metadata.EntryPoint, typing.Type[aiida.engine.WorkChain], typing.Callable] 158 | :canonical: aiida.plugins.factories.WorkflowFactory 159 | 160 | .. autodoc2-docstring:: aiida.plugins.factories.WorkflowFactory 161 | 162 | .. py:function:: get_entry_points(group: str) -> importlib_metadata.EntryPoints 163 | :canonical: aiida.plugins.entry_point.get_entry_points 164 | 165 | .. autodoc2-docstring:: aiida.plugins.entry_point.get_entry_points 166 | 167 | .. py:function:: load_entry_point(group: str, name: str) -> typing.Any 168 | :canonical: aiida.plugins.entry_point.load_entry_point 169 | 170 | .. autodoc2-docstring:: aiida.plugins.entry_point.load_entry_point 171 | 172 | .. py:function:: load_entry_point_from_string(entry_point_string: str) -> typing.Any 173 | :canonical: aiida.plugins.entry_point.load_entry_point_from_string 174 | 175 | .. autodoc2-docstring:: aiida.plugins.entry_point.load_entry_point_from_string 176 | 177 | .. py:function:: parse_entry_point(group: str, spec: str) -> importlib_metadata.EntryPoint 178 | :canonical: aiida.plugins.entry_point.parse_entry_point 179 | 180 | .. autodoc2-docstring:: aiida.plugins.entry_point.parse_entry_point 181 | -------------------------------------------------------------------------------- /docs/apidocs/aiida/aiida.rst: -------------------------------------------------------------------------------- 1 | :py:mod:`aiida` 2 | =============== 3 | 4 | .. py:module:: aiida 5 | 6 | .. autodoc2-docstring:: aiida 7 | :allowtitles: 8 | 9 | Subpackages 10 | ----------- 11 | 12 | .. toctree:: 13 | :titlesonly: 14 | :maxdepth: 3 15 | 16 | aiida.repository 17 | aiida.parsers 18 | aiida.tools 19 | aiida.plugins 20 | aiida.transports 21 | aiida.cmdline 22 | aiida.common 23 | aiida.manage 24 | aiida.orm 25 | aiida.engine 26 | aiida.schedulers 27 | 28 | Package Contents 29 | ---------------- 30 | 31 | Functions 32 | ~~~~~~~~~ 33 | 34 | .. list-table:: 35 | :class: autosummary longtable 36 | :align: left 37 | 38 | * - :py:obj:`get_strict_version ` 39 | - .. autodoc2-docstring:: aiida.get_strict_version 40 | :summary: 41 | * - :py:obj:`get_version ` 42 | - .. autodoc2-docstring:: aiida.get_version 43 | :summary: 44 | * - :py:obj:`_get_raw_file_header ` 45 | - .. autodoc2-docstring:: aiida._get_raw_file_header 46 | :summary: 47 | * - :py:obj:`get_file_header ` 48 | - .. autodoc2-docstring:: aiida.get_file_header 49 | :summary: 50 | * - :py:obj:`load_ipython_extension ` 51 | - .. autodoc2-docstring:: aiida.load_ipython_extension 52 | :summary: 53 | 54 | Data 55 | ~~~~ 56 | 57 | .. list-table:: 58 | :class: autosummary longtable 59 | :align: left 60 | 61 | * - :py:obj:`__copyright__ ` 62 | - .. autodoc2-docstring:: aiida.__copyright__ 63 | :summary: 64 | * - :py:obj:`__license__ ` 65 | - .. autodoc2-docstring:: aiida.__license__ 66 | :summary: 67 | * - :py:obj:`__version__ ` 68 | - .. autodoc2-docstring:: aiida.__version__ 69 | :summary: 70 | * - :py:obj:`__authors__ ` 71 | - .. autodoc2-docstring:: aiida.__authors__ 72 | :summary: 73 | * - :py:obj:`__paper__ ` 74 | - .. autodoc2-docstring:: aiida.__paper__ 75 | :summary: 76 | * - :py:obj:`__paper_short__ ` 77 | - .. autodoc2-docstring:: aiida.__paper_short__ 78 | :summary: 79 | 80 | API 81 | ~~~ 82 | 83 | .. py:data:: __copyright__ 84 | :canonical: aiida.__copyright__ 85 | :value: 'Copyright (c), This file is part of the AiiDA platform. For further information please visit http://...' 86 | 87 | .. autodoc2-docstring:: aiida.__copyright__ 88 | 89 | .. py:data:: __license__ 90 | :canonical: aiida.__license__ 91 | :value: 'MIT license, see LICENSE.txt file.' 92 | 93 | .. autodoc2-docstring:: aiida.__license__ 94 | 95 | .. py:data:: __version__ 96 | :canonical: aiida.__version__ 97 | :value: '2.2.2' 98 | 99 | .. autodoc2-docstring:: aiida.__version__ 100 | 101 | .. py:data:: __authors__ 102 | :canonical: aiida.__authors__ 103 | :value: 'The AiiDA team.' 104 | 105 | .. autodoc2-docstring:: aiida.__authors__ 106 | 107 | .. py:data:: __paper__ 108 | :canonical: aiida.__paper__ 109 | :value: 'S. P. Huber et al., "AiiDA 1.0, a scalable computational infrastructure for automated reproducible w...' 110 | 111 | .. autodoc2-docstring:: aiida.__paper__ 112 | 113 | .. py:data:: __paper_short__ 114 | :canonical: aiida.__paper_short__ 115 | :value: 'S. P. Huber et al., Scientific Data 7, 300 (2020).' 116 | 117 | .. autodoc2-docstring:: aiida.__paper_short__ 118 | 119 | .. py:function:: get_strict_version() 120 | :canonical: aiida.get_strict_version 121 | 122 | .. autodoc2-docstring:: aiida.get_strict_version 123 | 124 | .. py:function:: get_version() -> str 125 | :canonical: aiida.get_version 126 | 127 | .. autodoc2-docstring:: aiida.get_version 128 | 129 | .. py:function:: _get_raw_file_header() -> str 130 | :canonical: aiida._get_raw_file_header 131 | 132 | .. autodoc2-docstring:: aiida._get_raw_file_header 133 | 134 | .. py:function:: get_file_header(comment_char: str = '# ') -> str 135 | :canonical: aiida.get_file_header 136 | 137 | .. autodoc2-docstring:: aiida.get_file_header 138 | 139 | .. py:function:: load_ipython_extension(ipython) 140 | :canonical: aiida.load_ipython_extension 141 | 142 | .. autodoc2-docstring:: aiida.load_ipython_extension 143 | -------------------------------------------------------------------------------- /docs/apidocs/autodoc2/autodoc2.analysis.rst: -------------------------------------------------------------------------------- 1 | :py:mod:`autodoc2.analysis` 2 | =========================== 3 | 4 | .. py:module:: autodoc2.analysis 5 | 6 | .. autodoc2-docstring:: autodoc2.analysis 7 | :allowtitles: 8 | 9 | Module Contents 10 | --------------- 11 | 12 | Classes 13 | ~~~~~~~ 14 | 15 | .. list-table:: 16 | :class: autosummary longtable 17 | :align: left 18 | 19 | * - :py:obj:`State ` 20 | - .. autodoc2-docstring:: autodoc2.analysis.State 21 | :summary: 22 | 23 | Functions 24 | ~~~~~~~~~ 25 | 26 | .. list-table:: 27 | :class: autosummary longtable 28 | :align: left 29 | 30 | * - :py:obj:`analyse_module ` 31 | - .. autodoc2-docstring:: autodoc2.analysis.analyse_module 32 | :summary: 33 | * - :py:obj:`_get_full_name ` 34 | - .. autodoc2-docstring:: autodoc2.analysis._get_full_name 35 | :summary: 36 | * - :py:obj:`_get_parent_name ` 37 | - .. autodoc2-docstring:: autodoc2.analysis._get_parent_name 38 | :summary: 39 | * - :py:obj:`fix_docstring_indent ` 40 | - .. autodoc2-docstring:: autodoc2.analysis.fix_docstring_indent 41 | :summary: 42 | * - :py:obj:`walk_node ` 43 | - .. autodoc2-docstring:: autodoc2.analysis.walk_node 44 | :summary: 45 | * - :py:obj:`yield_module ` 46 | - .. autodoc2-docstring:: autodoc2.analysis.yield_module 47 | :summary: 48 | * - :py:obj:`yield_annotation_assign ` 49 | - .. autodoc2-docstring:: autodoc2.analysis.yield_annotation_assign 50 | :summary: 51 | * - :py:obj:`yield_assign ` 52 | - .. autodoc2-docstring:: autodoc2.analysis.yield_assign 53 | :summary: 54 | * - :py:obj:`_yield_assign ` 55 | - .. autodoc2-docstring:: autodoc2.analysis._yield_assign 56 | :summary: 57 | * - :py:obj:`yield_function_def ` 58 | - .. autodoc2-docstring:: autodoc2.analysis.yield_function_def 59 | :summary: 60 | * - :py:obj:`yield_class_def ` 61 | - .. autodoc2-docstring:: autodoc2.analysis.yield_class_def 62 | :summary: 63 | 64 | Data 65 | ~~~~ 66 | 67 | .. list-table:: 68 | :class: autosummary longtable 69 | :align: left 70 | 71 | * - :py:obj:`__all__ ` 72 | - .. autodoc2-docstring:: autodoc2.analysis.__all__ 73 | :summary: 74 | * - :py:obj:`_dc_kwargs ` 75 | - .. autodoc2-docstring:: autodoc2.analysis._dc_kwargs 76 | :summary: 77 | * - :py:obj:`_FUNC_MAPPER ` 78 | - .. autodoc2-docstring:: autodoc2.analysis._FUNC_MAPPER 79 | :summary: 80 | 81 | API 82 | ~~~ 83 | 84 | .. py:data:: __all__ 85 | :canonical: autodoc2.analysis.__all__ 86 | :value: ['analyse_module'] 87 | 88 | .. autodoc2-docstring:: autodoc2.analysis.__all__ 89 | 90 | .. py:function:: analyse_module(file_path: pathlib.Path, name: str, exclude_external_imports: typing.Pattern[str] | None = None) -> typing.Iterable[autodoc2.utils.ItemData] 91 | :canonical: autodoc2.analysis.analyse_module 92 | 93 | .. autodoc2-docstring:: autodoc2.analysis.analyse_module 94 | 95 | .. py:data:: _dc_kwargs 96 | :canonical: autodoc2.analysis._dc_kwargs 97 | :type: dict[str, bool] 98 | :value: None 99 | 100 | .. autodoc2-docstring:: autodoc2.analysis._dc_kwargs 101 | 102 | .. py:class:: State 103 | :canonical: autodoc2.analysis.State 104 | 105 | .. autodoc2-docstring:: autodoc2.analysis.State 106 | 107 | .. py:attribute:: package_name 108 | :canonical: autodoc2.analysis.State.package_name 109 | :type: str 110 | :value: None 111 | 112 | .. autodoc2-docstring:: autodoc2.analysis.State.package_name 113 | 114 | .. py:attribute:: name_stack 115 | :canonical: autodoc2.analysis.State.name_stack 116 | :type: list[str] 117 | :value: None 118 | 119 | .. autodoc2-docstring:: autodoc2.analysis.State.name_stack 120 | 121 | .. py:attribute:: exclude_external_imports 122 | :canonical: autodoc2.analysis.State.exclude_external_imports 123 | :type: typing.Pattern[str] | None 124 | :value: None 125 | 126 | .. autodoc2-docstring:: autodoc2.analysis.State.exclude_external_imports 127 | 128 | .. py:method:: copy(**kwargs: typing.Any) -> autodoc2.analysis.State 129 | :canonical: autodoc2.analysis.State.copy 130 | 131 | .. autodoc2-docstring:: autodoc2.analysis.State.copy 132 | 133 | .. py:function:: _get_full_name(name: str, name_stack: list[str]) -> str 134 | :canonical: autodoc2.analysis._get_full_name 135 | 136 | .. autodoc2-docstring:: autodoc2.analysis._get_full_name 137 | 138 | .. py:function:: _get_parent_name(name: str) -> str 139 | :canonical: autodoc2.analysis._get_parent_name 140 | 141 | .. autodoc2-docstring:: autodoc2.analysis._get_parent_name 142 | 143 | .. py:function:: fix_docstring_indent(s: None | str, tabsize: int = 8) -> str 144 | :canonical: autodoc2.analysis.fix_docstring_indent 145 | 146 | .. autodoc2-docstring:: autodoc2.analysis.fix_docstring_indent 147 | 148 | .. py:function:: walk_node(node: astroid.nodes.NodeNG, state: autodoc2.analysis.State) -> typing.Iterable[autodoc2.utils.ItemData] 149 | :canonical: autodoc2.analysis.walk_node 150 | 151 | .. autodoc2-docstring:: autodoc2.analysis.walk_node 152 | 153 | .. py:function:: yield_module(node: astroid.nodes.Module, state: autodoc2.analysis.State) -> typing.Iterable[autodoc2.utils.ItemData] 154 | :canonical: autodoc2.analysis.yield_module 155 | 156 | .. autodoc2-docstring:: autodoc2.analysis.yield_module 157 | 158 | .. py:function:: yield_annotation_assign(node: astroid.nodes.AnnAssign, state: autodoc2.analysis.State) -> typing.Iterable[autodoc2.utils.ItemData] 159 | :canonical: autodoc2.analysis.yield_annotation_assign 160 | 161 | .. autodoc2-docstring:: autodoc2.analysis.yield_annotation_assign 162 | 163 | .. py:function:: yield_assign(node: astroid.nodes.Assign, state: autodoc2.analysis.State) -> typing.Iterable[autodoc2.utils.ItemData] 164 | :canonical: autodoc2.analysis.yield_assign 165 | 166 | .. autodoc2-docstring:: autodoc2.analysis.yield_assign 167 | 168 | .. py:function:: _yield_assign(node: astroid.nodes.Assign | astroid.nodes.AnnAssign, state: autodoc2.analysis.State) -> typing.Iterable[autodoc2.utils.ItemData] 169 | :canonical: autodoc2.analysis._yield_assign 170 | 171 | .. autodoc2-docstring:: autodoc2.analysis._yield_assign 172 | 173 | .. py:function:: yield_function_def(node: astroid.nodes.FunctionDef | astroid.nodes.AsyncFunctionDef, state: autodoc2.analysis.State) -> typing.Iterable[autodoc2.utils.ItemData] 174 | :canonical: autodoc2.analysis.yield_function_def 175 | 176 | .. autodoc2-docstring:: autodoc2.analysis.yield_function_def 177 | 178 | .. py:function:: yield_class_def(node: astroid.nodes.ClassDef, state: autodoc2.analysis.State) -> typing.Iterable[autodoc2.utils.ItemData] 179 | :canonical: autodoc2.analysis.yield_class_def 180 | 181 | .. autodoc2-docstring:: autodoc2.analysis.yield_class_def 182 | 183 | .. py:data:: _FUNC_MAPPER 184 | :canonical: autodoc2.analysis._FUNC_MAPPER 185 | :type: dict[astroid.nodes.NodeNG, typing.Callable[[astroid.nodes.NodeNG, autodoc2.analysis.State], typing.Iterable[autodoc2.utils.ItemData]]] 186 | :value: None 187 | 188 | .. autodoc2-docstring:: autodoc2.analysis._FUNC_MAPPER 189 | -------------------------------------------------------------------------------- /docs/apidocs/autodoc2/autodoc2.cli.rst: -------------------------------------------------------------------------------- 1 | :py:mod:`autodoc2.cli` 2 | ====================== 3 | 4 | .. py:module:: autodoc2.cli 5 | 6 | .. autodoc2-docstring:: autodoc2.cli 7 | :allowtitles: 8 | 9 | Module Contents 10 | --------------- 11 | 12 | Functions 13 | ~~~~~~~~~ 14 | 15 | .. list-table:: 16 | :class: autosummary longtable 17 | :align: left 18 | 19 | * - :py:obj:`version_callback ` 20 | - .. autodoc2-docstring:: autodoc2.cli.version_callback 21 | :summary: 22 | * - :py:obj:`main_app ` 23 | - .. autodoc2-docstring:: autodoc2.cli.main_app 24 | :summary: 25 | * - :py:obj:`list_items ` 26 | - .. autodoc2-docstring:: autodoc2.cli.list_items 27 | :summary: 28 | * - :py:obj:`create_db ` 29 | - .. autodoc2-docstring:: autodoc2.cli.create_db 30 | :summary: 31 | * - :py:obj:`analyse_all ` 32 | - .. autodoc2-docstring:: autodoc2.cli.analyse_all 33 | :summary: 34 | * - :py:obj:`write ` 35 | - .. autodoc2-docstring:: autodoc2.cli.write 36 | :summary: 37 | 38 | Data 39 | ~~~~ 40 | 41 | .. list-table:: 42 | :class: autosummary longtable 43 | :align: left 44 | 45 | * - :py:obj:`console ` 46 | - .. autodoc2-docstring:: autodoc2.cli.console 47 | :summary: 48 | * - :py:obj:`app_main ` 49 | - .. autodoc2-docstring:: autodoc2.cli.app_main 50 | :summary: 51 | 52 | API 53 | ~~~ 54 | 55 | .. py:data:: console 56 | :canonical: autodoc2.cli.console 57 | :value: None 58 | 59 | .. autodoc2-docstring:: autodoc2.cli.console 60 | 61 | .. py:data:: app_main 62 | :canonical: autodoc2.cli.app_main 63 | :value: None 64 | 65 | .. autodoc2-docstring:: autodoc2.cli.app_main 66 | 67 | .. py:function:: version_callback(value: bool) -> None 68 | :canonical: autodoc2.cli.version_callback 69 | 70 | .. autodoc2-docstring:: autodoc2.cli.version_callback 71 | 72 | .. py:function:: main_app(version: typing.Optional[bool] = typer.Option(None, '-v', '--version', callback=version_callback, is_eager=True, help='Show the application version and exit.')) -> None 73 | :canonical: autodoc2.cli.main_app 74 | 75 | .. autodoc2-docstring:: autodoc2.cli.main_app 76 | 77 | .. py:function:: list_items(path: pathlib.Path = typer.Argument(..., exists=True, help='Path to analyse'), module: typing.Optional[str] = typer.Option(None, '-m', '--module', help='The name of the module, otherwise it will be guessed from the path'), inherited: bool = typer.Option(False, '-i', '--inherited', help='Show inherited members'), private: bool = typer.Option(False, '-p', '--private', help='Show private members'), one_line: bool = typer.Option(False, '-o', '--one-line', help='Show only full name and type'), filter_types_str: typing.Optional[str] = typer.Option(None, '-ft', '--filter-types', help='Only show members of types (comma separated)'), skip_types_str: str = typer.Option('import_from', '-st', '--skip-types', help='Do not show members of types (comma separated)'), filter_name: typing.Optional[str] = typer.Option(None, '-fn', '--filter-name', help='Only show members with this name regex')) -> None 78 | :canonical: autodoc2.cli.list_items 79 | 80 | .. autodoc2-docstring:: autodoc2.cli.list_items 81 | 82 | .. py:function:: create_db(path: pathlib.Path = typer.Argument(..., exists=True, help='Path to analyse'), output: pathlib.Path = typer.Argument('autodoc.db.json', help='File to write to'), module: typing.Optional[str] = typer.Option(None, '-m', '--module', help='The name of the module, otherwise it will be guessed from the path')) -> None 83 | :canonical: autodoc2.cli.create_db 84 | 85 | .. autodoc2-docstring:: autodoc2.cli.create_db 86 | 87 | .. py:function:: analyse_all(path: pathlib.Path = typer.Argument(..., exists=True, help='Path to a database file'), package: str = typer.Argument(..., help='The name of the package to resolve.')) -> None 88 | :canonical: autodoc2.cli.analyse_all 89 | 90 | .. autodoc2-docstring:: autodoc2.cli.analyse_all 91 | 92 | .. py:function:: write(path: pathlib.Path = typer.Argument(..., exists=True, help='Path to analyse'), module: typing.Optional[str] = typer.Option(None, '-m', '--module', help='The name of the module, otherwise it will be guessed from the path'), output: pathlib.Path = typer.Option('_autodoc', help='Folder to write to'), clean: bool = typer.Option(False, '-c', '--clean', help='Remove old files')) -> None 93 | :canonical: autodoc2.cli.write 94 | 95 | .. autodoc2-docstring:: autodoc2.cli.write 96 | -------------------------------------------------------------------------------- /docs/apidocs/autodoc2/autodoc2.db.md: -------------------------------------------------------------------------------- 1 | # {py:mod}`autodoc2.db` 2 | 3 | ```{py:module} autodoc2.db 4 | ``` 5 | 6 | ```{autodoc2-docstring} autodoc2.db 7 | :allowtitles: 8 | ``` 9 | 10 | ## Module Contents 11 | 12 | ### Classes 13 | 14 | ````{list-table} 15 | :class: autosummary longtable 16 | :align: left 17 | 18 | * - {py:obj}`Database ` 19 | - ```{autodoc2-docstring} autodoc2.db.Database 20 | :summary: 21 | ``` 22 | * - {py:obj}`InMemoryDb ` 23 | - ```{autodoc2-docstring} autodoc2.db.InMemoryDb 24 | :summary: 25 | ``` 26 | ```` 27 | 28 | ### Data 29 | 30 | ````{list-table} 31 | :class: autosummary longtable 32 | :align: left 33 | 34 | * - {py:obj}`_LIKE_REGEX ` 35 | - ```{autodoc2-docstring} autodoc2.db._LIKE_REGEX 36 | :summary: 37 | ``` 38 | ```` 39 | 40 | ### API 41 | 42 | ````{py:exception} UniqueError() 43 | :canonical: autodoc2.db.UniqueError 44 | 45 | Bases: {py:obj}`KeyError` 46 | 47 | ```{autodoc2-docstring} autodoc2.db.UniqueError 48 | ``` 49 | 50 | ```{rubric} Initialization 51 | ``` 52 | 53 | ```{autodoc2-docstring} autodoc2.db.UniqueError.__init__ 54 | ``` 55 | 56 | ```` 57 | 58 | `````{py:class} Database 59 | :canonical: autodoc2.db.Database 60 | 61 | Bases: {py:obj}`typing.Protocol` 62 | 63 | ```{autodoc2-docstring} autodoc2.db.Database 64 | ``` 65 | 66 | ````{py:method} add(item: autodoc2.utils.ItemData) -> None 67 | :canonical: autodoc2.db.Database.add 68 | 69 | ```{autodoc2-docstring} autodoc2.db.Database.add 70 | ``` 71 | 72 | ```` 73 | 74 | ````{py:method} remove(full_name: str, descendants: bool) -> None 75 | :canonical: autodoc2.db.Database.remove 76 | 77 | ```{autodoc2-docstring} autodoc2.db.Database.remove 78 | ``` 79 | 80 | ```` 81 | 82 | ````{py:method} __contains__(full_name: str) -> bool 83 | :canonical: autodoc2.db.Database.__contains__ 84 | 85 | ```{autodoc2-docstring} autodoc2.db.Database.__contains__ 86 | ``` 87 | 88 | ```` 89 | 90 | ````{py:method} get_item(full_name: str) -> autodoc2.utils.ItemData | None 91 | :canonical: autodoc2.db.Database.get_item 92 | 93 | ```{autodoc2-docstring} autodoc2.db.Database.get_item 94 | ``` 95 | 96 | ```` 97 | 98 | ````{py:method} get_items_like(full_name: str) -> typing.Iterable[autodoc2.utils.ItemData] 99 | :canonical: autodoc2.db.Database.get_items_like 100 | 101 | ```{autodoc2-docstring} autodoc2.db.Database.get_items_like 102 | ``` 103 | 104 | ```` 105 | 106 | ````{py:method} get_type(full_name: str) -> None | str 107 | :canonical: autodoc2.db.Database.get_type 108 | 109 | ```{autodoc2-docstring} autodoc2.db.Database.get_type 110 | ``` 111 | 112 | ```` 113 | 114 | ````{py:method} get_by_type(type_: str) -> typing.Iterable[autodoc2.utils.ItemData] 115 | :canonical: autodoc2.db.Database.get_by_type 116 | 117 | ```{autodoc2-docstring} autodoc2.db.Database.get_by_type 118 | ``` 119 | 120 | ```` 121 | 122 | ````{py:method} get_overloads(full_name: str) -> typing.Iterable[autodoc2.utils.ItemData] 123 | :canonical: autodoc2.db.Database.get_overloads 124 | 125 | ```{autodoc2-docstring} autodoc2.db.Database.get_overloads 126 | ``` 127 | 128 | ```` 129 | 130 | ````{py:method} get_children(full_name: str, types: None | set[str] = None, *, sort_name: bool = False) -> typing.Iterable[autodoc2.utils.ItemData] 131 | :canonical: autodoc2.db.Database.get_children 132 | 133 | ```{autodoc2-docstring} autodoc2.db.Database.get_children 134 | ``` 135 | 136 | ```` 137 | 138 | ````{py:method} get_children_names(full_name: str, types: None | set[str] = None, *, sort_name: bool = False) -> typing.Iterable[str] 139 | :canonical: autodoc2.db.Database.get_children_names 140 | 141 | ```{autodoc2-docstring} autodoc2.db.Database.get_children_names 142 | ``` 143 | 144 | ```` 145 | 146 | ````{py:method} get_ancestors(full_name: str, include_self: bool) -> typing.Iterable[autodoc2.utils.ItemData | None] 147 | :canonical: autodoc2.db.Database.get_ancestors 148 | 149 | ```{autodoc2-docstring} autodoc2.db.Database.get_ancestors 150 | ``` 151 | 152 | ```` 153 | 154 | ````` 155 | 156 | ````{py:data} _LIKE_REGEX 157 | :canonical: autodoc2.db._LIKE_REGEX 158 | :value: > 159 | None 160 | 161 | ```{autodoc2-docstring} autodoc2.db._LIKE_REGEX 162 | ``` 163 | 164 | ```` 165 | 166 | `````{py:class} InMemoryDb() 167 | :canonical: autodoc2.db.InMemoryDb 168 | 169 | Bases: {py:obj}`autodoc2.db.Database` 170 | 171 | ```{autodoc2-docstring} autodoc2.db.InMemoryDb 172 | ``` 173 | 174 | ```{rubric} Initialization 175 | ``` 176 | 177 | ```{autodoc2-docstring} autodoc2.db.InMemoryDb.__init__ 178 | ``` 179 | 180 | ````{py:method} add(item: autodoc2.utils.ItemData) -> None 181 | :canonical: autodoc2.db.InMemoryDb.add 182 | 183 | ```` 184 | 185 | ````{py:method} remove(full_name: str, descendants: bool) -> None 186 | :canonical: autodoc2.db.InMemoryDb.remove 187 | 188 | ```` 189 | 190 | ````{py:method} __contains__(full_name: str) -> bool 191 | :canonical: autodoc2.db.InMemoryDb.__contains__ 192 | 193 | ```` 194 | 195 | ````{py:method} get_item(full_name: str) -> autodoc2.utils.ItemData | None 196 | :canonical: autodoc2.db.InMemoryDb.get_item 197 | 198 | ```` 199 | 200 | ````{py:method} get_items_like(full_name: str) -> typing.Iterable[autodoc2.utils.ItemData] 201 | :canonical: autodoc2.db.InMemoryDb.get_items_like 202 | 203 | ```` 204 | 205 | ````{py:method} get_type(full_name: str) -> None | str 206 | :canonical: autodoc2.db.InMemoryDb.get_type 207 | 208 | ```` 209 | 210 | ````{py:method} get_by_type(type_: str) -> typing.Iterable[autodoc2.utils.ItemData] 211 | :canonical: autodoc2.db.InMemoryDb.get_by_type 212 | 213 | ```` 214 | 215 | ````{py:method} get_overloads(full_name: str) -> typing.Iterable[autodoc2.utils.ItemData] 216 | :canonical: autodoc2.db.InMemoryDb.get_overloads 217 | 218 | ```` 219 | 220 | ````{py:method} get_children(full_name: str, types: None | set[str] = None, *, sort_name: bool = False) -> typing.Iterable[autodoc2.utils.ItemData] 221 | :canonical: autodoc2.db.InMemoryDb.get_children 222 | 223 | ```` 224 | 225 | ````{py:method} get_children_names(full_name: str, types: None | set[str] = None, *, sort_name: bool = False) -> typing.Iterable[str] 226 | :canonical: autodoc2.db.InMemoryDb.get_children_names 227 | 228 | ```` 229 | 230 | ````{py:method} get_ancestors(full_name: str, include_self: bool) -> typing.Iterable[autodoc2.utils.ItemData | None] 231 | :canonical: autodoc2.db.InMemoryDb.get_ancestors 232 | 233 | ```` 234 | 235 | ````{py:method} write(stream: typing.TextIO) -> None 236 | :canonical: autodoc2.db.InMemoryDb.write 237 | 238 | ```{autodoc2-docstring} autodoc2.db.InMemoryDb.write 239 | ``` 240 | 241 | ```` 242 | 243 | ````{py:method} read(stream: typing.TextIO) -> autodoc2.db.InMemoryDb 244 | :canonical: autodoc2.db.InMemoryDb.read 245 | :classmethod: 246 | 247 | ```{autodoc2-docstring} autodoc2.db.InMemoryDb.read 248 | ``` 249 | 250 | ```` 251 | 252 | ````` 253 | -------------------------------------------------------------------------------- /docs/apidocs/autodoc2/autodoc2.render.base.rst: -------------------------------------------------------------------------------- 1 | :py:mod:`autodoc2.render.base` 2 | ============================== 3 | 4 | .. py:module:: autodoc2.render.base 5 | 6 | .. autodoc2-docstring:: autodoc2.render.base 7 | :allowtitles: 8 | 9 | Module Contents 10 | --------------- 11 | 12 | Classes 13 | ~~~~~~~ 14 | 15 | .. list-table:: 16 | :class: autosummary longtable 17 | :align: left 18 | 19 | * - :py:obj:`RendererBase ` 20 | - .. autodoc2-docstring:: autodoc2.render.base.RendererBase 21 | :summary: 22 | 23 | API 24 | ~~~ 25 | 26 | .. py:class:: RendererBase(db: autodoc2.db.Database, config: autodoc2.config.Config, *, warn: typing.Callable[[str, autodoc2.utils.WarningSubtypes], None] | None = None, all_resolver: autodoc2.resolve_all.AllResolver | None = None, standalone: bool = True) 27 | :canonical: autodoc2.render.base.RendererBase 28 | 29 | Bases: :py:obj:`abc.ABC` 30 | 31 | .. autodoc2-docstring:: autodoc2.render.base.RendererBase 32 | 33 | .. rubric:: Initialization 34 | 35 | .. autodoc2-docstring:: autodoc2.render.base.RendererBase.__init__ 36 | 37 | .. py:attribute:: EXTENSION 38 | :canonical: autodoc2.render.base.RendererBase.EXTENSION 39 | :type: typing.ClassVar[str] 40 | :value: '.txt' 41 | 42 | .. autodoc2-docstring:: autodoc2.render.base.RendererBase.EXTENSION 43 | 44 | .. py:attribute:: _is_hidden_cache 45 | :canonical: autodoc2.render.base.RendererBase._is_hidden_cache 46 | :type: collections.OrderedDict[str, bool] 47 | :value: None 48 | 49 | .. autodoc2-docstring:: autodoc2.render.base.RendererBase._is_hidden_cache 50 | 51 | .. py:property:: config 52 | :canonical: autodoc2.render.base.RendererBase.config 53 | :type: autodoc2.config.Config 54 | 55 | .. autodoc2-docstring:: autodoc2.render.base.RendererBase.config 56 | 57 | .. py:property:: standalone 58 | :canonical: autodoc2.render.base.RendererBase.standalone 59 | :type: bool 60 | 61 | .. autodoc2-docstring:: autodoc2.render.base.RendererBase.standalone 62 | 63 | .. py:method:: warn(msg: str, type_: autodoc2.utils.WarningSubtypes = WarningSubtypes.RENDER_ERROR) -> None 64 | :canonical: autodoc2.render.base.RendererBase.warn 65 | 66 | .. autodoc2-docstring:: autodoc2.render.base.RendererBase.warn 67 | 68 | .. py:method:: get_item(full_name: str) -> autodoc2.utils.ItemData | None 69 | :canonical: autodoc2.render.base.RendererBase.get_item 70 | 71 | .. autodoc2-docstring:: autodoc2.render.base.RendererBase.get_item 72 | 73 | .. py:method:: get_children(item: autodoc2.utils.ItemData, types: None | set[str] = None, *, omit_hidden: bool = True) -> typing.Iterable[autodoc2.utils.ItemData] 74 | :canonical: autodoc2.render.base.RendererBase.get_children 75 | 76 | .. autodoc2-docstring:: autodoc2.render.base.RendererBase.get_children 77 | 78 | .. py:method:: is_hidden(item: autodoc2.utils.ItemData) -> bool 79 | :canonical: autodoc2.render.base.RendererBase.is_hidden 80 | 81 | .. autodoc2-docstring:: autodoc2.render.base.RendererBase.is_hidden 82 | 83 | .. py:method:: is_module_deprecated(item: autodoc2.utils.ItemData) -> bool 84 | :canonical: autodoc2.render.base.RendererBase.is_module_deprecated 85 | 86 | .. autodoc2-docstring:: autodoc2.render.base.RendererBase.is_module_deprecated 87 | 88 | .. py:method:: no_index(item: autodoc2.utils.ItemData) -> bool 89 | :canonical: autodoc2.render.base.RendererBase.no_index 90 | 91 | .. autodoc2-docstring:: autodoc2.render.base.RendererBase.no_index 92 | 93 | .. py:method:: show_module_summary(item: autodoc2.utils.ItemData) -> bool 94 | :canonical: autodoc2.render.base.RendererBase.show_module_summary 95 | 96 | .. autodoc2-docstring:: autodoc2.render.base.RendererBase.show_module_summary 97 | 98 | .. py:method:: show_class_inheritance(item: autodoc2.utils.ItemData) -> bool 99 | :canonical: autodoc2.render.base.RendererBase.show_class_inheritance 100 | 101 | .. autodoc2-docstring:: autodoc2.render.base.RendererBase.show_class_inheritance 102 | 103 | .. py:method:: show_annotations(item: autodoc2.utils.ItemData) -> bool 104 | :canonical: autodoc2.render.base.RendererBase.show_annotations 105 | 106 | .. autodoc2-docstring:: autodoc2.render.base.RendererBase.show_annotations 107 | 108 | .. py:method:: show_docstring(item: autodoc2.utils.ItemData) -> bool 109 | :canonical: autodoc2.render.base.RendererBase.show_docstring 110 | 111 | .. autodoc2-docstring:: autodoc2.render.base.RendererBase.show_docstring 112 | 113 | .. py:method:: render_item(full_name: str) -> typing.Iterable[str] 114 | :canonical: autodoc2.render.base.RendererBase.render_item 115 | :abstractmethod: 116 | 117 | .. autodoc2-docstring:: autodoc2.render.base.RendererBase.render_item 118 | 119 | .. py:method:: format_args(args_info: autodoc2.utils.ARGS_TYPE, include_annotations: bool = True, ignore_self: None | str = None) -> str 120 | :canonical: autodoc2.render.base.RendererBase.format_args 121 | 122 | .. autodoc2-docstring:: autodoc2.render.base.RendererBase.format_args 123 | 124 | .. py:method:: format_annotation(annotation: None | str) -> str 125 | :canonical: autodoc2.render.base.RendererBase.format_annotation 126 | 127 | .. autodoc2-docstring:: autodoc2.render.base.RendererBase.format_annotation 128 | 129 | .. py:method:: format_base(base: None | str) -> str 130 | :canonical: autodoc2.render.base.RendererBase.format_base 131 | 132 | .. autodoc2-docstring:: autodoc2.render.base.RendererBase.format_base 133 | 134 | .. py:method:: get_doc_parser(full_name: str) -> str 135 | :canonical: autodoc2.render.base.RendererBase.get_doc_parser 136 | 137 | .. autodoc2-docstring:: autodoc2.render.base.RendererBase.get_doc_parser 138 | 139 | .. py:method:: generate_summary(objects: list[autodoc2.utils.ItemData], alias: dict[str, str] | None = None) -> typing.Iterable[str] 140 | :canonical: autodoc2.render.base.RendererBase.generate_summary 141 | :abstractmethod: 142 | 143 | .. autodoc2-docstring:: autodoc2.render.base.RendererBase.generate_summary 144 | -------------------------------------------------------------------------------- /docs/apidocs/autodoc2/autodoc2.render.myst_.rst: -------------------------------------------------------------------------------- 1 | :py:mod:`autodoc2.render.myst_` 2 | =============================== 3 | 4 | .. py:module:: autodoc2.render.myst_ 5 | 6 | .. autodoc2-docstring:: autodoc2.render.myst_ 7 | :allowtitles: 8 | 9 | Module Contents 10 | --------------- 11 | 12 | Classes 13 | ~~~~~~~ 14 | 15 | .. list-table:: 16 | :class: autosummary longtable 17 | :align: left 18 | 19 | * - :py:obj:`MystRenderer ` 20 | - .. autodoc2-docstring:: autodoc2.render.myst_.MystRenderer 21 | :summary: 22 | 23 | Data 24 | ~~~~ 25 | 26 | .. list-table:: 27 | :class: autosummary longtable 28 | :align: left 29 | 30 | * - :py:obj:`_RE_DELIMS ` 31 | - .. autodoc2-docstring:: autodoc2.render.myst_._RE_DELIMS 32 | :summary: 33 | 34 | API 35 | ~~~ 36 | 37 | .. py:data:: _RE_DELIMS 38 | :canonical: autodoc2.render.myst_._RE_DELIMS 39 | :value: None 40 | 41 | .. autodoc2-docstring:: autodoc2.render.myst_._RE_DELIMS 42 | 43 | .. py:class:: MystRenderer(db: autodoc2.db.Database, config: autodoc2.config.Config, *, warn: typing.Callable[[str, autodoc2.utils.WarningSubtypes], None] | None = None, all_resolver: autodoc2.resolve_all.AllResolver | None = None, standalone: bool = True) 44 | :canonical: autodoc2.render.myst_.MystRenderer 45 | 46 | Bases: :py:obj:`autodoc2.render.base.RendererBase` 47 | 48 | .. autodoc2-docstring:: autodoc2.render.myst_.MystRenderer 49 | 50 | .. rubric:: Initialization 51 | 52 | .. autodoc2-docstring:: autodoc2.render.myst_.MystRenderer.__init__ 53 | 54 | .. py:attribute:: EXTENSION 55 | :canonical: autodoc2.render.myst_.MystRenderer.EXTENSION 56 | :value: '.md' 57 | 58 | .. autodoc2-docstring:: autodoc2.render.myst_.MystRenderer.EXTENSION 59 | 60 | .. py:method:: render_item(full_name: str) -> typing.Iterable[str] 61 | :canonical: autodoc2.render.myst_.MystRenderer.render_item 62 | 63 | .. py:method:: generate_summary(objects: list[autodoc2.utils.ItemData], alias: dict[str, str] | None = None) -> typing.Iterable[str] 64 | :canonical: autodoc2.render.myst_.MystRenderer.generate_summary 65 | 66 | .. py:method:: enclosing_backticks(text: str) -> str 67 | :canonical: autodoc2.render.myst_.MystRenderer.enclosing_backticks 68 | :staticmethod: 69 | 70 | .. autodoc2-docstring:: autodoc2.render.myst_.MystRenderer.enclosing_backticks 71 | 72 | .. py:method:: render_package(item: autodoc2.utils.ItemData) -> typing.Iterable[str] 73 | :canonical: autodoc2.render.myst_.MystRenderer.render_package 74 | 75 | .. autodoc2-docstring:: autodoc2.render.myst_.MystRenderer.render_package 76 | 77 | .. py:method:: render_module(item: autodoc2.utils.ItemData) -> typing.Iterable[str] 78 | :canonical: autodoc2.render.myst_.MystRenderer.render_module 79 | 80 | .. autodoc2-docstring:: autodoc2.render.myst_.MystRenderer.render_module 81 | 82 | .. py:method:: render_function(item: autodoc2.utils.ItemData) -> typing.Iterable[str] 83 | :canonical: autodoc2.render.myst_.MystRenderer.render_function 84 | 85 | .. autodoc2-docstring:: autodoc2.render.myst_.MystRenderer.render_function 86 | 87 | .. py:method:: render_exception(item: autodoc2.utils.ItemData) -> typing.Iterable[str] 88 | :canonical: autodoc2.render.myst_.MystRenderer.render_exception 89 | 90 | .. autodoc2-docstring:: autodoc2.render.myst_.MystRenderer.render_exception 91 | 92 | .. py:method:: render_class(item: autodoc2.utils.ItemData) -> typing.Iterable[str] 93 | :canonical: autodoc2.render.myst_.MystRenderer.render_class 94 | 95 | .. autodoc2-docstring:: autodoc2.render.myst_.MystRenderer.render_class 96 | 97 | .. py:method:: render_property(item: autodoc2.utils.ItemData) -> typing.Iterable[str] 98 | :canonical: autodoc2.render.myst_.MystRenderer.render_property 99 | 100 | .. autodoc2-docstring:: autodoc2.render.myst_.MystRenderer.render_property 101 | 102 | .. py:method:: render_method(item: autodoc2.utils.ItemData) -> typing.Iterable[str] 103 | :canonical: autodoc2.render.myst_.MystRenderer.render_method 104 | 105 | .. autodoc2-docstring:: autodoc2.render.myst_.MystRenderer.render_method 106 | 107 | .. py:method:: render_attribute(item: autodoc2.utils.ItemData) -> typing.Iterable[str] 108 | :canonical: autodoc2.render.myst_.MystRenderer.render_attribute 109 | 110 | .. autodoc2-docstring:: autodoc2.render.myst_.MystRenderer.render_attribute 111 | 112 | .. py:method:: render_data(item: autodoc2.utils.ItemData) -> typing.Iterable[str] 113 | :canonical: autodoc2.render.myst_.MystRenderer.render_data 114 | 115 | .. autodoc2-docstring:: autodoc2.render.myst_.MystRenderer.render_data 116 | 117 | .. py:method:: _reformat_cls_base_myst(value: str) -> str 118 | :canonical: autodoc2.render.myst_.MystRenderer._reformat_cls_base_myst 119 | 120 | .. autodoc2-docstring:: autodoc2.render.myst_.MystRenderer._reformat_cls_base_myst 121 | -------------------------------------------------------------------------------- /docs/apidocs/autodoc2/autodoc2.render.rst: -------------------------------------------------------------------------------- 1 | :py:mod:`autodoc2.render` 2 | ========================= 3 | 4 | .. py:module:: autodoc2.render 5 | 6 | .. autodoc2-docstring:: autodoc2.render 7 | :allowtitles: 8 | 9 | Submodules 10 | ---------- 11 | 12 | .. toctree:: 13 | :titlesonly: 14 | :maxdepth: 1 15 | 16 | autodoc2.render.myst_ 17 | autodoc2.render.rst_ 18 | autodoc2.render.base 19 | -------------------------------------------------------------------------------- /docs/apidocs/autodoc2/autodoc2.render.rst_.rst: -------------------------------------------------------------------------------- 1 | :py:mod:`autodoc2.render.rst_` 2 | ============================== 3 | 4 | .. py:module:: autodoc2.render.rst_ 5 | 6 | .. autodoc2-docstring:: autodoc2.render.rst_ 7 | :allowtitles: 8 | 9 | Module Contents 10 | --------------- 11 | 12 | Classes 13 | ~~~~~~~ 14 | 15 | .. list-table:: 16 | :class: autosummary longtable 17 | :align: left 18 | 19 | * - :py:obj:`RstRenderer ` 20 | - .. autodoc2-docstring:: autodoc2.render.rst_.RstRenderer 21 | :summary: 22 | 23 | Data 24 | ~~~~ 25 | 26 | .. list-table:: 27 | :class: autosummary longtable 28 | :align: left 29 | 30 | * - :py:obj:`_RE_DELIMS ` 31 | - .. autodoc2-docstring:: autodoc2.render.rst_._RE_DELIMS 32 | :summary: 33 | 34 | API 35 | ~~~ 36 | 37 | .. py:data:: _RE_DELIMS 38 | :canonical: autodoc2.render.rst_._RE_DELIMS 39 | :value: None 40 | 41 | .. autodoc2-docstring:: autodoc2.render.rst_._RE_DELIMS 42 | 43 | .. py:class:: RstRenderer(db: autodoc2.db.Database, config: autodoc2.config.Config, *, warn: typing.Callable[[str, autodoc2.utils.WarningSubtypes], None] | None = None, all_resolver: autodoc2.resolve_all.AllResolver | None = None, standalone: bool = True) 44 | :canonical: autodoc2.render.rst_.RstRenderer 45 | 46 | Bases: :py:obj:`autodoc2.render.base.RendererBase` 47 | 48 | .. autodoc2-docstring:: autodoc2.render.rst_.RstRenderer 49 | 50 | .. rubric:: Initialization 51 | 52 | .. autodoc2-docstring:: autodoc2.render.rst_.RstRenderer.__init__ 53 | 54 | .. py:attribute:: EXTENSION 55 | :canonical: autodoc2.render.rst_.RstRenderer.EXTENSION 56 | :value: '.rst' 57 | 58 | .. autodoc2-docstring:: autodoc2.render.rst_.RstRenderer.EXTENSION 59 | 60 | .. py:method:: render_item(full_name: str) -> typing.Iterable[str] 61 | :canonical: autodoc2.render.rst_.RstRenderer.render_item 62 | 63 | .. py:method:: generate_summary(objects: list[autodoc2.utils.ItemData], alias: dict[str, str] | None = None) -> typing.Iterable[str] 64 | :canonical: autodoc2.render.rst_.RstRenderer.generate_summary 65 | 66 | .. py:method:: render_package(item: autodoc2.utils.ItemData) -> typing.Iterable[str] 67 | :canonical: autodoc2.render.rst_.RstRenderer.render_package 68 | 69 | .. autodoc2-docstring:: autodoc2.render.rst_.RstRenderer.render_package 70 | 71 | .. py:method:: render_module(item: autodoc2.utils.ItemData) -> typing.Iterable[str] 72 | :canonical: autodoc2.render.rst_.RstRenderer.render_module 73 | 74 | .. autodoc2-docstring:: autodoc2.render.rst_.RstRenderer.render_module 75 | 76 | .. py:method:: render_function(item: autodoc2.utils.ItemData) -> typing.Iterable[str] 77 | :canonical: autodoc2.render.rst_.RstRenderer.render_function 78 | 79 | .. autodoc2-docstring:: autodoc2.render.rst_.RstRenderer.render_function 80 | 81 | .. py:method:: render_exception(item: autodoc2.utils.ItemData) -> typing.Iterable[str] 82 | :canonical: autodoc2.render.rst_.RstRenderer.render_exception 83 | 84 | .. autodoc2-docstring:: autodoc2.render.rst_.RstRenderer.render_exception 85 | 86 | .. py:method:: render_class(item: autodoc2.utils.ItemData) -> typing.Iterable[str] 87 | :canonical: autodoc2.render.rst_.RstRenderer.render_class 88 | 89 | .. autodoc2-docstring:: autodoc2.render.rst_.RstRenderer.render_class 90 | 91 | .. py:method:: render_property(item: autodoc2.utils.ItemData) -> typing.Iterable[str] 92 | :canonical: autodoc2.render.rst_.RstRenderer.render_property 93 | 94 | .. autodoc2-docstring:: autodoc2.render.rst_.RstRenderer.render_property 95 | 96 | .. py:method:: render_method(item: autodoc2.utils.ItemData) -> typing.Iterable[str] 97 | :canonical: autodoc2.render.rst_.RstRenderer.render_method 98 | 99 | .. autodoc2-docstring:: autodoc2.render.rst_.RstRenderer.render_method 100 | 101 | .. py:method:: render_attribute(item: autodoc2.utils.ItemData) -> typing.Iterable[str] 102 | :canonical: autodoc2.render.rst_.RstRenderer.render_attribute 103 | 104 | .. autodoc2-docstring:: autodoc2.render.rst_.RstRenderer.render_attribute 105 | 106 | .. py:method:: render_data(item: autodoc2.utils.ItemData) -> typing.Iterable[str] 107 | :canonical: autodoc2.render.rst_.RstRenderer.render_data 108 | 109 | .. autodoc2-docstring:: autodoc2.render.rst_.RstRenderer.render_data 110 | 111 | .. py:method:: _reformat_cls_base_rst(value: str) -> str 112 | :canonical: autodoc2.render.rst_.RstRenderer._reformat_cls_base_rst 113 | 114 | .. autodoc2-docstring:: autodoc2.render.rst_.RstRenderer._reformat_cls_base_rst 115 | -------------------------------------------------------------------------------- /docs/apidocs/autodoc2/autodoc2.resolve_all.rst: -------------------------------------------------------------------------------- 1 | :py:mod:`autodoc2.resolve_all` 2 | ============================== 3 | 4 | .. py:module:: autodoc2.resolve_all 5 | 6 | .. autodoc2-docstring:: autodoc2.resolve_all 7 | :allowtitles: 8 | 9 | Module Contents 10 | --------------- 11 | 12 | Classes 13 | ~~~~~~~ 14 | 15 | .. list-table:: 16 | :class: autosummary longtable 17 | :align: left 18 | 19 | * - :py:obj:`AllResolveResult ` 20 | - 21 | * - :py:obj:`AllResolver ` 22 | - .. autodoc2-docstring:: autodoc2.resolve_all.AllResolver 23 | :summary: 24 | 25 | API 26 | ~~~ 27 | 28 | .. py:exception:: AllResolutionError() 29 | :canonical: autodoc2.resolve_all.AllResolutionError 30 | 31 | Bases: :py:obj:`Exception` 32 | 33 | .. autodoc2-docstring:: autodoc2.resolve_all.AllResolutionError 34 | 35 | .. rubric:: Initialization 36 | 37 | .. autodoc2-docstring:: autodoc2.resolve_all.AllResolutionError.__init__ 38 | 39 | .. py:exception:: ObjectMissingError() 40 | :canonical: autodoc2.resolve_all.ObjectMissingError 41 | 42 | Bases: :py:obj:`autodoc2.resolve_all.AllResolutionError` 43 | 44 | .. autodoc2-docstring:: autodoc2.resolve_all.ObjectMissingError 45 | 46 | .. rubric:: Initialization 47 | 48 | .. autodoc2-docstring:: autodoc2.resolve_all.ObjectMissingError.__init__ 49 | 50 | .. py:exception:: CircularImportError() 51 | :canonical: autodoc2.resolve_all.CircularImportError 52 | 53 | Bases: :py:obj:`autodoc2.resolve_all.AllResolutionError` 54 | 55 | .. autodoc2-docstring:: autodoc2.resolve_all.CircularImportError 56 | 57 | .. rubric:: Initialization 58 | 59 | .. autodoc2-docstring:: autodoc2.resolve_all.CircularImportError.__init__ 60 | 61 | .. py:exception:: NoAllError() 62 | :canonical: autodoc2.resolve_all.NoAllError 63 | 64 | Bases: :py:obj:`autodoc2.resolve_all.AllResolutionError` 65 | 66 | .. autodoc2-docstring:: autodoc2.resolve_all.NoAllError 67 | 68 | .. rubric:: Initialization 69 | 70 | .. autodoc2-docstring:: autodoc2.resolve_all.NoAllError.__init__ 71 | 72 | .. py:class:: AllResolveResult() 73 | :canonical: autodoc2.resolve_all.AllResolveResult 74 | 75 | Bases: :py:obj:`typing.TypedDict` 76 | 77 | .. py:attribute:: resolved 78 | :canonical: autodoc2.resolve_all.AllResolveResult.resolved 79 | :type: dict[str, str] 80 | :value: None 81 | 82 | .. autodoc2-docstring:: autodoc2.resolve_all.AllResolveResult.resolved 83 | 84 | .. py:attribute:: errors 85 | :canonical: autodoc2.resolve_all.AllResolveResult.errors 86 | :type: list[tuple[str, str]] 87 | :value: None 88 | 89 | .. autodoc2-docstring:: autodoc2.resolve_all.AllResolveResult.errors 90 | 91 | .. py:class:: AllResolver(db: autodoc2.db.Database, warn_func: typing.Callable[[str], None] | None = None) 92 | :canonical: autodoc2.resolve_all.AllResolver 93 | 94 | .. autodoc2-docstring:: autodoc2.resolve_all.AllResolver 95 | 96 | .. rubric:: Initialization 97 | 98 | .. autodoc2-docstring:: autodoc2.resolve_all.AllResolver.__init__ 99 | 100 | .. py:method:: clear_cache() -> None 101 | :canonical: autodoc2.resolve_all.AllResolver.clear_cache 102 | 103 | .. autodoc2-docstring:: autodoc2.resolve_all.AllResolver.clear_cache 104 | 105 | .. py:method:: get_resolved_all(full_name: str, _breadcrumbs: tuple[str, ...] = ()) -> autodoc2.resolve_all.AllResolveResult 106 | :canonical: autodoc2.resolve_all.AllResolver.get_resolved_all 107 | 108 | .. autodoc2-docstring:: autodoc2.resolve_all.AllResolver.get_resolved_all 109 | 110 | .. py:method:: get_name(name: str) -> str | None 111 | :canonical: autodoc2.resolve_all.AllResolver.get_name 112 | 113 | .. autodoc2-docstring:: autodoc2.resolve_all.AllResolver.get_name 114 | -------------------------------------------------------------------------------- /docs/apidocs/autodoc2/autodoc2.rst: -------------------------------------------------------------------------------- 1 | :py:mod:`autodoc2` 2 | ================== 3 | 4 | .. py:module:: autodoc2 5 | 6 | .. autodoc2-docstring:: autodoc2 7 | :allowtitles: 8 | 9 | Subpackages 10 | ----------- 11 | 12 | .. toctree:: 13 | :titlesonly: 14 | :maxdepth: 3 15 | 16 | autodoc2.render 17 | autodoc2.sphinx 18 | 19 | Submodules 20 | ---------- 21 | 22 | .. toctree:: 23 | :titlesonly: 24 | :maxdepth: 1 25 | 26 | autodoc2.db 27 | autodoc2.config 28 | autodoc2.analysis 29 | autodoc2.cli 30 | autodoc2.utils 31 | autodoc2.resolve_all 32 | autodoc2.astroid_utils 33 | 34 | Package Contents 35 | ---------------- 36 | 37 | Functions 38 | ~~~~~~~~~ 39 | 40 | .. list-table:: 41 | :class: autosummary longtable 42 | :align: left 43 | 44 | * - :py:obj:`setup ` 45 | - .. autodoc2-docstring:: autodoc2.setup 46 | :summary: 47 | 48 | Data 49 | ~~~~ 50 | 51 | .. list-table:: 52 | :class: autosummary longtable 53 | :align: left 54 | 55 | * - :py:obj:`__version__ ` 56 | - .. autodoc2-docstring:: autodoc2.__version__ 57 | :summary: 58 | 59 | API 60 | ~~~ 61 | 62 | .. py:data:: __version__ 63 | :canonical: autodoc2.__version__ 64 | :value: '0.4.2' 65 | 66 | .. autodoc2-docstring:: autodoc2.__version__ 67 | 68 | .. py:function:: setup(app) 69 | :canonical: autodoc2.setup 70 | 71 | .. autodoc2-docstring:: autodoc2.setup 72 | -------------------------------------------------------------------------------- /docs/apidocs/autodoc2/autodoc2.sphinx.autodoc.rst: -------------------------------------------------------------------------------- 1 | :py:mod:`autodoc2.sphinx.autodoc` 2 | ================================= 3 | 4 | .. py:module:: autodoc2.sphinx.autodoc 5 | 6 | .. autodoc2-docstring:: autodoc2.sphinx.autodoc 7 | :allowtitles: 8 | 9 | Module Contents 10 | --------------- 11 | 12 | Classes 13 | ~~~~~~~ 14 | 15 | .. list-table:: 16 | :class: autosummary longtable 17 | :align: left 18 | 19 | * - :py:obj:`AutodocObject ` 20 | - .. autodoc2-docstring:: autodoc2.sphinx.autodoc.AutodocObject 21 | :summary: 22 | 23 | Functions 24 | ~~~~~~~~~ 25 | 26 | .. list-table:: 27 | :class: autosummary longtable 28 | :align: left 29 | 30 | * - :py:obj:`_set_parents ` 31 | - .. autodoc2-docstring:: autodoc2.sphinx.autodoc._set_parents 32 | :summary: 33 | 34 | API 35 | ~~~ 36 | 37 | .. py:class:: AutodocObject(name, arguments, options, content, lineno, content_offset, block_text, state, state_machine) 38 | :canonical: autodoc2.sphinx.autodoc.AutodocObject 39 | 40 | Bases: :py:obj:`sphinx.util.docutils.SphinxDirective` 41 | 42 | .. autodoc2-docstring:: autodoc2.sphinx.autodoc.AutodocObject 43 | 44 | .. rubric:: Initialization 45 | 46 | .. autodoc2-docstring:: autodoc2.sphinx.autodoc.AutodocObject.__init__ 47 | 48 | .. py:attribute:: required_arguments 49 | :canonical: autodoc2.sphinx.autodoc.AutodocObject.required_arguments 50 | :value: 1 51 | 52 | .. autodoc2-docstring:: autodoc2.sphinx.autodoc.AutodocObject.required_arguments 53 | 54 | .. py:attribute:: final_argument_whitespace 55 | :canonical: autodoc2.sphinx.autodoc.AutodocObject.final_argument_whitespace 56 | :value: False 57 | 58 | .. autodoc2-docstring:: autodoc2.sphinx.autodoc.AutodocObject.final_argument_whitespace 59 | 60 | .. py:attribute:: has_content 61 | :canonical: autodoc2.sphinx.autodoc.AutodocObject.has_content 62 | :value: True 63 | 64 | .. autodoc2-docstring:: autodoc2.sphinx.autodoc.AutodocObject.has_content 65 | 66 | .. py:attribute:: option_spec 67 | :canonical: autodoc2.sphinx.autodoc.AutodocObject.option_spec 68 | :type: typing.ClassVar[dict[str, typing.Any]] 69 | :value: None 70 | 71 | .. autodoc2-docstring:: autodoc2.sphinx.autodoc.AutodocObject.option_spec 72 | 73 | .. py:method:: run() -> list[docutils.nodes.Node] 74 | :canonical: autodoc2.sphinx.autodoc.AutodocObject.run 75 | 76 | .. autodoc2-docstring:: autodoc2.sphinx.autodoc.AutodocObject.run 77 | 78 | .. py:function:: _set_parents(env: sphinx.environment.BuildEnvironment, mod: autodoc2.utils.ItemData, klass: autodoc2.utils.ItemData | None) -> typing.Generator[None, None, None] 79 | :canonical: autodoc2.sphinx.autodoc._set_parents 80 | 81 | .. autodoc2-docstring:: autodoc2.sphinx.autodoc._set_parents 82 | -------------------------------------------------------------------------------- /docs/apidocs/autodoc2/autodoc2.sphinx.docstring.rst: -------------------------------------------------------------------------------- 1 | :py:mod:`autodoc2.sphinx.docstring` 2 | =================================== 3 | 4 | .. py:module:: autodoc2.sphinx.docstring 5 | 6 | .. autodoc2-docstring:: autodoc2.sphinx.docstring 7 | :allowtitles: 8 | 9 | Module Contents 10 | --------------- 11 | 12 | Classes 13 | ~~~~~~~ 14 | 15 | .. list-table:: 16 | :class: autosummary longtable 17 | :align: left 18 | 19 | * - :py:obj:`DocstringRenderer ` 20 | - .. autodoc2-docstring:: autodoc2.sphinx.docstring.DocstringRenderer 21 | :summary: 22 | 23 | Functions 24 | ~~~~~~~~~ 25 | 26 | .. list-table:: 27 | :class: autosummary longtable 28 | :align: left 29 | 30 | * - :py:obj:`parser_options ` 31 | - .. autodoc2-docstring:: autodoc2.sphinx.docstring.parser_options 32 | :summary: 33 | * - :py:obj:`summary_option ` 34 | - .. autodoc2-docstring:: autodoc2.sphinx.docstring.summary_option 35 | :summary: 36 | * - :py:obj:`parsing_context ` 37 | - .. autodoc2-docstring:: autodoc2.sphinx.docstring.parsing_context 38 | :summary: 39 | * - :py:obj:`change_source ` 40 | - .. autodoc2-docstring:: autodoc2.sphinx.docstring.change_source 41 | :summary: 42 | * - :py:obj:`_example ` 43 | - .. autodoc2-docstring:: autodoc2.sphinx.docstring._example 44 | :parser: myst 45 | :summary: 46 | 47 | API 48 | ~~~ 49 | 50 | .. py:function:: parser_options(argument: str) -> docutils.parsers.Parser | None 51 | :canonical: autodoc2.sphinx.docstring.parser_options 52 | 53 | .. autodoc2-docstring:: autodoc2.sphinx.docstring.parser_options 54 | 55 | .. py:function:: summary_option(argument: str) -> int | None 56 | :canonical: autodoc2.sphinx.docstring.summary_option 57 | 58 | .. autodoc2-docstring:: autodoc2.sphinx.docstring.summary_option 59 | 60 | .. py:class:: DocstringRenderer(name, arguments, options, content, lineno, content_offset, block_text, state, state_machine) 61 | :canonical: autodoc2.sphinx.docstring.DocstringRenderer 62 | 63 | Bases: :py:obj:`sphinx.util.docutils.SphinxDirective` 64 | 65 | .. autodoc2-docstring:: autodoc2.sphinx.docstring.DocstringRenderer 66 | 67 | .. rubric:: Initialization 68 | 69 | .. autodoc2-docstring:: autodoc2.sphinx.docstring.DocstringRenderer.__init__ 70 | 71 | .. py:attribute:: has_content 72 | :canonical: autodoc2.sphinx.docstring.DocstringRenderer.has_content 73 | :value: False 74 | 75 | .. autodoc2-docstring:: autodoc2.sphinx.docstring.DocstringRenderer.has_content 76 | 77 | .. py:attribute:: required_arguments 78 | :canonical: autodoc2.sphinx.docstring.DocstringRenderer.required_arguments 79 | :value: 1 80 | 81 | .. autodoc2-docstring:: autodoc2.sphinx.docstring.DocstringRenderer.required_arguments 82 | 83 | .. py:attribute:: optional_arguments 84 | :canonical: autodoc2.sphinx.docstring.DocstringRenderer.optional_arguments 85 | :value: 0 86 | 87 | .. autodoc2-docstring:: autodoc2.sphinx.docstring.DocstringRenderer.optional_arguments 88 | 89 | .. py:attribute:: final_argument_whitespace 90 | :canonical: autodoc2.sphinx.docstring.DocstringRenderer.final_argument_whitespace 91 | :value: True 92 | 93 | .. autodoc2-docstring:: autodoc2.sphinx.docstring.DocstringRenderer.final_argument_whitespace 94 | 95 | .. py:attribute:: option_spec 96 | :canonical: autodoc2.sphinx.docstring.DocstringRenderer.option_spec 97 | :type: typing.ClassVar[dict[str, typing.Any]] 98 | :value: None 99 | 100 | .. autodoc2-docstring:: autodoc2.sphinx.docstring.DocstringRenderer.option_spec 101 | 102 | .. py:method:: run() -> list[docutils.nodes.Node] 103 | :canonical: autodoc2.sphinx.docstring.DocstringRenderer.run 104 | 105 | .. autodoc2-docstring:: autodoc2.sphinx.docstring.DocstringRenderer.run 106 | 107 | .. py:function:: parsing_context() -> typing.Generator[None, None, None] 108 | :canonical: autodoc2.sphinx.docstring.parsing_context 109 | 110 | .. autodoc2-docstring:: autodoc2.sphinx.docstring.parsing_context 111 | 112 | .. py:function:: change_source(state: docutils.parsers.rst.states.RSTStateMachine, source_path: str, line_offset: int) -> typing.Generator[None, None, None] 113 | :canonical: autodoc2.sphinx.docstring.change_source 114 | 115 | .. autodoc2-docstring:: autodoc2.sphinx.docstring.change_source 116 | 117 | .. py:function:: _example(a: int, b: str) -> None 118 | :canonical: autodoc2.sphinx.docstring._example 119 | 120 | .. autodoc2-docstring:: autodoc2.sphinx.docstring._example 121 | :parser: myst 122 | -------------------------------------------------------------------------------- /docs/apidocs/autodoc2/autodoc2.sphinx.extension.rst: -------------------------------------------------------------------------------- 1 | :py:mod:`autodoc2.sphinx.extension` 2 | =================================== 3 | 4 | .. py:module:: autodoc2.sphinx.extension 5 | 6 | .. autodoc2-docstring:: autodoc2.sphinx.extension 7 | :allowtitles: 8 | 9 | Module Contents 10 | --------------- 11 | 12 | Classes 13 | ~~~~~~~ 14 | 15 | .. list-table:: 16 | :class: autosummary longtable 17 | :align: left 18 | 19 | * - :py:obj:`EnvCache ` 20 | - .. autodoc2-docstring:: autodoc2.sphinx.extension.EnvCache 21 | :summary: 22 | 23 | Functions 24 | ~~~~~~~~~ 25 | 26 | .. list-table:: 27 | :class: autosummary longtable 28 | :align: left 29 | 30 | * - :py:obj:`setup ` 31 | - .. autodoc2-docstring:: autodoc2.sphinx.extension.setup 32 | :summary: 33 | * - :py:obj:`run_autodoc ` 34 | - .. autodoc2-docstring:: autodoc2.sphinx.extension.run_autodoc 35 | :summary: 36 | * - :py:obj:`run_autodoc_package ` 37 | - .. autodoc2-docstring:: autodoc2.sphinx.extension.run_autodoc_package 38 | :summary: 39 | * - :py:obj:`get_git_clone ` 40 | - .. autodoc2-docstring:: autodoc2.sphinx.extension.get_git_clone 41 | :summary: 42 | 43 | API 44 | ~~~ 45 | 46 | .. py:function:: setup(app: sphinx.application.Sphinx) -> dict[str, str | bool] 47 | :canonical: autodoc2.sphinx.extension.setup 48 | 49 | .. autodoc2-docstring:: autodoc2.sphinx.extension.setup 50 | 51 | .. py:function:: run_autodoc(app: sphinx.application.Sphinx) -> None 52 | :canonical: autodoc2.sphinx.extension.run_autodoc 53 | 54 | .. autodoc2-docstring:: autodoc2.sphinx.extension.run_autodoc 55 | 56 | .. py:function:: run_autodoc_package(app: sphinx.application.Sphinx, config: autodoc2.config.Config, pkg_index: int) -> str | None 57 | :canonical: autodoc2.sphinx.extension.run_autodoc_package 58 | 59 | .. autodoc2-docstring:: autodoc2.sphinx.extension.run_autodoc_package 60 | 61 | .. py:function:: get_git_clone(app: sphinx.application.Sphinx, url: str, branch_tag: str, config: autodoc2.config.Config) -> None | pathlib.Path 62 | :canonical: autodoc2.sphinx.extension.get_git_clone 63 | 64 | .. autodoc2-docstring:: autodoc2.sphinx.extension.get_git_clone 65 | 66 | .. py:class:: EnvCache() 67 | :canonical: autodoc2.sphinx.extension.EnvCache 68 | 69 | Bases: :py:obj:`typing.TypedDict` 70 | 71 | .. autodoc2-docstring:: autodoc2.sphinx.extension.EnvCache 72 | 73 | .. rubric:: Initialization 74 | 75 | .. autodoc2-docstring:: autodoc2.sphinx.extension.EnvCache.__init__ 76 | 77 | .. py:attribute:: hash 78 | :canonical: autodoc2.sphinx.extension.EnvCache.hash 79 | :type: str 80 | :value: None 81 | 82 | .. autodoc2-docstring:: autodoc2.sphinx.extension.EnvCache.hash 83 | 84 | .. py:attribute:: root_module 85 | :canonical: autodoc2.sphinx.extension.EnvCache.root_module 86 | :type: str 87 | :value: None 88 | 89 | .. autodoc2-docstring:: autodoc2.sphinx.extension.EnvCache.root_module 90 | -------------------------------------------------------------------------------- /docs/apidocs/autodoc2/autodoc2.sphinx.rst: -------------------------------------------------------------------------------- 1 | :py:mod:`autodoc2.sphinx` 2 | ========================= 3 | 4 | .. py:module:: autodoc2.sphinx 5 | 6 | .. autodoc2-docstring:: autodoc2.sphinx 7 | :allowtitles: 8 | 9 | Submodules 10 | ---------- 11 | 12 | .. toctree:: 13 | :titlesonly: 14 | :maxdepth: 1 15 | 16 | autodoc2.sphinx.docstring 17 | autodoc2.sphinx.summary 18 | autodoc2.sphinx.utils 19 | autodoc2.sphinx.extension 20 | autodoc2.sphinx.autodoc 21 | -------------------------------------------------------------------------------- /docs/apidocs/autodoc2/autodoc2.sphinx.summary.rst: -------------------------------------------------------------------------------- 1 | :py:mod:`autodoc2.sphinx.summary` 2 | ================================= 3 | 4 | .. py:module:: autodoc2.sphinx.summary 5 | 6 | .. autodoc2-docstring:: autodoc2.sphinx.summary 7 | :allowtitles: 8 | 9 | Module Contents 10 | --------------- 11 | 12 | Classes 13 | ~~~~~~~ 14 | 15 | .. list-table:: 16 | :class: autosummary longtable 17 | :align: left 18 | 19 | * - :py:obj:`AutodocSummary ` 20 | - .. autodoc2-docstring:: autodoc2.sphinx.summary.AutodocSummary 21 | :summary: 22 | 23 | API 24 | ~~~ 25 | 26 | .. py:class:: AutodocSummary(name, arguments, options, content, lineno, content_offset, block_text, state, state_machine) 27 | :canonical: autodoc2.sphinx.summary.AutodocSummary 28 | 29 | Bases: :py:obj:`sphinx.util.docutils.SphinxDirective` 30 | 31 | .. autodoc2-docstring:: autodoc2.sphinx.summary.AutodocSummary 32 | 33 | .. rubric:: Initialization 34 | 35 | .. autodoc2-docstring:: autodoc2.sphinx.summary.AutodocSummary.__init__ 36 | 37 | .. py:attribute:: has_content 38 | :canonical: autodoc2.sphinx.summary.AutodocSummary.has_content 39 | :value: True 40 | 41 | .. autodoc2-docstring:: autodoc2.sphinx.summary.AutodocSummary.has_content 42 | 43 | .. py:attribute:: required_arguments 44 | :canonical: autodoc2.sphinx.summary.AutodocSummary.required_arguments 45 | :value: 0 46 | 47 | .. autodoc2-docstring:: autodoc2.sphinx.summary.AutodocSummary.required_arguments 48 | 49 | .. py:attribute:: optional_arguments 50 | :canonical: autodoc2.sphinx.summary.AutodocSummary.optional_arguments 51 | :value: 0 52 | 53 | .. autodoc2-docstring:: autodoc2.sphinx.summary.AutodocSummary.optional_arguments 54 | 55 | .. py:attribute:: final_argument_whitespace 56 | :canonical: autodoc2.sphinx.summary.AutodocSummary.final_argument_whitespace 57 | :value: False 58 | 59 | .. autodoc2-docstring:: autodoc2.sphinx.summary.AutodocSummary.final_argument_whitespace 60 | 61 | .. py:attribute:: option_spec 62 | :canonical: autodoc2.sphinx.summary.AutodocSummary.option_spec 63 | :type: typing.ClassVar[dict[str, typing.Any]] 64 | :value: None 65 | 66 | .. autodoc2-docstring:: autodoc2.sphinx.summary.AutodocSummary.option_spec 67 | 68 | .. py:method:: run() -> list[docutils.nodes.Node] 69 | :canonical: autodoc2.sphinx.summary.AutodocSummary.run 70 | 71 | .. autodoc2-docstring:: autodoc2.sphinx.summary.AutodocSummary.run 72 | -------------------------------------------------------------------------------- /docs/apidocs/autodoc2/autodoc2.sphinx.utils.rst: -------------------------------------------------------------------------------- 1 | :py:mod:`autodoc2.sphinx.utils` 2 | =============================== 3 | 4 | .. py:module:: autodoc2.sphinx.utils 5 | 6 | .. autodoc2-docstring:: autodoc2.sphinx.utils 7 | :allowtitles: 8 | 9 | Module Contents 10 | --------------- 11 | 12 | Functions 13 | ~~~~~~~~~ 14 | 15 | .. list-table:: 16 | :class: autosummary longtable 17 | :align: left 18 | 19 | * - :py:obj:`load_config ` 20 | - .. autodoc2-docstring:: autodoc2.sphinx.utils.load_config 21 | :summary: 22 | * - :py:obj:`warn_sphinx ` 23 | - .. autodoc2-docstring:: autodoc2.sphinx.utils.warn_sphinx 24 | :summary: 25 | * - :py:obj:`get_database ` 26 | - .. autodoc2-docstring:: autodoc2.sphinx.utils.get_database 27 | :summary: 28 | * - :py:obj:`_warn ` 29 | - .. autodoc2-docstring:: autodoc2.sphinx.utils._warn 30 | :summary: 31 | * - :py:obj:`get_all_analyser ` 32 | - .. autodoc2-docstring:: autodoc2.sphinx.utils.get_all_analyser 33 | :summary: 34 | * - :py:obj:`nested_parse_generated ` 35 | - .. autodoc2-docstring:: autodoc2.sphinx.utils.nested_parse_generated 36 | :summary: 37 | 38 | Data 39 | ~~~~ 40 | 41 | .. list-table:: 42 | :class: autosummary longtable 43 | :align: left 44 | 45 | * - :py:obj:`LOGGER ` 46 | - .. autodoc2-docstring:: autodoc2.sphinx.utils.LOGGER 47 | :summary: 48 | 49 | API 50 | ~~~ 51 | 52 | .. py:data:: LOGGER 53 | :canonical: autodoc2.sphinx.utils.LOGGER 54 | :value: None 55 | 56 | .. autodoc2-docstring:: autodoc2.sphinx.utils.LOGGER 57 | 58 | .. py:function:: load_config(app: sphinx.application.Sphinx, *, overrides: None | dict[str, typing.Any] = None, location: None | docutils.nodes.Element = None) -> autodoc2.config.Config 59 | :canonical: autodoc2.sphinx.utils.load_config 60 | 61 | .. autodoc2-docstring:: autodoc2.sphinx.utils.load_config 62 | 63 | .. py:function:: warn_sphinx(msg: str, subtype: autodoc2.utils.WarningSubtypes, location: None | docutils.nodes.Element = None) -> None 64 | :canonical: autodoc2.sphinx.utils.warn_sphinx 65 | 66 | .. autodoc2-docstring:: autodoc2.sphinx.utils.warn_sphinx 67 | 68 | .. py:function:: get_database(env: sphinx.environment.BuildEnvironment) -> autodoc2.db.Database 69 | :canonical: autodoc2.sphinx.utils.get_database 70 | 71 | .. autodoc2-docstring:: autodoc2.sphinx.utils.get_database 72 | 73 | .. py:function:: _warn(msg: str) -> None 74 | :canonical: autodoc2.sphinx.utils._warn 75 | 76 | .. autodoc2-docstring:: autodoc2.sphinx.utils._warn 77 | 78 | .. py:function:: get_all_analyser(env: sphinx.environment.BuildEnvironment) -> autodoc2.resolve_all.AllResolver 79 | :canonical: autodoc2.sphinx.utils.get_all_analyser 80 | 81 | .. autodoc2-docstring:: autodoc2.sphinx.utils.get_all_analyser 82 | 83 | .. py:function:: nested_parse_generated(state: docutils.parsers.rst.states.RSTStateMachine, content: list[str], source: str, line: int, *, match_titles: bool = False, base: docutils.nodes.Element | None = None) -> docutils.nodes.Element 84 | :canonical: autodoc2.sphinx.utils.nested_parse_generated 85 | 86 | .. autodoc2-docstring:: autodoc2.sphinx.utils.nested_parse_generated 87 | -------------------------------------------------------------------------------- /docs/apidocs/autodoc2/autodoc2.utils.rst: -------------------------------------------------------------------------------- 1 | :py:mod:`autodoc2.utils` 2 | ======================== 3 | 4 | .. py:module:: autodoc2.utils 5 | 6 | .. autodoc2-docstring:: autodoc2.utils 7 | :allowtitles: 8 | 9 | Module Contents 10 | --------------- 11 | 12 | Classes 13 | ~~~~~~~ 14 | 15 | .. list-table:: 16 | :class: autosummary longtable 17 | :align: left 18 | 19 | * - :py:obj:`ItemData ` 20 | - .. autodoc2-docstring:: autodoc2.utils.ItemData 21 | :summary: 22 | * - :py:obj:`WarningSubtypes ` 23 | - .. autodoc2-docstring:: autodoc2.utils.WarningSubtypes 24 | :summary: 25 | 26 | Functions 27 | ~~~~~~~~~ 28 | 29 | .. list-table:: 30 | :class: autosummary longtable 31 | :align: left 32 | 33 | * - :py:obj:`yield_modules ` 34 | - .. autodoc2-docstring:: autodoc2.utils.yield_modules 35 | :summary: 36 | 37 | Data 38 | ~~~~ 39 | 40 | .. list-table:: 41 | :class: autosummary longtable 42 | :align: left 43 | 44 | * - :py:obj:`PROPERTY_TYPE ` 45 | - .. autodoc2-docstring:: autodoc2.utils.PROPERTY_TYPE 46 | :summary: 47 | * - :py:obj:`ARGS_TYPE ` 48 | - .. autodoc2-docstring:: autodoc2.utils.ARGS_TYPE 49 | :summary: 50 | 51 | API 52 | ~~~ 53 | 54 | .. py:data:: PROPERTY_TYPE 55 | :canonical: autodoc2.utils.PROPERTY_TYPE 56 | :value: None 57 | 58 | .. autodoc2-docstring:: autodoc2.utils.PROPERTY_TYPE 59 | 60 | .. py:data:: ARGS_TYPE 61 | :canonical: autodoc2.utils.ARGS_TYPE 62 | :value: None 63 | 64 | .. autodoc2-docstring:: autodoc2.utils.ARGS_TYPE 65 | 66 | .. py:class:: ItemData() 67 | :canonical: autodoc2.utils.ItemData 68 | 69 | Bases: :py:obj:`typing.TypedDict` 70 | 71 | .. autodoc2-docstring:: autodoc2.utils.ItemData 72 | 73 | .. rubric:: Initialization 74 | 75 | .. autodoc2-docstring:: autodoc2.utils.ItemData.__init__ 76 | 77 | .. py:attribute:: type 78 | :canonical: autodoc2.utils.ItemData.type 79 | :type: typing_extensions.Required[str] 80 | :value: None 81 | 82 | .. autodoc2-docstring:: autodoc2.utils.ItemData.type 83 | 84 | .. py:attribute:: full_name 85 | :canonical: autodoc2.utils.ItemData.full_name 86 | :type: typing_extensions.Required[str] 87 | :value: None 88 | 89 | .. autodoc2-docstring:: autodoc2.utils.ItemData.full_name 90 | 91 | .. py:attribute:: doc 92 | :canonical: autodoc2.utils.ItemData.doc 93 | :type: typing_extensions.Required[str] 94 | :value: None 95 | 96 | .. autodoc2-docstring:: autodoc2.utils.ItemData.doc 97 | 98 | .. py:attribute:: range 99 | :canonical: autodoc2.utils.ItemData.range 100 | :type: tuple[int, int] 101 | :value: None 102 | 103 | .. autodoc2-docstring:: autodoc2.utils.ItemData.range 104 | 105 | .. py:attribute:: file_path 106 | :canonical: autodoc2.utils.ItemData.file_path 107 | :type: None | str 108 | :value: None 109 | 110 | .. autodoc2-docstring:: autodoc2.utils.ItemData.file_path 111 | 112 | .. py:attribute:: encoding 113 | :canonical: autodoc2.utils.ItemData.encoding 114 | :type: str 115 | :value: None 116 | 117 | .. autodoc2-docstring:: autodoc2.utils.ItemData.encoding 118 | 119 | .. py:attribute:: all 120 | :canonical: autodoc2.utils.ItemData.all 121 | :type: None | list[str] 122 | :value: None 123 | 124 | .. autodoc2-docstring:: autodoc2.utils.ItemData.all 125 | 126 | .. py:attribute:: imports 127 | :canonical: autodoc2.utils.ItemData.imports 128 | :type: list[tuple[str, str | None]] 129 | :value: None 130 | 131 | .. autodoc2-docstring:: autodoc2.utils.ItemData.imports 132 | 133 | .. py:attribute:: value 134 | :canonical: autodoc2.utils.ItemData.value 135 | :type: None | str | typing.Any 136 | :value: None 137 | 138 | .. autodoc2-docstring:: autodoc2.utils.ItemData.value 139 | 140 | .. py:attribute:: annotation 141 | :canonical: autodoc2.utils.ItemData.annotation 142 | :type: None | str 143 | :value: None 144 | 145 | .. autodoc2-docstring:: autodoc2.utils.ItemData.annotation 146 | 147 | .. py:attribute:: properties 148 | :canonical: autodoc2.utils.ItemData.properties 149 | :type: list[autodoc2.utils.PROPERTY_TYPE] 150 | :value: None 151 | 152 | .. autodoc2-docstring:: autodoc2.utils.ItemData.properties 153 | 154 | .. py:attribute:: args 155 | :canonical: autodoc2.utils.ItemData.args 156 | :type: autodoc2.utils.ARGS_TYPE 157 | :value: None 158 | 159 | .. autodoc2-docstring:: autodoc2.utils.ItemData.args 160 | 161 | .. py:attribute:: return_annotation 162 | :canonical: autodoc2.utils.ItemData.return_annotation 163 | :type: None | str 164 | :value: None 165 | 166 | .. autodoc2-docstring:: autodoc2.utils.ItemData.return_annotation 167 | 168 | .. py:attribute:: bases 169 | :canonical: autodoc2.utils.ItemData.bases 170 | :type: list[str] 171 | :value: None 172 | 173 | .. autodoc2-docstring:: autodoc2.utils.ItemData.bases 174 | 175 | .. py:attribute:: doc_inherited 176 | :canonical: autodoc2.utils.ItemData.doc_inherited 177 | :type: str 178 | :value: None 179 | 180 | .. autodoc2-docstring:: autodoc2.utils.ItemData.doc_inherited 181 | 182 | .. py:attribute:: inherited 183 | :canonical: autodoc2.utils.ItemData.inherited 184 | :type: str 185 | :value: None 186 | 187 | .. autodoc2-docstring:: autodoc2.utils.ItemData.inherited 188 | 189 | .. py:class:: WarningSubtypes(*args, **kwds) 190 | :canonical: autodoc2.utils.WarningSubtypes 191 | 192 | Bases: :py:obj:`enum.Enum` 193 | 194 | .. autodoc2-docstring:: autodoc2.utils.WarningSubtypes 195 | 196 | .. rubric:: Initialization 197 | 198 | .. autodoc2-docstring:: autodoc2.utils.WarningSubtypes.__init__ 199 | 200 | .. py:attribute:: CONFIG_ERROR 201 | :canonical: autodoc2.utils.WarningSubtypes.CONFIG_ERROR 202 | :value: 'config_error' 203 | 204 | .. autodoc2-docstring:: autodoc2.utils.WarningSubtypes.CONFIG_ERROR 205 | 206 | .. py:attribute:: GIT_CLONE_FAILED 207 | :canonical: autodoc2.utils.WarningSubtypes.GIT_CLONE_FAILED 208 | :value: 'git_clone' 209 | 210 | .. autodoc2-docstring:: autodoc2.utils.WarningSubtypes.GIT_CLONE_FAILED 211 | 212 | .. py:attribute:: MISSING_MODULE 213 | :canonical: autodoc2.utils.WarningSubtypes.MISSING_MODULE 214 | :value: 'missing_module' 215 | 216 | .. autodoc2-docstring:: autodoc2.utils.WarningSubtypes.MISSING_MODULE 217 | 218 | .. py:attribute:: DUPLICATE_ITEM 219 | :canonical: autodoc2.utils.WarningSubtypes.DUPLICATE_ITEM 220 | :value: 'dup_item' 221 | 222 | .. autodoc2-docstring:: autodoc2.utils.WarningSubtypes.DUPLICATE_ITEM 223 | 224 | .. py:attribute:: RENDER_ERROR 225 | :canonical: autodoc2.utils.WarningSubtypes.RENDER_ERROR 226 | :value: 'render' 227 | 228 | .. autodoc2-docstring:: autodoc2.utils.WarningSubtypes.RENDER_ERROR 229 | 230 | .. py:attribute:: ALL_MISSING 231 | :canonical: autodoc2.utils.WarningSubtypes.ALL_MISSING 232 | :value: 'all_missing' 233 | 234 | .. autodoc2-docstring:: autodoc2.utils.WarningSubtypes.ALL_MISSING 235 | 236 | .. py:attribute:: ALL_RESOLUTION 237 | :canonical: autodoc2.utils.WarningSubtypes.ALL_RESOLUTION 238 | :value: 'all_resolve' 239 | 240 | .. autodoc2-docstring:: autodoc2.utils.WarningSubtypes.ALL_RESOLUTION 241 | 242 | .. py:attribute:: NAME_NOT_FOUND 243 | :canonical: autodoc2.utils.WarningSubtypes.NAME_NOT_FOUND 244 | :value: 'missing' 245 | 246 | .. autodoc2-docstring:: autodoc2.utils.WarningSubtypes.NAME_NOT_FOUND 247 | 248 | .. py:function:: yield_modules(folder: str | pathlib.Path, *, root_module: str | None = None, extensions: typing.Sequence[str] = ('.py', '.pyi'), exclude_dirs: typing.Sequence[str] = ('__pycache__', ), exclude_files: typing.Sequence[str] = ()) -> typing.Iterable[tuple[pathlib.Path, str]] 249 | :canonical: autodoc2.utils.yield_modules 250 | 251 | .. autodoc2-docstring:: autodoc2.utils.yield_modules 252 | -------------------------------------------------------------------------------- /docs/apidocs/index.rst: -------------------------------------------------------------------------------- 1 | API Reference 2 | ============= 3 | 4 | This page contains auto-generated API reference documentation [#f1]_. 5 | 6 | .. toctree:: 7 | :titlesonly: 8 | 9 | autodoc2/autodoc2 10 | aiida/aiida 11 | 12 | .. [#f1] Created with `sphinx-autodoc2 `_ 13 | -------------------------------------------------------------------------------- /docs/autodoc.md: -------------------------------------------------------------------------------- 1 | # `autodoc-object` directive 2 | 3 | The `autodoc-object` directive can be used to render the documentation for a single Python object. 4 | It takes a single argument, the fully qualified name of the object that should be rendered. 5 | 6 | Using the `:literal:` option, the pre-rendered content will be rendered as a literal block, 7 | and the `:literal-lexer:` option can be used to specify the lexer to use for syntax highlighting. 8 | 9 | The directive can contain content, 10 | which is read as [TOML](https://toml.io) and will override any of the {ref}`global configuration ` options (without the `autodoc2_` prefix). 11 | 12 | ## Literal representation 13 | 14 | For example: 15 | 16 | ````restructuredtext 17 | .. autodoc2-object:: autodoc2.sphinx.docstring._example 18 | :literal: 19 | :literal-lexer: restructuredtext 20 | 21 | render_plugin = "rst" 22 | no_index = true 23 | ```` 24 | 25 | creates: 26 | 27 | ```{autodoc2-object} autodoc2.sphinx.docstring._example 28 | :literal: 29 | :literal-lexer: restructuredtext 30 | 31 | render_plugin = "rst" 32 | no_index = true 33 | ``` 34 | 35 | ## Rendered representation 36 | 37 | For example: 38 | 39 | ````restructuredtext 40 | .. autodoc2-object:: autodoc2.sphinx.docstring._example 41 | 42 | render_plugin = "rst" 43 | no_index = true 44 | ```` 45 | 46 | creates: 47 | 48 | ```{autodoc2-object} autodoc2.sphinx.docstring._example 49 | render_plugin = "myst" 50 | no_index = true 51 | ``` 52 | 53 | ## Rendered representation (signature only) 54 | 55 | Or without annotations and docstring: 56 | 57 | ````restructuredtext 58 | .. autodoc2-object:: autodoc2.sphinx.docstring._example 59 | 60 | render_plugin = "rst" 61 | no_index = true 62 | annotations = false 63 | docstrings = false 64 | ```` 65 | 66 | creates: 67 | 68 | ```{autodoc2-object} autodoc2.sphinx.docstring._example 69 | render_plugin = "myst" 70 | no_index = true 71 | annotations = false 72 | docstrings = false 73 | ``` 74 | -------------------------------------------------------------------------------- /docs/autodoc_diff.md: -------------------------------------------------------------------------------- 1 | (autodoc-differences)= 2 | # Differences from `sphinx.ext.autodoc` 3 | 4 | The the main differences between `sphinx-autodoc2` and [`sphinx.ext.autodoc`](https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#module-sphinx.ext.autodoc): 5 | 6 | 1. `sphinx-autodoc2` analyses the source code using **static analysis**, 7 | rather than **dynamic introspection**. 8 | 9 | - This means that it can be used to document code that is not importable, 10 | or that is not installed in the same environment as the documentation. 11 | - The analysis can infer information not available at runtime, 12 | such as type strings of attributes and imports under `TYPE_CHECKING` block. 13 | - The analysis does not lead to any un-desirable side-effects, 14 | that could occur on importing the code. 15 | 16 | 2. `sphinx-autodoc2` integrates auto-documentation within the sphinx build process, 17 | rather than requiring the separate `sphinx-apidoc` CLI tool. 18 | - This allows it to optimise rebuilds, by only re-generating documentation for objects that have changed. 19 | 20 | 3. `sphinx-autodoc2` allows for docstrings not written in RestructuredText, principally [MyST](https://myst-parser.readthedocs.io). 21 | - `sphinx.ext.autodoc` assumes that your docstings are written in RestructuredText, 22 | and that you are using the directives in a RestructuredText document. 23 | - `sphinx-autodoc2` allows you to write your docstrings in either RestructuredText or MyST, 24 | and to use the directives in either RestructuredText or MyST documents. 25 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | """The configuration for this packages documentation.""" 2 | 3 | from datetime import date 4 | 5 | from autodoc2 import __version__ 6 | 7 | # -- Project information ----------------------------------------------------- 8 | 9 | project = "sphinx-autodoc2" 10 | version = __version__ 11 | copyright = f"{date.today().year}, Chris Sewell" 12 | author = "Chris Sewell" 13 | 14 | # -- General configuration --------------------------------------------------- 15 | 16 | extensions = [ 17 | "myst_parser", 18 | "autodoc2", 19 | "sphinx.ext.intersphinx", 20 | "sphinx.ext.viewcode", 21 | "sphinx.ext.todo", # for aiida 22 | ] 23 | exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] 24 | intersphinx_mapping = { 25 | "python": ("https://docs.python.org/3/", None), 26 | "sphinx": ("https://www.sphinx-doc.org/en/master", None), 27 | } 28 | myst_enable_extensions = ["fieldlist", "deflist"] 29 | 30 | # -- HTML output ------------------------------------------------- 31 | 32 | html_theme = "furo" 33 | html_title = "sphinx-autodoc2" 34 | # html_logo = "logo.svg" 35 | html_theme_options = { 36 | "top_of_page_button": "edit", 37 | "source_repository": "https://github.com/chrisjsewell/sphinx-autodoc2/", 38 | "source_branch": "main", 39 | "source_directory": "docs/", 40 | "announcement": "Just released 🎉, feedback welcomed at " 41 | "sphinx-autodoc2", 42 | } 43 | 44 | # --- Autodoc configuration ------ 45 | 46 | autodoc2_packages = [ 47 | "../src/autodoc2", 48 | { 49 | "path": "aiida", 50 | "from_git_clone": ( 51 | "https://github.com/aiidateam/aiida-core.git", 52 | "v2.2.2", 53 | ), 54 | "exclude_dirs": [ 55 | "__pycache__", 56 | # "migrations", 57 | ], 58 | }, 59 | ] 60 | autodoc2_render_plugin_regexes = [(r"autodoc2\.db", "myst")] 61 | autodoc2_replace_annotations = [ 62 | ("re.Pattern", "typing.Pattern"), 63 | ] 64 | autodoc2_docstring_parser_regexes = [ 65 | (r"autodoc2\.sphinx\.docstring\._example", "myst"), 66 | ] 67 | autodoc2_deprecated_module_regexes = [ 68 | r"aiida\.parsers\.parser", 69 | ] 70 | autodoc2_module_all_regexes = [r"aiida\.[^\.]+"] 71 | autodoc2_skip_module_regexes = [ 72 | r"aiida\.[^\.]+\..*", 73 | r"aiida\.(__main__|calculations|restapi|sphinxext|storage|workflows)", 74 | ] 75 | # autodoc2_docstrings = "all" 76 | 77 | nitpick_ignore_regex = [ 78 | (r"py:.*", r"typing_extensions.*"), 79 | (r"py:.*", r"astroid.*"), 80 | (r"py:.*", r"docutils.*"), 81 | # TODO for some reason in: 82 | # .. py:function:: format_args(args_info: autodoc2.utils.ARGS_TYPE ... 83 | # ARGS_TYPE is treated as a class rather than data 84 | ("py:class", r"autodoc2\.utils\..*_TYPE"), 85 | # from aiida 86 | (r"py:.*", r"types\.FunctionType"), 87 | ( 88 | r"py:.*", 89 | r"(aiida|circus|click|disk_objectstore|importlib_metadata|kiwipy|plumpy|pgsu|requests).*", 90 | ), 91 | (r"py:.*", r"(DaemonException|Manager|PersistenceError)"), 92 | (r"py:.*", r"QueryBuilder\._get_ormclass"), 93 | ] 94 | 95 | # --- Additional configuration ---- 96 | 97 | import typing as t # noqa: E402 98 | 99 | from autodoc2.config import CONFIG_PREFIX, Config, PackageConfig # noqa: E402 100 | from docutils import nodes # noqa: E402 101 | from sphinx.application import Sphinx # noqa: E402 102 | from sphinx.util.docutils import SphinxDirective # noqa: E402 103 | 104 | 105 | def setup(app: Sphinx) -> None: 106 | app.add_object_type( 107 | "confval", # directivename 108 | "confval", # rolename 109 | "pair: %s; configuration value", # indextemplate 110 | ) 111 | 112 | app.add_directive("autodoc2-config", CreateConfigDirective) 113 | app.add_directive("autodoc2-config-package", CreateConfigPkgDirective) 114 | 115 | 116 | class CreateConfigDirective(SphinxDirective): 117 | """Document the configuration options.""" 118 | 119 | def run(self) -> t.List[nodes.Node]: 120 | text = [] 121 | 122 | config = Config() 123 | for name, value, field in config.as_triple(): 124 | text.append(f"``````{{confval}} {CONFIG_PREFIX}{name}") 125 | text.append(f'{field.metadata.get("help", "")}') 126 | text.append("") 127 | # if "category" in field.metadata: 128 | # text.append(f"**category**: { field.metadata['category']}") 129 | # text.append("") 130 | type_ = type_to_string(field.metadata.get("doc_type", field.type)) 131 | text.append(f"**type**: {type_}") 132 | text.append("") 133 | default_str = value if isinstance(value, str) else repr(value) 134 | if len(default_str.splitlines()) == 1: 135 | text.append(f"**default**: ``{default_str}``") 136 | else: 137 | text.append("**default**:") 138 | text.append("") 139 | text.append("```") 140 | text.append(default_str) 141 | text.append("```") 142 | text.append("") 143 | text.append("``````") 144 | 145 | base_node = nodes.Element() 146 | self.state.nested_parse(text, self.content_offset, base_node) 147 | return base_node.children # type: ignore 148 | 149 | 150 | class CreateConfigPkgDirective(SphinxDirective): 151 | """Document the package-level configuration options.""" 152 | 153 | def run(self) -> t.List[nodes.Node]: 154 | base_node = nodes.Element() 155 | text = [] 156 | pkg_config = PackageConfig("") 157 | for name, value, field in pkg_config.as_triple(): 158 | text.append(f"``````{{confval}} {CONFIG_PREFIX}packages[{name}]") 159 | text.append(f'{field.metadata.get("help", "")}') 160 | text.append("") 161 | type_ = type_to_string(field.type) 162 | text.append(f"**type**: {type_}") 163 | text.append("") 164 | default_str = value if isinstance(value, str) else repr(value) 165 | if not default_str: 166 | pass 167 | elif len(default_str.splitlines()) < 2: 168 | text.append(f"**default**: ``{default_str}``") 169 | else: 170 | text.append("**default**:") 171 | text.append("") 172 | text.append("```") 173 | text.append(default_str) 174 | text.append("```") 175 | text.append("``````") 176 | self.state.nested_parse(text, self.content_offset, base_node) 177 | return base_node.children # type: ignore 178 | 179 | 180 | def type_to_string(type_: t.Any) -> str: 181 | """Convert a type to a string.""" 182 | # TODO just keeping it simple for now but can we do this with astroid!? 183 | if isinstance(type_, tuple): 184 | return " or ".join(type_to_string(t) for t in type_) 185 | if type_ is type(None): 186 | return "``None``" 187 | if type_ is str: 188 | return "``str``" 189 | if type_ is int: 190 | return "``int``" 191 | if type_ is bool: 192 | return "``bool``" 193 | if type_ is float: 194 | return "``float``" 195 | if type_ is list: 196 | return "``list``" 197 | type_string = str(type_) 198 | if "RstRender" in type_string: 199 | return '``"rst"``' 200 | return type_string 201 | -------------------------------------------------------------------------------- /docs/config.md: -------------------------------------------------------------------------------- 1 | # Configuration 2 | 3 | (config:global)= 4 | ## Global 5 | 6 | This section describes the configuration options for `sphinx-autodoc2`, that you can set in the `conf.py` file. 7 | 8 | ```{autodoc2-config} 9 | ``` 10 | 11 | (config:package)= 12 | ## Package analysis 13 | 14 | In the `autodoc2_packages` configuration option, an item can be a string, or a dictionary such as: 15 | 16 | ```python 17 | autodoc2_packages = [ 18 | "../src/autodoc2", 19 | { 20 | "path": "../src/other/module", 21 | "module": "other.module", 22 | }, 23 | ] 24 | ``` 25 | 26 | The following are keys allowed in the dictionary: 27 | 28 | ```{autodoc2-config-package} 29 | ``` 30 | -------------------------------------------------------------------------------- /docs/docstrings.md: -------------------------------------------------------------------------------- 1 | # `autodoc2-docstring` directive 2 | 3 | One of the key features of autodoc2 is the ability to identify object docstrings 4 | and render them in the documentation, using a given parser. 5 | 6 | The `autodoc2-docstring` directive is used to render a docstring. 7 | It takes a single argument, the fully qualified name of the object whose docstring should be rendered. 8 | 9 | Using the `:literal:` option, the docstring will be rendered as a literal block. 10 | 11 | - the `:literal-linenos:` option can be used to enable line numbers for the literal block, based on the line number in the source document, 12 | - the `:literal-lexer:` option can be used to specify the lexer to use for syntax highlighting. 13 | 14 | ````restructuredtext 15 | .. autodoc2-docstring:: autodoc2.sphinx.docstring._example 16 | :literal: 17 | :literal-linenos: 18 | :literal-lexer: markdown 19 | ```` 20 | 21 | creates: 22 | 23 | ```{autodoc2-docstring} autodoc2.sphinx.docstring._example 24 | :literal: 25 | :literal-linenos: 26 | :literal-lexer: markdown 27 | ``` 28 | 29 | Omitting the `:literal:` option will render the docstring as a nested syntax block. 30 | 31 | - the `parser` option can be used to specify the parser to use for the docstring, such as `myst`, `rst` or a the fully qualified name of a custom parser class, 32 | If not specified the docstring will be rendered using the current parser. 33 | - the `:allowtitles:` option can be used to allow the docstring to contain heading, and can be used if the `autodoc2-docstring` is at the top level of the document. 34 | 35 | ````restructuredtext 36 | .. autodoc2-docstring:: autodoc2.sphinx.docstring._example 37 | :parser: myst 38 | :allowtitles: 39 | ```` 40 | 41 | creates: 42 | 43 | ```{autodoc2-docstring} autodoc2.sphinx.docstring._example 44 | :parser: myst 45 | :allowtitles: 46 | ``` 47 | 48 | ## Specifying the parser for auto-generated documentation 49 | 50 | When auto-documenting source code, 51 | by default the docstring will be rendered using the current parser. 52 | 53 | To list specific parsers for specific objects, 54 | you can use the {confval}`autodoc2_docstring_parser_regexes` configuration option. 55 | 56 | ```python 57 | autodoc2_docstring_parser_regexes = [ 58 | (r"autodoc2\.sphinx\.docstring\._example", "myst"), 59 | ] 60 | ``` 61 | 62 | You can see this in action at {py:func}`autodoc2.sphinx.docstring._example` 63 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # sphinx-autodoc2 2 | 3 | [![GitHub Repo stars](https://img.shields.io/github/stars/chrisjsewell/sphinx-autodoc2?label=Like%20and%20Share%21&style=social)](https://github.com/chrisjsewell/sphinx-autodoc2) 4 | [![PyPI](https://img.shields.io/pypi/v/sphinx-autodoc2?label=PyPI&logo=pypi&style=social)](https://pypi.org/project/sphinx-autodoc2/) 5 | 6 | `sphinx-autodoc2` is a Sphinx extension that automatically generates API documentation for your Python packages. 7 | 8 | Static analysis of Python code 9 | : There is no need to install your package to generate the documentation, and `sphinx-autodoc2` will correctly handle `if TYPE_CHECKING` blocks and other typing only features. 10 | : Sphinx parse warnings correctly point to the source code line, and not the generated documentation. 11 | : You can even document packages from outside the project (via `git clone`)! 12 | 13 | Integrated API documentation generation 14 | : Document genration is integrated with the Sphinx build process, rather than requiring the separate `sphinx-apidoc` CLI tool. 15 | 16 | Optimized for rebuilds 17 | : Analysis of packages and file rendering are cached, so you can use `sphinx-autodoc2` in your development workflow. 18 | 19 | Support for `__all__` 20 | : `sphinx-autodoc2` can follow `__all__` variable, to only document the public API. 21 | 22 | Support for both `rst` and `md` docstrings 23 | : `sphinx-autodoc2` supports both `rst` and `md` ([MyST](https://myst-parser.readthedocs.io)) docstrings, which can be mixed within the same project. 24 | 25 | Highly configurable 26 | : `sphinx-autodoc2` is highly configurable, with many options to control the analysis and output of the documentation. 27 | 28 | Decoupled analysis and rendering 29 | : The analysis and rendering of the documentation are decoupled, and not dependent on Sphinx. 30 | : This means that you can use `sphinx-autodoc2` to generate documentation outside of Sphinx (see the `autodoc2` command line tool). 31 | 32 | Get started with the [Quickstart Guide](quickstart.md) ⏩ 33 | 34 | Or checkout the the [Example API Documentation](apidocs/index.rst) ✨ 35 | 36 | ```{toctree} 37 | :maxdepth: 2 38 | 39 | quickstart 40 | docstrings 41 | summary 42 | autodoc 43 | config 44 | autodoc_diff 45 | apidocs/index 46 | ``` 47 | -------------------------------------------------------------------------------- /docs/quickstart.md: -------------------------------------------------------------------------------- 1 | # Quickstart 2 | 3 | This section describes how to get started with `sphinx-autodoc2` 🎉 4 | 5 | ## Installation 6 | 7 | Install from PyPI: 8 | 9 | ```{code-block} bash 10 | pip install sphinx-autodoc2 11 | ``` 12 | 13 | ## Enabling the extension 14 | 15 | Add `autodoc2` to the `extensions` list in your `conf.py` file and, as as a minimum, set the {confval}`autodoc2_packages` configuration option to the list of packages you want to document: 16 | 17 | ```python 18 | extensions = [ 19 | "autodoc2", 20 | ] 21 | autodoc2_packages = [ 22 | "../my_package", 23 | ] 24 | ``` 25 | 26 | This will generate documentation for the `my_package` package, and all of its sub-packages and modules, within the `apidocs` (or {confval}`autodoc2_output_dir`) directory, 27 | which you can include in a `toctree` directive. 28 | 29 | ```restructuredtext 30 | .. toctree:: 31 | :maxdepth: 2 32 | 33 | apidocs/index 34 | ``` 35 | 36 | ```{seealso} 37 | {ref}`config:package` for more information on how to configure the packages to document. 38 | ``` 39 | 40 | ```{tip} 41 | If you don't want to include the `apidocs` directory in your repository, 42 | you may want to add a `.gitignore` in the `apidocs` folder with `*` in it. 43 | ``` 44 | 45 | ## Manually documenting select objects 46 | 47 | `sphinx-autodoc2` can be used in one or both of two "modes": 48 | 49 | 1. **auto mode** (default) - Automatically generate files for all modules and packages specified by the {confval}`autodoc2_packages` configuration option. 50 | 51 | 2. **manual mode** - Use the [`autodoc2-object` directive](autodoc.md) to manually specify which objects to document. 52 | 53 | To turn off auto mode, set the {confval}`autodoc2_packages[auto_mode]` configuration option to `False`: 54 | 55 | ```python 56 | extensions = [ 57 | "autodoc2", 58 | ] 59 | autodoc2_packages = [ 60 | { 61 | "path": "../my_package", 62 | "auto_mode": False, 63 | }, 64 | ] 65 | ``` 66 | 67 | You can even render only the docstring of any object, see: [](docstrings.md). 68 | 69 | ## Ignoring autodoc2 warnings 70 | 71 | When running `autodoc2` in Sphinx, you may see warnings such as: 72 | 73 | ```console 74 | WARNING: autodoc2_packages must not be empty [autodoc2.config_error] 75 | ``` 76 | 77 | All warnings emitted by `sphinx-autodoc2` will have the `autodoc2` type and a related subtype, so you can ignore them by adding them to the 78 | [Sphinx `suppress_warnings` configuration](https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-suppress_warnings) 79 | in your `conf.py`: 80 | 81 | ```python 82 | suppress_warnings = [ 83 | "autodoc2.*", # suppress all 84 | "autodoc2.config_error", # suppress specific 85 | ] 86 | ``` 87 | 88 | ## Dealing with `"reference target not found"` warnings 89 | 90 | When running `autodoc2` in Sphinx (in nitpick mode), you may see warnings such as: 91 | 92 | ```console 93 | path/to/module.rst:62: WARNING: py:class reference target not found: package.module.MyClass 94 | ``` 95 | 96 | These are potentially from type annotations, 97 | for packages that you have not included in your 98 | [intersphinx configuration](https://www.sphinx-doc.org/en/master/usage/extensions/intersphinx.html). 99 | 100 | Alternatively, they may be from imports that are named differently in the external project's intersphinx inventory, 101 | For example, if you import `MyClass` from `package`, 102 | but the external project exposes it only as `package.module.MyClass`. 103 | In this case, you can use the {confval}`autodoc2_replace_annotations` and {confval}`autodoc2_replace_bases` configuration options to replace the annotation/class base with the correct reference. 104 | 105 | ```python 106 | autodoc2_replace_annotations = { 107 | "package.MyClass": "package.module.MyClass", 108 | } 109 | autodoc2_replace_bases = { 110 | "package.MyClass": "package.module.MyClass", 111 | } 112 | ``` 113 | 114 | If you cannot, or do not, wish to fix them, 115 | then you can suppress these warnings using the 116 | [`nitpick_ignore` or `nitpick_ignore_regex`](https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-nitpick_ignore) configurations. 117 | In your `conf.py`: 118 | 119 | ```python 120 | # ignore all warnings from this package 121 | nitpick_ignore_regex = [ 122 | ("py:.*", r"package\..*"), 123 | ] 124 | # ignore a specific warning 125 | nitpick_ignore = [ 126 | ("py:class", "package.module.MyClass"), 127 | ] 128 | ``` 129 | 130 | ```{tip} 131 | To find out what references an external project exposes to intersphinx, 132 | you can use the `myst-inv` command line tool. 133 | See [MyST cross-project links](https://myst-parser.readthedocs.io/en/latest/syntax/syntax.html#cross-project-inventory-links). 134 | ``` 135 | 136 | ## Documenting only the public API (*via* `__all__`) 137 | 138 | By default, `sphinx-autodoc2` will document all objects within each package/module, and reference direct children of them. 139 | 140 | If you want to document only the public API of your package, you can use the `__all__` variables to specify which objects to document. 141 | For example: 142 | 143 | ```python 144 | from .my_module import MyClass 145 | __all__ = [ 146 | "MyClass", 147 | "my_function", 148 | ] 149 | def my_function(): ... 150 | ``` 151 | 152 | ```{seealso} 153 | The [Python import documentation](https://docs.python.org/3/reference/simple_stmts.html#import) 154 | ``` 155 | 156 | To enable this feature, set the {confval}`autodoc2_module_all_regexes` configuration option in your `conf.py`: 157 | 158 | ```python 159 | autodoc2_module_all_regexes = [ 160 | r"my_package\..*", 161 | ] 162 | ``` 163 | 164 | You can see an axample of this in the [Example documentation of the `aiida` package](aiida). 165 | 166 | Note, when following `__all__` imports, 167 | since the `:canonical:` option is added to each object, 168 | [intersphinx](https://www.sphinx-doc.org/en/master/usage/extensions/intersphinx.html) 169 | will record both the canonical and non-canonical names of the object. 170 | For example, if there is a package `my_package` with the following `__init__.py`: 171 | 172 | ```python 173 | from .my_module import MyClass 174 | __all__ = [ 175 | "MyClass", 176 | ] 177 | ``` 178 | 179 | Then you will be able to reference `MyClass` in your documentation as either `my_package.MyClass` or `my_package.my_module.MyClass`. 180 | 181 | ## Using Markdown (MyST) docstrings 182 | 183 | By default, `sphinx-autodoc2` will generate the file for each module/package as `.rst`, 184 | and the docstrings of each object within that module will also be interpreted as `rst`. 185 | 186 | If you want to use Markdown ([MyST](https://myst-parser.readthedocs.io)) docstrings, 187 | you can set the {confval}`autodoc2_docstring_parser_regexes` for objects that use Markdown docstrings: 188 | 189 | ```python 190 | autodoc2_docstring_parser_regexes = [ 191 | # this will render all docstrings as Markdown 192 | (r".*", "myst"), 193 | # this will render select docstrings as Markdown 194 | (r"autodoc2\..*", "myst"), 195 | ] 196 | ``` 197 | 198 | Alternatively, you can set the {confval}`autodoc2_render_plugin` configuration option in your `conf.py`: 199 | 200 | ```python 201 | autodoc2_render_plugin = "myst" 202 | ``` 203 | 204 | This will now create all files with the ".md" extension, and thus the docstrings will be interpreted as MyST by default. 205 | 206 | To specify at a module level which files to render as Markdown or RestructuredText, you can set the {confval}`autodoc2_render_plugin_regexes` configuration option in your `conf.py`: 207 | 208 | ```python 209 | autodoc2_render_plugin_regexes = [ 210 | (r"autodoc2\.db", "myst") 211 | ] 212 | ``` 213 | 214 | Which for example, created this page using Markdown docstrings: {py:mod}`autodoc2.db` 215 | 216 | ````{tip} 217 | If you are looking to use Markdown docstrings, 218 | with the default [sphinx-style](https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#info-field-lists), for example: 219 | 220 | ```python 221 | def my_function(a: str, b: int) -> bool: 222 | """This is my function. 223 | 224 | :param arg1: The first argument. 225 | :param arg2: The second argument. 226 | :return: The return value. 227 | """ 228 | ``` 229 | 230 | Then you should enable the [MyST `fieldlist` extension](https://myst-parser.readthedocs.io/en/latest/syntax/optional.html#field-lists) in your `conf.py`: 231 | 232 | ```python 233 | myst_enable_extensions = ["fieldlist"] 234 | ``` 235 | 236 | ```{important} 237 | It is advised that you ensure the `mdit-py-plugins`, which `myst-parser` depends on, is pinned to `>0.3.4`, 238 | since this version introduces improvements to the `fieldlist` extension 239 | (see [`executablebooks/mdit-py-plugins#65`](https://github.com/executablebooks/mdit-py-plugins/pull/65)) 240 | ``` 241 | 242 | ```` 243 | 244 | ## Command Line Tool 245 | 246 | If installed with the `cli` extra, `sphinx-autodoc2` will install the `autodoc2` command line tool. 247 | 248 | ```console 249 | $ pip install sphinx-autodoc2[cli] 250 | $ autodoc2 --help 251 | ``` 252 | -------------------------------------------------------------------------------- /docs/summary.md: -------------------------------------------------------------------------------- 1 | # `autodoc2-summary` directive 2 | 3 | The `autodoc2-summary` directive is used to render a summary of a list of objects. 4 | This is useful for creating a table of contents for a module, or a list of objects in a package. 5 | 6 | For example, the following: 7 | 8 | ````restructuredtext 9 | .. autodoc2-summary:: 10 | :renderer: myst 11 | 12 | aiida.orm.Node 13 | ~aiida.orm.Dict 14 | autodoc2.sphinx.docstring._example my example 15 | ```` 16 | 17 | creates: 18 | 19 | ```{autodoc2-summary} 20 | :renderer: myst 21 | 22 | aiida.orm.Node 23 | ~aiida.orm.Dict 24 | autodoc2.sphinx.docstring._example my example 25 | ``` 26 | 27 | Note that fully qualified names can be used to refer to objects in other packages, 28 | and they will also resolve against public API names, i.e. if the object is specified in an `__all__` variable. 29 | 30 | Any text after the fully qualified name will be used as the title for the object, 31 | or alternatively, if the name begins with `~` then the last component will be used as the title. 32 | 33 | The `:renderer:` option can also be used to specify the renderer to use for the summary. 34 | 35 | The summary renders the first block of text in the docstring of each object, 36 | these renderings are governed by the {confval}`autodoc2_docstrings` and {confval}`autodoc2_docstring_parser_regexes` configuration option. 37 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["flit_core >=3.2,<4"] 3 | build-backend = "flit_core.buildapi" 4 | 5 | [tool.flit.module] 6 | name = "autodoc2" 7 | 8 | [project] 9 | name = "sphinx-autodoc2" 10 | dynamic = ["version", "description"] 11 | authors = [{name = "Chris Sewell", email = "chrisj_sewell@hotmail.com"}] 12 | license = {file = "LICENSE"} 13 | classifiers = [ 14 | "License :: OSI Approved :: MIT License", 15 | "Programming Language :: Python :: 3", 16 | "Framework :: Sphinx :: Extension", 17 | ] 18 | readme = "README.md" 19 | keywords = ["sphinx", "autodoc", "extension", "documentation"] 20 | urls = {Home = "https://github.com/chrisjsewell/sphinx-autodoc2"} 21 | requires-python = ">=3.8" 22 | dependencies = [ 23 | "astroid>=2.7,<4", 24 | "tomli; python_version<'3.11'", 25 | "typing-extensions" 26 | ] 27 | 28 | [project.optional-dependencies] 29 | cli = ["typer[all]"] 30 | # we don't put a hard dependency on sphinx, 31 | # because anyway the core can be run without it 32 | sphinx = ["sphinx>=4.0.0"] 33 | testing = [ 34 | "pytest", 35 | "pytest-regressions", 36 | "pytest-cov", 37 | "sphinx>=4.0.0,<7", 38 | ] 39 | docs = [ 40 | "sphinx>=4.0.0", 41 | "furo", 42 | "myst-parser" 43 | ] 44 | 45 | [project.scripts] 46 | autodoc2 = "autodoc2.cli:app_main" 47 | 48 | [tool.ruff.lint] 49 | extend-select = [ 50 | "B", # flake8-bugbear 51 | "C4", # flake8-comprehensions 52 | "I", # isort 53 | "ICN", # flake8-import-conventions 54 | "ISC", # flake8-implicit-str-concat 55 | "N", # pep8-naming 56 | "PERF", # perflint (performance anti-patterns) 57 | "PGH", # pygrep-hooks 58 | "PIE", # flake8-pie 59 | "PTH", # flake8-use-pathlib 60 | "RUF", # Ruff-specific rules 61 | "SIM", # flake8-simplify 62 | "UP", # pyupgrade 63 | "T20", # flake8-print 64 | ] 65 | extend-ignore = ["ISC001", "PERF203", "PGH003"] 66 | 67 | [tool.ruff.lint.per-file-ignores] 68 | # ignore: Do not perform function call `typer.Option` in argument defaults 69 | "src/autodoc2/cli.py" = ["B008"] 70 | "tests/test_analyse_module.py" = ["E501"] 71 | 72 | [tool.ruff.lint.isort] 73 | force-sort-within-sections = true 74 | 75 | [tool.mypy] 76 | show_error_codes = true 77 | strict = true 78 | exclude = ['^tests/.*'] 79 | 80 | [[tool.mypy.overrides]] 81 | module = [ 82 | "astroid.*", # https://github.com/PyCQA/astroid/issues/1287 83 | "docutils.*", 84 | "tomllib.*", 85 | "tomli.*", 86 | ] 87 | ignore_missing_imports = true 88 | 89 | [[tool.mypy.overrides]] 90 | module = ["autodoc2.sphinx.autodoc"] 91 | # the try/except for tomllib/tomli causes different behaviour 92 | # on different python versions 93 | warn_unused_ignores = false 94 | 95 | [tool.pytest.ini_options] 96 | testpaths = [ 97 | "tests", 98 | ] 99 | 100 | [tool.tox] 101 | legacy_tox_ini = """ 102 | [tox] 103 | envlist = py38 104 | 105 | [testenv] 106 | usedevelop = true 107 | 108 | [testenv:py{38,39,310,311}] 109 | extras = 110 | testing 111 | commands = pytest {posargs} 112 | 113 | [testenv:cli-py{38,39,310,311}] 114 | extras = cli 115 | commands = autodoc2 {posargs} 116 | 117 | [testenv:docs] 118 | extras = docs 119 | passenv = 120 | TERM 121 | allowlist_externals = echo 122 | commands = sphinx-build {posargs} -nW --keep-going -b html -d docs/_build/doctrees docs docs/_build/html 123 | commands_post = echo "Documentation available at: docs/_build/html/index.html" 124 | """ 125 | -------------------------------------------------------------------------------- /src/autodoc2/__init__.py: -------------------------------------------------------------------------------- 1 | """Analyse a python project and create documentation for it.""" 2 | 3 | __version__ = "0.5.0" 4 | 5 | 6 | def setup(app): # type: ignore 7 | """Entrypoint for sphinx.""" 8 | from .sphinx.extension import setup as _setup 9 | 10 | return _setup(app) 11 | -------------------------------------------------------------------------------- /src/autodoc2/cli.py: -------------------------------------------------------------------------------- 1 | """CLI for the package.""" 2 | 3 | from pathlib import Path 4 | import re 5 | import typing as t 6 | 7 | from rich import progress as rp 8 | from rich.console import Console 9 | import typer 10 | 11 | from autodoc2 import __name__ as package_name 12 | from autodoc2 import __version__ 13 | from autodoc2.analysis import analyse_module 14 | from autodoc2.config import Config 15 | from autodoc2.db import InMemoryDb, UniqueError 16 | from autodoc2.resolve_all import AllResolver 17 | from autodoc2.utils import WarningSubtypes, yield_modules 18 | 19 | console = Console() 20 | 21 | 22 | app_main = typer.Typer( 23 | context_settings={"help_option_names": ["-h", "--help"]}, 24 | rich_markup_mode="rich", 25 | no_args_is_help=True, 26 | ) 27 | 28 | 29 | def version_callback(value: bool) -> None: 30 | """Print the version and exit.""" 31 | if value: 32 | console.print(f"{package_name} version: {__version__}") 33 | raise typer.Exit() 34 | 35 | 36 | @app_main.callback() 37 | def main_app( 38 | version: t.Optional[bool] = typer.Option( 39 | None, 40 | "-v", 41 | "--version", 42 | callback=version_callback, 43 | is_eager=True, 44 | help="Show the application version and exit.", 45 | ), 46 | ) -> None: 47 | """[underline]CLI for sphinx-autodoc2[/underline]""" 48 | 49 | 50 | @app_main.command("list") 51 | def list_items( 52 | path: Path = typer.Argument(..., exists=True, help="Path to analyse"), 53 | module: t.Optional[str] = typer.Option( 54 | None, 55 | "-m", 56 | "--module", 57 | help="The name of the module, otherwise it will be guessed from the path", 58 | ), 59 | inherited: bool = typer.Option( 60 | False, "-i", "--inherited", help="Show inherited members" 61 | ), 62 | private: bool = typer.Option(False, "-p", "--private", help="Show private members"), 63 | one_line: bool = typer.Option( 64 | False, "-o", "--one-line", help="Show only full name and type" 65 | ), 66 | filter_types_str: t.Optional[str] = typer.Option( 67 | None, 68 | "-ft", 69 | "--filter-types", 70 | help="Only show members of types (comma separated)", 71 | ), 72 | skip_types_str: str = typer.Option( 73 | "import_from", 74 | "-st", 75 | "--skip-types", 76 | help="Do not show members of types (comma separated)", 77 | ), 78 | filter_name: t.Optional[str] = typer.Option( 79 | None, "-fn", "--filter-name", help="Only show members with this name regex" 80 | ), 81 | ) -> None: 82 | """Analyse a python module or package and stream the results to the console.""" 83 | # initialise filters 84 | skip_types = skip_types_str.split(",") 85 | filter_types = filter_types_str.split(",") if filter_types_str else None 86 | filter_name_func: t.Callable[[str], bool] = ( 87 | re.compile(filter_name).match if filter_name else lambda _: True # type: ignore 88 | ) 89 | 90 | # gather the modules 91 | modules: t.Iterable[t.Tuple[Path, str]] 92 | if path.is_dir(): 93 | root_module = module or path.name 94 | modules = yield_modules(path, root_module=root_module) 95 | else: 96 | root_module = module or path.stem 97 | modules = [(path, root_module)] 98 | 99 | for mod_path, mod_name in modules: 100 | for data in analyse_module(mod_path, mod_name): 101 | if not filter_name_func(data["full_name"]): 102 | continue 103 | if data["type"] in skip_types or ( 104 | filter_types and data["type"] not in filter_types 105 | ): 106 | continue 107 | if not inherited and data.get("inherited", None): 108 | continue 109 | if not private and data["full_name"].split(".")[-1].startswith("_"): 110 | continue 111 | if one_line: 112 | console.print(f'{data["full_name"]} ({data["type"]})') 113 | else: 114 | console.print(data) 115 | 116 | 117 | @app_main.command("create-db") 118 | def create_db( 119 | path: Path = typer.Argument(..., exists=True, help="Path to analyse"), 120 | output: Path = typer.Argument("autodoc.db.json", help="File to write to"), 121 | module: t.Optional[str] = typer.Option( 122 | None, 123 | "-m", 124 | "--module", 125 | help="The name of the module, otherwise it will be guessed from the path", 126 | ), 127 | ) -> None: 128 | """Create a database for a python module or package.""" 129 | # gather the modules 130 | modules: t.Iterable[t.Tuple[Path, str]] 131 | if path.is_dir(): 132 | root_module = module or path.name 133 | modules = list(yield_modules(path, root_module=root_module)) 134 | else: 135 | root_module = module or path.stem 136 | modules = [(path, root_module)] 137 | 138 | # analyse the modules and write to the database 139 | db = InMemoryDb() 140 | with rp.Progress( 141 | rp.TextColumn("[bold]Analyse[/bold]"), 142 | rp.BarColumn(), 143 | rp.TaskProgressColumn(), 144 | rp.TimeElapsedColumn(), 145 | rp.TextColumn("[progress.description]{task.description}"), 146 | ) as progress: 147 | task = progress.add_task("", total=len(modules)) 148 | for mod_path, mod_name in modules: 149 | progress.update(task, description=mod_name) 150 | for data in analyse_module(mod_path, mod_name): 151 | try: 152 | db.add(data) 153 | except UniqueError: 154 | progress.console.print( 155 | f"[yellow]Warning[/yellow] Duplicate item {data['full_name']} ({data['type']})" 156 | ) 157 | progress.advance(task) 158 | 159 | # write the database to file 160 | with output.open("w") as f: 161 | db.write(f) 162 | console.print(f"[green]Database written[/green]: {output}") 163 | 164 | 165 | @app_main.command("resolve-all") 166 | def analyse_all( 167 | path: Path = typer.Argument(..., exists=True, help="Path to a database file"), 168 | package: str = typer.Argument( 169 | ..., 170 | help="The name of the package to resolve.", 171 | ), 172 | ) -> None: 173 | """Analyse the __all__ of a module and find potential matches""" 174 | with path.open("r") as f: 175 | db = InMemoryDb.read(f) 176 | 177 | resolver = AllResolver( 178 | db, lambda x: console.print(f"[yellow]Warning[/yellow]: {x}") 179 | ) 180 | 181 | data = resolver.get_resolved_all(package) 182 | 183 | console.print(data) 184 | 185 | console.print("") 186 | console.print("[green]Done![/green]") 187 | 188 | 189 | @app_main.command("write") 190 | def write( 191 | path: Path = typer.Argument(..., exists=True, help="Path to analyse"), 192 | module: t.Optional[str] = typer.Option( 193 | None, 194 | "-m", 195 | "--module", 196 | help="The name of the module, otherwise it will be guessed from the path", 197 | ), 198 | # TODO read from config file, to populate config object 199 | output: Path = typer.Option("_autodoc", help="Folder to write to"), 200 | clean: bool = typer.Option(False, "-c", "--clean", help="Remove old files"), 201 | ) -> None: 202 | """Create sphinx files for a python module or package.""" 203 | # gather the module 204 | modules: t.Iterable[t.Tuple[Path, str]] 205 | if path.is_dir(): 206 | root_module = module or path.name 207 | modules = list(yield_modules(path, root_module=root_module)) 208 | else: 209 | root_module = module or path.stem 210 | modules = [(path, root_module)] 211 | 212 | # analyse the modules and write to the database 213 | db = InMemoryDb() 214 | with rp.Progress( 215 | rp.TextColumn("[bold]Analyse[/bold]"), 216 | rp.BarColumn(), 217 | rp.TaskProgressColumn(), 218 | rp.TimeElapsedColumn(), 219 | rp.TextColumn("[progress.description]{task.description}"), 220 | ) as progress: 221 | task = progress.add_task("", total=len(modules)) 222 | for mod_path, mod_name in modules: 223 | progress.update(task, advance=1, description=mod_name) 224 | for data in analyse_module(mod_path, mod_name): 225 | try: 226 | db.add(data) 227 | except UniqueError: 228 | progress.console.print( 229 | f"[yellow]Warning[/yellow] Duplicate item {data['full_name']} ({data['type']})" 230 | ) 231 | 232 | # find all the package/module, so we know what files to write 233 | # To following __all__ strategy 234 | console.print("Determining files to write...") 235 | to_write: t.List[str] = [] 236 | stack = [root_module] 237 | while stack: 238 | item = stack.pop() 239 | to_write.append(item) 240 | stack.extend(list(db.get_children_names(item, {"package", "module"}))) 241 | 242 | # write the files 243 | output.mkdir(parents=True, exist_ok=True) 244 | paths = [] 245 | with rp.Progress( 246 | rp.TextColumn("[bold]Write[/bold]"), 247 | rp.BarColumn(), 248 | rp.TaskProgressColumn(), 249 | rp.TimeElapsedColumn(), 250 | rp.TextColumn("[progress.description]{task.description}"), 251 | ) as progress: 252 | task = progress.add_task("", total=len(to_write)) 253 | 254 | def _warn(msg: str, type_: WarningSubtypes) -> None: 255 | progress.console.print(f"[yellow]Warning[/yellow] {msg} [{type_.value}]") 256 | 257 | config = Config() 258 | for mod_name in to_write: 259 | progress.update(task, advance=1, description=mod_name) 260 | content = "\n".join( 261 | config.render_plugin(db, config, warn=_warn).render_item(mod_name) 262 | ) 263 | out_path = output / (mod_name + config.render_plugin.EXTENSION) 264 | paths.append(out_path) 265 | if out_path.exists() and out_path.read_text("utf8") == content: 266 | # Don't write the file if it hasn't changed 267 | # this means that sphinx doesn't mark it for rebuild (mtime based) 268 | continue 269 | out_path.write_text(content, "utf8") 270 | 271 | # remove any files that are no longer needed 272 | if clean: 273 | console.print("[bold]Cleaning old files[/bold]") 274 | for path in output.iterdir(): 275 | if path.is_dir(): 276 | continue 277 | if path not in paths: 278 | path.unlink() 279 | 280 | console.print("[bold green]Success![/bold green]") 281 | console.print(f"Files written to: {output}") 282 | -------------------------------------------------------------------------------- /src/autodoc2/db.py: -------------------------------------------------------------------------------- 1 | """A database interface for storing and querying the analysis items.""" 2 | 3 | from __future__ import annotations 4 | 5 | import json 6 | import re 7 | import typing as t 8 | 9 | if t.TYPE_CHECKING: 10 | from .utils import ItemData 11 | 12 | 13 | class UniqueError(KeyError): 14 | """An error raised when a unique constraint is violated.""" 15 | 16 | 17 | class Database(t.Protocol): 18 | """A simple interface for storing and querying the analysis items, from a single package. 19 | 20 | This allows for potential extensibility in the future, 21 | e.g. using a persistent sqlite database. 22 | """ 23 | 24 | def add(self, item: ItemData) -> None: 25 | """Add an item to the database.""" 26 | 27 | def remove(self, full_name: str, descendants: bool) -> None: 28 | """Remove an item from the database, by full_name. 29 | 30 | If `descendants` is True, remove all descendants of this item. 31 | """ 32 | 33 | def __contains__(self, full_name: str) -> bool: 34 | """Check if an item is in the database, by full_name.""" 35 | 36 | def get_item(self, full_name: str) -> ItemData | None: 37 | """Get an item from the database, by full_name.""" 38 | 39 | def get_items_like(self, full_name: str) -> t.Iterable[ItemData]: 40 | """Get an item from the database, matching the wildcards `*` and `?`. 41 | 42 | `*` matches any number of characters, and `?` matches any single character. 43 | """ 44 | 45 | def get_type(self, full_name: str) -> None | str: 46 | """Get the type of an item from the database, by full_name.""" 47 | 48 | def get_by_type(self, type_: str) -> t.Iterable[ItemData]: 49 | """Get all items from the database, by type.""" 50 | 51 | def get_overloads(self, full_name: str) -> t.Iterable[ItemData]: 52 | """Get all function overloads for this name.""" 53 | 54 | def get_children( 55 | self, full_name: str, types: None | set[str] = None, *, sort_name: bool = False 56 | ) -> t.Iterable[ItemData]: 57 | """Get all items that are direct children of this name, i.e. `{full_name}.{name}`. 58 | 59 | :param full_name: The full name of the item. 60 | :param types: If given, only return items of these types. 61 | :param sort_name: If True, sort the names alphabetically. 62 | """ 63 | 64 | def get_children_names( 65 | self, full_name: str, types: None | set[str] = None, *, sort_name: bool = False 66 | ) -> t.Iterable[str]: 67 | """Get all names of direct children of this name, i.e. `{full_name}.{name}`. 68 | 69 | :param full_name: The full name of the item. 70 | :param types: If given, only return items of these types. 71 | :param sort_name: If True, sort the names alphabetically. 72 | """ 73 | 74 | def get_ancestors( 75 | self, full_name: str, include_self: bool 76 | ) -> t.Iterable[ItemData | None]: 77 | """Get all ancestors of this name, e.g. `a.b`, `a` for `a.b.c`. 78 | 79 | The order is guaranteed from closest to furthest ancestor. 80 | 81 | :param full_name: The full name of the item. 82 | :param include_self: If True, include the item itself. 83 | """ 84 | 85 | 86 | _LIKE_REGEX = re.compile(r"([\*\?])") 87 | 88 | 89 | class InMemoryDb(Database): 90 | """A simple in-memory database for storing and querying the analysis items.""" 91 | 92 | def __init__(self) -> None: 93 | """Create the database.""" 94 | self._items: dict[str, ItemData] = {} 95 | self._overloads: dict[str, list[ItemData]] = {} 96 | 97 | def add(self, item: ItemData) -> None: 98 | if item["type"] == "overload": 99 | # note we do this here and not in the analyser, 100 | # because overloads come before the function they overload 101 | # and we don't want the analyzer to have to "look ahead" 102 | self._overloads.setdefault(item["full_name"], []).append(item) 103 | return 104 | if item["full_name"] in self._items: 105 | raise UniqueError(f"Item {item['full_name']} already exists") 106 | self._items[item["full_name"]] = item 107 | 108 | def remove(self, full_name: str, descendants: bool) -> None: 109 | # remove the item itself 110 | self._items.pop(full_name, None) 111 | self._overloads.pop(full_name, None) 112 | if descendants: 113 | # remove all descendants 114 | for name in list(self._items): 115 | if name.startswith(full_name + "."): 116 | self._items.pop(name, None) 117 | self._overloads.pop(name, None) 118 | 119 | def __contains__(self, full_name: str) -> bool: 120 | return full_name in self._items 121 | 122 | def get_item(self, full_name: str) -> ItemData | None: 123 | return self._items.get(full_name) 124 | 125 | def get_items_like(self, full_name: str) -> t.Iterable[ItemData]: 126 | parts = _LIKE_REGEX.split(full_name) 127 | pattern = re.compile( 128 | "".join( 129 | [ 130 | ".*" if part == "*" else ("." if part == "?" else re.escape(part)) 131 | for part in parts 132 | ] 133 | ) 134 | ) 135 | return ( 136 | item 137 | for item in self._items.values() 138 | if pattern.fullmatch(item["full_name"]) 139 | ) 140 | 141 | def get_type(self, full_name: str) -> None | str: 142 | item = self._items.get(full_name) 143 | if item is None: 144 | return None 145 | return item["type"] 146 | 147 | def get_by_type(self, type_: str) -> t.Iterable[ItemData]: 148 | return (item for item in self._items.values() if item["type"] == type_) 149 | 150 | def get_overloads(self, full_name: str) -> t.Iterable[ItemData]: 151 | return self._overloads.get(full_name, []) 152 | 153 | def get_children( 154 | self, full_name: str, types: None | set[str] = None, *, sort_name: bool = False 155 | ) -> t.Iterable[ItemData]: 156 | generator = ( 157 | item 158 | for item in self._items.values() 159 | if item["full_name"].startswith(full_name + ".") 160 | and "." not in item["full_name"][len(full_name) + 1 :] 161 | and ((types is None) or (item["type"] in types)) 162 | ) 163 | if sort_name: 164 | return sorted(generator, key=lambda item: item["full_name"]) 165 | return generator 166 | 167 | def get_children_names( 168 | self, full_name: str, types: None | set[str] = None, *, sort_name: bool = False 169 | ) -> t.Iterable[str]: 170 | generator = ( 171 | item["full_name"] 172 | for item in self._items.values() 173 | if item["full_name"].startswith(full_name + ".") 174 | and "." not in item["full_name"][len(full_name) + 1 :] 175 | and ((types is None) or (item["type"] in types)) 176 | ) 177 | if sort_name: 178 | return sorted(generator) 179 | return generator 180 | 181 | def get_ancestors( 182 | self, full_name: str, include_self: bool 183 | ) -> t.Iterable[ItemData | None]: 184 | if include_self: 185 | yield self.get_item(full_name) 186 | parts = full_name.split(".")[:-1] 187 | while parts: 188 | yield self.get_item(".".join(parts)) 189 | parts.pop() 190 | 191 | def write(self, stream: t.TextIO) -> None: 192 | """Write the database to a file.""" 193 | json.dump({"items": self._items, "overloads": self._overloads}, stream) 194 | 195 | @classmethod 196 | def read(cls, stream: t.TextIO) -> InMemoryDb: 197 | """Read the database from a file.""" 198 | items = json.load(stream) 199 | db = cls() 200 | db._items = items["items"] 201 | db._overloads = items["overloads"] 202 | return db 203 | -------------------------------------------------------------------------------- /src/autodoc2/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sphinx-extensions2/sphinx-autodoc2/1f55a8872cccd235cafa6323e2ae8c3a563156f4/src/autodoc2/py.typed -------------------------------------------------------------------------------- /src/autodoc2/render/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sphinx-extensions2/sphinx-autodoc2/1f55a8872cccd235cafa6323e2ae8c3a563156f4/src/autodoc2/render/__init__.py -------------------------------------------------------------------------------- /src/autodoc2/resolve_all.py: -------------------------------------------------------------------------------- 1 | """Handling of ``__all__`` resolution.""" 2 | 3 | from __future__ import annotations 4 | 5 | import typing as t 6 | 7 | from autodoc2.db import Database 8 | 9 | 10 | class AllResolutionError(Exception): 11 | """An error occurred while resolving the ``__all__``.""" 12 | 13 | 14 | class ObjectMissingError(AllResolutionError): 15 | """An object in the ``__all__`` is not available in the database.""" 16 | 17 | 18 | class CircularImportError(AllResolutionError): 19 | """A circular import was detected.""" 20 | 21 | 22 | class NoAllError(AllResolutionError): 23 | """The module does not have an ``__all__``.""" 24 | 25 | 26 | class AllResolveResult(t.TypedDict): 27 | resolved: dict[str, str] 28 | """Resolved is a dict of ``{full_name: {name}}``""" 29 | errors: list[tuple[str, str]] 30 | """Errors are tuples of ``(full_name, error_message)``""" 31 | 32 | 33 | class AllResolver: 34 | def __init__( 35 | self, db: Database, warn_func: t.Callable[[str], None] | None = None 36 | ) -> None: 37 | """Initialise the resolver. 38 | 39 | :param db: the database to use 40 | :param warn_func: a function to call with warnings 41 | """ 42 | self._db = db 43 | self._warn_func = (lambda x: None) if warn_func is None else warn_func 44 | self._resolve_cache: dict[str, AllResolveResult] = {} 45 | 46 | def clear_cache(self) -> None: 47 | """Clear the cache.""" 48 | self._resolve_cache = {} 49 | 50 | def get_resolved_all( 51 | self, full_name: str, _breadcrumbs: tuple[str, ...] = () 52 | ) -> AllResolveResult: 53 | """Yield all names that would be imported by star. 54 | 55 | :param full_name: the fully qualified name of the module 56 | :param _breadcrumbs: used to detect circular imports 57 | """ 58 | if full_name in self._resolve_cache: 59 | return self._resolve_cache[full_name] 60 | if full_name in self._resolve_cache: 61 | return self._resolve_cache[full_name] 62 | if full_name in _breadcrumbs: 63 | raise CircularImportError( 64 | f"Circular import detected: {full_name} -> {_breadcrumbs}" 65 | ) 66 | if (item := self._db.get_item(full_name)) is None: 67 | raise ObjectMissingError(full_name) 68 | if (all_list := item.get("all")) is None: 69 | raise NoAllError(f"{full_name!r} does not have an __all__") 70 | 71 | resolved: dict[str, set[str]] = {name: set() for name in all_list} 72 | errors: list[tuple[str, str]] = [] 73 | 74 | # direct children 75 | for name in all_list: 76 | if f"{full_name}.{name}" in self._db: 77 | resolved[name].add(f"{full_name}.{name}") 78 | 79 | # direct imports 80 | star_imports: list[str] = [] 81 | for import_name, alias in item.get("imports", []): 82 | final_name = alias or import_name.split(".")[-1] 83 | if final_name == "*": 84 | star_imports.append(import_name[:-2]) 85 | elif final_name in resolved: 86 | resolved[final_name].add(import_name) 87 | 88 | # star imports 89 | for import_name in star_imports: 90 | # TODO how do we "bubble up" errors? so that we can report them 91 | try: 92 | resolved_import = self.get_resolved_all( 93 | import_name, (*_breadcrumbs, full_name) 94 | ) 95 | except ObjectMissingError: 96 | errors.append((full_name, f"from {import_name} import *; is unknown")) 97 | except CircularImportError: 98 | errors.append( 99 | (full_name, f"from {import_name} import *; is a circular import") 100 | ) 101 | except NoAllError: 102 | errors.append( 103 | ( 104 | full_name, 105 | f"from {import_name} import *; does not have an __all__", 106 | ) 107 | ) 108 | else: 109 | errors.extend(resolved_import["errors"]) 110 | for name, items in resolved_import["resolved"].items(): 111 | if name in resolved: 112 | resolved[name].add(items) 113 | 114 | final_resolved: dict[str, str] = {} 115 | for name, rnames in resolved.items(): 116 | if not rnames: 117 | errors.append((full_name, f"{name!r} is unknown")) 118 | elif len(rnames) > 1: 119 | errors.append((full_name, f"{name!r} is ambiguous: {rnames}")) 120 | else: 121 | final_resolved[name] = rnames.pop() 122 | 123 | for error in errors: 124 | self._warn_func(f"{full_name}: {error[0]}: {error[1]}") 125 | 126 | self._resolve_cache[full_name] = { 127 | "resolved": final_resolved, 128 | "errors": errors, 129 | } 130 | return self._resolve_cache[full_name] 131 | 132 | def get_name(self, name: str) -> str | None: 133 | """Get the item, first by trying the fully qualified name, 134 | then by looking at __all__ in parent modules. 135 | """ 136 | if name in self._db: 137 | return name 138 | 139 | parts = name.split(".") 140 | if len(parts) < 2: 141 | return None 142 | 143 | parent, child = ".".join(parts[:-1]), parts[-1] 144 | try: 145 | resolved = self.get_resolved_all(parent) 146 | except AllResolutionError: 147 | return None 148 | return resolved["resolved"].get(child, None) 149 | -------------------------------------------------------------------------------- /src/autodoc2/sphinx/__init__.py: -------------------------------------------------------------------------------- 1 | """Module for Sphinx integration.""" 2 | -------------------------------------------------------------------------------- /src/autodoc2/sphinx/autodoc.py: -------------------------------------------------------------------------------- 1 | """autodoc directive for sphinx.""" 2 | 3 | from __future__ import annotations 4 | 5 | from contextlib import contextmanager 6 | import typing as t 7 | 8 | from docutils import nodes 9 | from docutils.parsers.rst import directives 10 | from sphinx.environment import BuildEnvironment 11 | from sphinx.util.docutils import SphinxDirective 12 | 13 | from autodoc2.sphinx.utils import ( 14 | get_all_analyser, 15 | get_database, 16 | load_config, 17 | nested_parse_generated, 18 | warn_sphinx, 19 | ) 20 | from autodoc2.utils import ItemData, WarningSubtypes 21 | 22 | try: 23 | import tomllib 24 | except ImportError: 25 | # python < 3.11 26 | import tomli as tomllib # type: ignore 27 | 28 | 29 | class AutodocObject(SphinxDirective): 30 | """Directive to render a docstring of an object.""" 31 | 32 | required_arguments = 1 # the full name 33 | final_argument_whitespace = False 34 | has_content = True 35 | 36 | # TODO autogenerate this from the config 37 | option_spec: t.ClassVar[dict[str, t.Any]] = { 38 | "literal": directives.flag, # return the literal render string 39 | "literal-lexer": directives.unchanged, # the lexer to use for literal 40 | } 41 | 42 | def run(self) -> list[nodes.Node]: 43 | source, line = self.get_source_info() 44 | # warnings take the docname and line number 45 | warning_loc = (self.env.docname, line) 46 | 47 | full_name = self.arguments[0] 48 | autodoc2_db = get_database(self.env) 49 | 50 | if full_name not in autodoc2_db: 51 | warn_sphinx( 52 | f"Could not find {full_name}", 53 | WarningSubtypes.NAME_NOT_FOUND, 54 | location=warning_loc, 55 | ) 56 | return [] 57 | 58 | # find the parent class/module 59 | mod_parent = None 60 | class_parent = None 61 | for ancestor in autodoc2_db.get_ancestors(full_name, include_self=True): 62 | if ancestor is None: 63 | break # should never happen 64 | if class_parent is None and ancestor["type"] == "class": 65 | class_parent = ancestor 66 | if ancestor["type"] in ("module", "package"): 67 | mod_parent = ancestor 68 | break 69 | 70 | if mod_parent is None: 71 | warn_sphinx( 72 | f"Could not find parent module {full_name}", 73 | WarningSubtypes.NAME_NOT_FOUND, 74 | location=warning_loc, 75 | ) 76 | return [] 77 | 78 | # ensure rebuilds when the source file changes 79 | file_path = mod_parent.get("file_path") 80 | if file_path: 81 | self.env.note_dependency(file_path) 82 | 83 | # load the configuration with overrides 84 | overrides = {} 85 | try: 86 | overrides = tomllib.loads("\n".join(self.content)) if self.content else {} 87 | except Exception as err: 88 | warn_sphinx( 89 | f"Could not parse TOML config: {err}", 90 | WarningSubtypes.CONFIG_ERROR, 91 | location=warning_loc, 92 | ) 93 | config = load_config(self.env.app, overrides=overrides, location=warning_loc) 94 | 95 | # setup warnings 96 | def _warn_render(msg: str, type_: WarningSubtypes) -> None: 97 | warn_sphinx(msg, type_, location=warning_loc) 98 | 99 | # create the content from the renderer 100 | content = list( 101 | config.render_plugin( 102 | autodoc2_db, 103 | config, 104 | all_resolver=get_all_analyser(self.env), 105 | warn=_warn_render, 106 | standalone=True, 107 | ).render_item(full_name) 108 | ) 109 | 110 | if "literal" in self.options: 111 | literal = nodes.literal_block(text="\n".join(content)) 112 | self.set_source_info(literal) 113 | if "literal-lexer" in self.options: 114 | literal["language"] = self.options["literal-lexer"] 115 | return [literal] 116 | 117 | with _set_parents(self.env, mod_parent, class_parent): 118 | base = nested_parse_generated( 119 | self.state, 120 | content, 121 | source, 122 | line, 123 | match_titles=True, # TODO 124 | ) 125 | 126 | return base.children or [] 127 | 128 | 129 | @contextmanager 130 | def _set_parents( 131 | env: BuildEnvironment, mod: ItemData, klass: ItemData | None 132 | ) -> t.Generator[None, None, None]: 133 | """Ensure we setup the correct parent 134 | This allows sphinx to properly process the `py` directives. 135 | """ 136 | current_module = env.ref_context.get("py:module") 137 | current_class = env.ref_context.get("py:class") 138 | env.ref_context["py:module"] = mod["full_name"] 139 | if klass: 140 | env.ref_context["py:class"] = klass["full_name"] 141 | try: 142 | yield 143 | finally: 144 | env.ref_context["py:module"] = current_module 145 | env.ref_context["py:class"] = current_class 146 | -------------------------------------------------------------------------------- /src/autodoc2/sphinx/docstring.py: -------------------------------------------------------------------------------- 1 | """Directive for rendering docstrings.""" 2 | 3 | from __future__ import annotations 4 | 5 | from contextlib import contextmanager 6 | import typing as t 7 | 8 | from docutils import nodes 9 | from docutils.parsers import Parser, get_parser_class 10 | from docutils.parsers.rst import directives, roles 11 | from docutils.statemachine import StringList 12 | from sphinx.util.docutils import SphinxDirective, new_document 13 | from sphinx.util.logging import prefixed_warnings 14 | 15 | from autodoc2.sphinx.utils import get_database, nested_parse_generated, warn_sphinx 16 | from autodoc2.utils import WarningSubtypes 17 | 18 | if t.TYPE_CHECKING: 19 | from docutils.parsers.rst.states import RSTStateMachine 20 | 21 | 22 | def parser_options(argument: str) -> Parser | None: 23 | """ 24 | Return a docutils parser whose name matches the argument. 25 | (Directive option conversion function.) 26 | 27 | Return `None`, if the argument evaluates to `False`. 28 | Raise `ValueError` if importing the parser module fails. 29 | """ 30 | if not argument or not argument.strip(): 31 | return None 32 | if argument in ("myst", "markdown", "md"): 33 | # we want to use the sphinx parser, not the docutils one 34 | argument = "myst_parser.sphinx_" 35 | try: 36 | return get_parser_class(argument) 37 | except ImportError as err: 38 | raise ValueError(str(err)) from err 39 | 40 | 41 | def summary_option(argument: str) -> int | None: 42 | """Must be empty or a positive integer.""" 43 | if argument and argument.strip(): 44 | try: 45 | value = int(argument) 46 | except ValueError as err: 47 | raise ValueError("non-integer value; must be an integer") from err 48 | if value < 0: 49 | raise ValueError("negative value; must be positive or zero") 50 | return value 51 | else: 52 | return None 53 | 54 | 55 | class DocstringRenderer(SphinxDirective): 56 | """Directive to render a docstring of an object.""" 57 | 58 | has_content = False 59 | required_arguments = 1 # the full name 60 | optional_arguments = 0 61 | final_argument_whitespace = True 62 | option_spec: t.ClassVar[dict[str, t.Any]] = { 63 | "parser": parser_options, 64 | "allowtitles": directives.flag, # used for module docstrings 65 | "summary": summary_option, # number of children to return 66 | "literal": directives.flag, # return the literal docstring 67 | "literal-lexer": directives.unchanged, # the lexer to use for literal 68 | "literal-linenos": directives.flag, # add line numbers to literal 69 | } 70 | 71 | def run(self) -> list[nodes.Node]: 72 | """Run the directive {a}`1`.""" 73 | directive_source, directive_line = self.get_source_info() 74 | # warnings take the docname and line number 75 | warning_loc = (self.env.docname, directive_line) 76 | 77 | # find the database item for this object 78 | full_name: str = self.arguments[0] 79 | autodoc2_db = get_database(self.env) 80 | item = autodoc2_db.get_item(full_name) 81 | 82 | if item is None: 83 | if "summary" not in self.options: 84 | # summaries can include items imported from external modules 85 | # which may not be in the database, so we don't warn about those 86 | warn_sphinx( 87 | f"Could not find {full_name}", 88 | WarningSubtypes.NAME_NOT_FOUND, 89 | location=warning_loc, 90 | ) 91 | return [] 92 | 93 | # find the source path for this object, by walking up the parent tree 94 | source_name = item["doc_inherited"] if item.get("doc_inherited") else full_name 95 | source_path: str | None = None 96 | for ancestor in autodoc2_db.get_ancestors(source_name, include_self=True): 97 | if ancestor is None: 98 | break # should never happen 99 | if "file_path" in ancestor: 100 | source_path = ancestor["file_path"] 101 | break 102 | source_item = autodoc2_db.get_item(source_name) 103 | # also get the line number within the file 104 | source_offset = ( 105 | source_item["range"][0] if source_item and ("range" in source_item) else 0 106 | ) 107 | 108 | if source_path: 109 | # ensure rebuilds when the source file changes 110 | self.env.note_dependency(source_path) 111 | 112 | if not item["doc"].strip(): 113 | return [] 114 | 115 | if "literal" in self.options: 116 | # return the literal docstring 117 | literal = nodes.literal_block(text=item["doc"]) 118 | self.set_source_info(literal) 119 | if "literal-lexer" in self.options: 120 | literal["language"] = self.options["literal-lexer"] 121 | if "literal-linenos" in self.options: 122 | literal["linenos"] = True 123 | literal["highlight_args"] = {"linenostart": 1 + source_offset} 124 | return [literal] 125 | 126 | # now we run the actual parsing 127 | # here things get a little tricky: 128 | # 1. We want to parse the docstring according to the correct parser, 129 | # which, may not be the same as the current parser. 130 | # 2. We want to set the source path and line number correctly 131 | # so that warnings and errors are reported against the actual source documentation. 132 | 133 | with prefixed_warnings("[Autodoc2]:"): 134 | if self.options.get("parser", None): 135 | # parse into a dummy document and return created nodes 136 | parser: Parser = self.options["parser"]() 137 | document = new_document( 138 | source_path or self.state.document["source"], 139 | self.state.document.settings, 140 | ) 141 | document.reporter.get_source_and_line = lambda li: ( 142 | source_path, 143 | li + source_offset, 144 | ) 145 | with parsing_context(): 146 | parser.parse(item["doc"], document) 147 | children = document.children or [] 148 | 149 | else: 150 | doc_lines = item["doc"].splitlines() 151 | if source_path: 152 | # Here we perform a nested render, but temporarily setup the document/reporter 153 | # with the correct document path and lineno for the included file. 154 | with change_source( 155 | self.state, source_path, source_offset - directive_line 156 | ): 157 | base = nodes.Element() 158 | base.source = source_path 159 | base.line = source_offset 160 | content = StringList( 161 | doc_lines, 162 | source=source_path, 163 | items=[ 164 | (source_path, i + source_offset + 1) 165 | for i in range(len(doc_lines)) 166 | ], 167 | ) 168 | self.state.nested_parse( 169 | content, 0, base, match_titles="allowtitles" in self.options 170 | ) 171 | 172 | else: 173 | base = nested_parse_generated( 174 | self.state, 175 | doc_lines, 176 | directive_source, 177 | directive_line, 178 | match_titles="allowtitles" in self.options, 179 | ) 180 | 181 | children = base.children or [] 182 | 183 | if children and ("summary" in self.options): 184 | if self.options["summary"] in (None, 1): 185 | return [children[0]] 186 | return children[: self.options["summary"]] 187 | 188 | return children 189 | 190 | 191 | @contextmanager 192 | def parsing_context() -> t.Generator[None, None, None]: 193 | """Restore the parsing context after a nested parse with a different parser.""" 194 | should_restore = False 195 | if "" in roles._roles: 196 | blankrole = roles._roles[""] 197 | try: 198 | yield 199 | finally: 200 | if should_restore: 201 | roles._roles[""] = blankrole 202 | 203 | 204 | @contextmanager 205 | def change_source( 206 | state: RSTStateMachine, source_path: str, line_offset: int 207 | ) -> t.Generator[None, None, None]: 208 | """Temporarily change the source and line number.""" 209 | # TODO also override the warning message to include the original source 210 | source = state.document["source"] 211 | rsource = state.reporter.source 212 | line_func = getattr(state.reporter, "get_source_and_line", None) 213 | try: 214 | state.document["source"] = source_path 215 | state.reporter.source = source_path 216 | state.reporter.get_source_and_line = lambda li: ( 217 | source_path, 218 | li + line_offset, 219 | ) 220 | yield 221 | finally: 222 | state.document["source"] = source 223 | state.reporter.source = rsource 224 | if line_func is not None: 225 | state.reporter.get_source_and_line = line_func 226 | else: 227 | del state.reporter.get_source_and_line 228 | 229 | 230 | def _example(a: int, b: str) -> None: 231 | """This is an example docstring, written in MyST. 232 | 233 | It has a code fence: 234 | 235 | ```python 236 | a = "hallo" 237 | ``` 238 | 239 | and a table: 240 | 241 | | a | b | c | 242 | | - | - | - | 243 | | 1 | 2 | 3 | 244 | 245 | and, using the `fieldlist` extension, a field list: 246 | 247 | :param a: the first parameter 248 | :param b: the second parameter 249 | :return: the return value 250 | 251 | """ 252 | -------------------------------------------------------------------------------- /src/autodoc2/sphinx/summary.py: -------------------------------------------------------------------------------- 1 | """Directive to generate a summary of listed objects.""" 2 | 3 | from __future__ import annotations 4 | 5 | from typing import Any, ClassVar 6 | 7 | from docutils import nodes 8 | from docutils.parsers.rst import directives 9 | from sphinx.util.docutils import SphinxDirective 10 | 11 | from autodoc2.sphinx.utils import ( 12 | get_all_analyser, 13 | get_database, 14 | load_config, 15 | nested_parse_generated, 16 | warn_sphinx, 17 | ) 18 | from autodoc2.utils import ItemData, WarningSubtypes 19 | 20 | 21 | class AutodocSummary(SphinxDirective): 22 | """Directive to generate a summary of listed objects.""" 23 | 24 | has_content = True 25 | required_arguments = 0 26 | optional_arguments = 0 27 | final_argument_whitespace = False 28 | option_spec: ClassVar[dict[str, Any]] = { 29 | "renderer": directives.unchanged_required, 30 | } 31 | 32 | def run(self) -> list[nodes.Node]: 33 | source, line = self.get_source_info() 34 | # warnings take the docname and line number 35 | warning_loc = (self.env.docname, line) 36 | 37 | all_resolver = get_all_analyser(self.env) 38 | 39 | # load the configuration 40 | overrides = {} 41 | if "renderer" in self.options: 42 | overrides = {"render_plugin": self.options["renderer"]} 43 | config = load_config(self.env.app, overrides=overrides, location=warning_loc) 44 | 45 | db = get_database(self.env) 46 | 47 | objects: list[ItemData] = [] 48 | content_line: str 49 | aliases: dict[str, str] = {} 50 | for content_idx, content_line in enumerate(self.content): 51 | parts = content_line.strip().split(maxsplit=1) 52 | if len(parts) == 0: 53 | continue 54 | full_name = parts[0] 55 | alias: str | None = None 56 | if full_name.startswith("~"): 57 | full_name = full_name[1:] 58 | alias = full_name.split(".")[-1] 59 | if len(parts) > 1: 60 | alias = parts[1] 61 | if (item := db.get_item(full_name)) is None and ( 62 | resolved_name := all_resolver.get_name(full_name) 63 | ): 64 | item = db.get_item(resolved_name) 65 | if item is not None: 66 | for ancestor in db.get_ancestors(full_name, include_self=True): 67 | if ancestor and "file_path" in ancestor: 68 | if file_path := ancestor["file_path"]: 69 | self.env.note_dependency(file_path) 70 | break 71 | if alias: 72 | aliases[item["full_name"]] = alias 73 | elif full_name != item["full_name"]: 74 | aliases[item["full_name"]] = full_name 75 | objects.append(item) 76 | else: 77 | warn_sphinx( 78 | f"Could not find {full_name}", 79 | WarningSubtypes.NAME_NOT_FOUND, 80 | location=( 81 | self.env.docname, 82 | line + self.content_offset + 1 + content_idx, 83 | ), 84 | ) 85 | 86 | if not objects: 87 | return [] 88 | 89 | # setup warnings 90 | def _warn_render(msg: str, type_: WarningSubtypes) -> None: 91 | warn_sphinx(msg, type_, location=warning_loc) 92 | 93 | # TODO it would be ideal to create this as nodes, rather than nested parsing, 94 | # but for now this is the simplest option 95 | content = list( 96 | config.render_plugin( 97 | db, 98 | config, 99 | all_resolver=all_resolver, 100 | warn=_warn_render, 101 | standalone=True, 102 | ).generate_summary(objects, alias=aliases) 103 | ) 104 | base = nested_parse_generated(self.state, content, source, line) 105 | 106 | return base.children or [] 107 | -------------------------------------------------------------------------------- /src/autodoc2/sphinx/utils.py: -------------------------------------------------------------------------------- 1 | """Handle sphinx logging.""" 2 | 3 | from __future__ import annotations 4 | 5 | import typing as t 6 | 7 | from docutils.nodes import Element 8 | from docutils.statemachine import StringList 9 | from sphinx.application import Sphinx 10 | from sphinx.environment import BuildEnvironment 11 | from sphinx.util import logging 12 | 13 | from autodoc2.config import CONFIG_PREFIX, Config, ValidationError 14 | from autodoc2.db import Database, InMemoryDb 15 | from autodoc2.resolve_all import AllResolver 16 | from autodoc2.utils import WarningSubtypes 17 | 18 | if t.TYPE_CHECKING: 19 | from docutils.parsers.rst.states import RSTStateMachine 20 | 21 | LOGGER = logging.getLogger("autodoc2") 22 | 23 | 24 | def load_config( 25 | app: Sphinx, 26 | *, 27 | overrides: None | dict[str, t.Any] = None, 28 | location: None | Element = None, 29 | ) -> Config: 30 | """Load the configuration.""" 31 | values: dict[str, t.Any] = {} 32 | overrides = overrides or {} 33 | config_fields = {name: field for name, _, field in Config().as_triple()} 34 | # check if keys in overrides are valid 35 | difference = set(overrides.keys()) - set(config_fields.keys()) 36 | if difference: 37 | warn_sphinx( 38 | f"Unknown configuration keys: {', '.join(difference)}", 39 | WarningSubtypes.CONFIG_ERROR, 40 | location, 41 | ) 42 | for name, field in config_fields.items(): 43 | sphinx_name = f"{CONFIG_PREFIX}{name}" 44 | value = overrides.get(name, app.config[sphinx_name]) 45 | if "sphinx_validate" in field.metadata: 46 | try: 47 | value = field.metadata["sphinx_validate"](sphinx_name, value) 48 | except ValidationError as err: 49 | warn_sphinx(str(err), WarningSubtypes.CONFIG_ERROR, location) 50 | continue 51 | values[name] = value 52 | return Config(**values) 53 | 54 | 55 | def warn_sphinx( 56 | msg: str, subtype: WarningSubtypes, location: None | Element = None 57 | ) -> None: 58 | """Log a warning in Sphinx.""" 59 | LOGGER.warning( 60 | f"{msg} [autodoc2.{subtype.value}]", 61 | type="autodoc2", 62 | subtype=subtype.value, 63 | location=location, 64 | ) 65 | 66 | 67 | def get_database(env: BuildEnvironment) -> Database: 68 | """Get the database from the environment.""" 69 | # We store it persistently in the environment so that it can be 70 | # accessed by directives and other extensions. 71 | if not hasattr(env, "autodoc2_db"): 72 | env.autodoc2_db = InMemoryDb() # type: ignore 73 | return env.autodoc2_db # type: ignore 74 | 75 | 76 | def _warn(msg: str) -> None: 77 | warn_sphinx(msg, WarningSubtypes.ALL_RESOLUTION) 78 | 79 | 80 | def get_all_analyser(env: BuildEnvironment) -> AllResolver: 81 | """Get the all analyser from the environment.""" 82 | # We store it persistently in the environment so that it can be 83 | # accessed by directives and other extensions. 84 | if not hasattr(env, "autodoc2_all_analyser"): 85 | env.autodoc2_all_analyser = AllResolver(get_database(env), _warn) # type: ignore 86 | return env.autodoc2_all_analyser # type: ignore 87 | 88 | 89 | def nested_parse_generated( 90 | state: RSTStateMachine, 91 | content: list[str], 92 | source: str, 93 | line: int, 94 | *, 95 | match_titles: bool = False, 96 | base: Element | None = None, 97 | ) -> Element: 98 | """This function, nested parses generated content in a directive. 99 | 100 | All reported warnings are redirected to a specific source document and line. 101 | 102 | This is useful for directives that want to parse generated content. 103 | """ 104 | base = Element() if base is None else base 105 | base.source = source 106 | base.line = line 107 | string_list = StringList( 108 | content, 109 | items=[(source, line - 1) for _ in content], 110 | ) 111 | line_func = getattr(state.reporter, "get_source_and_line", None) 112 | state.reporter.get_source_and_line = lambda li: ( 113 | source, 114 | line, 115 | ) 116 | try: 117 | state.nested_parse(string_list, 0, base, match_titles=match_titles) 118 | finally: 119 | if line_func is not None: 120 | state.reporter.get_source_and_line = line_func 121 | else: 122 | del state.reporter.get_source_and_line 123 | 124 | return base 125 | -------------------------------------------------------------------------------- /src/autodoc2/utils.py: -------------------------------------------------------------------------------- 1 | """Utility functions and types.""" 2 | 3 | from __future__ import annotations 4 | 5 | import enum 6 | from fnmatch import fnmatch 7 | import os 8 | from pathlib import Path 9 | import typing as t 10 | 11 | from typing_extensions import Required 12 | 13 | PROPERTY_TYPE = t.Literal[ 14 | "async", "staticmethod", "classmethod", "abstractmethod", "singledispatch" 15 | ] 16 | ARGS_TYPE = t.List[ 17 | t.Tuple[t.Optional[str], t.Optional[str], t.Optional[str], t.Optional[str]] 18 | ] 19 | 20 | 21 | class ItemData(t.TypedDict, total=False): 22 | """A data item, for the results of the analysis.""" 23 | 24 | type: Required[str] 25 | full_name: Required[str] # this is delimited by dots 26 | doc: Required[str] 27 | 28 | range: tuple[int, int] 29 | 30 | ## module / package 31 | file_path: None | str 32 | encoding: str 33 | all: None | list[str] 34 | imports: list[tuple[str, str | None]] # path, alias 35 | 36 | # assign (data) 37 | value: None | str | t.Any # TODO make value JSON serializable 38 | annotation: None | str 39 | 40 | # function/method/overload 41 | properties: list[PROPERTY_TYPE] 42 | args: ARGS_TYPE 43 | return_annotation: None | str 44 | 45 | # class 46 | bases: list[str] 47 | 48 | # class or method 49 | doc_inherited: str 50 | 51 | # child of class 52 | inherited: str 53 | 54 | 55 | class WarningSubtypes(enum.Enum): 56 | """The subtypes of warnings for the extension.""" 57 | 58 | CONFIG_ERROR = "config_error" 59 | """Issue with configuration validation.""" 60 | GIT_CLONE_FAILED = "git_clone" 61 | """Failed to clone a git repository.""" 62 | MISSING_MODULE = "missing_module" 63 | """If the package file/folder does not exist.""" 64 | DUPLICATE_ITEM = "dup_item" 65 | """Duplicate fully qualified name found during package analysis.""" 66 | RENDER_ERROR = "render" 67 | """Generic rendering error.""" 68 | ALL_MISSING = "all_missing" 69 | """__all__ attribute missing or empty in a module.""" 70 | ALL_RESOLUTION = "all_resolve" 71 | """Issue with resolution of an item in a module's __all__ attribute.""" 72 | NAME_NOT_FOUND = "missing" 73 | 74 | 75 | def yield_modules( 76 | folder: str | Path, 77 | *, 78 | root_module: str | None = None, 79 | extensions: t.Sequence[str] = (".py", ".pyi"), 80 | exclude_dirs: t.Sequence[str] = ("__pycache__",), 81 | exclude_files: t.Sequence[str] = (), 82 | ) -> t.Iterable[tuple[Path, str]]: 83 | """Walk the given folder and yield all required modules. 84 | 85 | :param folder: The path to walk. 86 | :param root_module: The name of the root module, 87 | otherwise the folder name is used. 88 | :param extensions: The extensions to include. 89 | If multiple files with the same stem, 90 | only the first extension will be used. 91 | :param exclude_dirs: Directory names to exclude (matched with fnmatch). 92 | :param exclude_files: File names to exclude (matched with fnmatch). 93 | """ 94 | folder = Path(folder) 95 | root_mod = (root_module or folder.name).split(".") 96 | exc_dirs = set(exclude_dirs or []) 97 | exc_files = set(exclude_files or []) 98 | 99 | def _suffix_sort_key(s: str) -> int: 100 | return extensions.index(s) 101 | 102 | for root, dirs, filenames in os.walk(folder, topdown=True): 103 | dirs[:] = [d for d in dirs if not any(fnmatch(d, m) for m in exc_dirs)] 104 | to_yield: dict[str, list[str]] = {} 105 | for filename in filenames: 106 | if any(fnmatch(filename, m) for m in exc_files): 107 | continue 108 | name, suffix = os.path.splitext(filename) # noqa: PTH122 109 | if suffix in extensions: 110 | to_yield.setdefault(name, []).append(suffix) 111 | root_path = Path(root) 112 | rel_mod = root_path.relative_to(folder).parts 113 | for name, suffixes in to_yield.items(): 114 | suffix = sorted(suffixes, key=_suffix_sort_key)[0] 115 | yield (root_path / f"{name}{suffix}", ".".join([*root_mod, *rel_mod, name])) 116 | -------------------------------------------------------------------------------- /tests/test_analyse_module.py: -------------------------------------------------------------------------------- 1 | """Basic tests for the analysis module.""" 2 | 3 | from __future__ import annotations 4 | 5 | import typing as t 6 | 7 | from autodoc2.analysis import analyse_module 8 | import pytest 9 | 10 | 11 | def clean_item(item: dict[str, t.Any]) -> dict[str, t.Any]: 12 | """Remove non-deterministic data.""" 13 | return { 14 | key: value 15 | for key, value in item.items() 16 | if key not in ("modified", "file_path", "encoding") 17 | } 18 | 19 | 20 | test_items = { 21 | # module 22 | "module_docstring": "'''Docstring'''", 23 | "module_all": "__all__ = ['a', 'b', 'c']", 24 | # annotation only assign 25 | "assign_annotation": "a: str", 26 | "assign_annotation_union": "a: str | int", 27 | # assign 28 | "assign_class": "class Foo: ...\na = Foo()", 29 | # assign with annotation 30 | "assign_string": "a: str = 'Hello World'\n'''Docstring'''", 31 | "assign_bytes": "a: bytes = b'Hello World'", 32 | "assign_int": "a: int = 42", 33 | "assign_float": "a: float = 3.14", 34 | "assign_list": "a: list = [1, 2, 3]", 35 | "assign_tuple": "a: tuple = (1, 2, 3)", 36 | "assign_dict": "a: dict[str, int] = {'a': 1, 'b': 2, 'c': 3}", 37 | "assign_set": "a: set[int] = {1, 2, 3}", 38 | "assign_with_docstring": "a: str = 'Hello World'\n'''Docstring'''", 39 | # function with annotation 40 | "func_basic": "def a() -> str: ...", 41 | "func_1arg": "def a(b: int) -> str: ...", 42 | "func_args": "def a(*b: int) -> str: ...", 43 | "func_1kwarg": "def a(*, b: int) -> str: ...", 44 | "func_kwargs": "def a(**kw: float) -> str: ...", 45 | "func_docstring": "def a() -> str:\n '''Docstring'''\n", 46 | "func_async": "async def a() -> str: ...", 47 | # class with annotation 48 | "class_basic": "class A: ...", 49 | "class_inherit": "class A(B): ...", 50 | "class_inherit_multi": "class A(B, C): ...", 51 | "class_inherit_generic": "class A(B[int]): ...", 52 | "class_docstring": "class A:\n '''Docstring'''\n", 53 | "class_attribute": "class A:\n a: str", 54 | "class_attribute_with_docstring": "class A:\n a: str\n '''Docstring'''\n", 55 | # class method with annotation 56 | "class_method_basic": "class A:\n def a(self) -> str: ...", 57 | # class property with annotation 58 | "class_property_basic": "class A:\n @property\n def a(self) -> str: ...", 59 | # class static method with annotation 60 | "class_staticmethod_basic": "class A:\n @staticmethod\n def a() -> str: ...", 61 | # class class method with annotation 62 | "class_classmethod_basic": "class A:\n @classmethod\n def a(cls) -> str: ...", 63 | # class abstract method with annotation 64 | "class_abstractmethod_basic": "import abc\n\nclass A:\n @abc.abstractmethod\n def a(self) -> str: ...", 65 | "class_inherited": "class A:\n def a(self) -> str: ...\nclass B(A): ...", 66 | "class_inherited_with_docstring": "class A:\n '''Docstring'''\n\n def a(self) -> str: ...\nclass B(A): ...", 67 | # overloads 68 | "overload_basic": "from typing import overload\n\n@overload\ndef a() -> str: ...\n@overload\ndef a(b: int) -> str: ...", 69 | } 70 | 71 | 72 | @pytest.mark.parametrize( 73 | "content", 74 | list(test_items.values()), 75 | ids=list(test_items), 76 | ) 77 | def test_basic(content, tmp_path, data_regression): 78 | tmp_path.joinpath("test.py").write_text(content) 79 | data = [clean_item(item) for item in analyse_module(tmp_path / "test.py", "test")] 80 | data_regression.check(data) 81 | 82 | 83 | def test_package(tmp_path, data_regression): 84 | pkg = tmp_path.joinpath("test") 85 | pkg.mkdir() 86 | pkg.joinpath("__init__.py").write_text("'''Docstring'''") 87 | pkg.joinpath("a.py").write_text("a: str = 'Hello World'") 88 | pkg.joinpath("b.py").write_text( 89 | "from .a import a\nfrom .a import a as x\nb: str = a" 90 | ) 91 | data = { 92 | "init": [ 93 | clean_item(item) 94 | for item in analyse_module(pkg.joinpath("__init__.py"), "test") 95 | ], 96 | "a": [ 97 | clean_item(item) for item in analyse_module(pkg.joinpath("a.py"), "test.a") 98 | ], 99 | "b": [ 100 | clean_item(item) for item in analyse_module(pkg.joinpath("b.py"), "test.b") 101 | ], 102 | } 103 | data_regression.check(data) 104 | -------------------------------------------------------------------------------- /tests/test_analyse_module/test_basic_assign_annotation_.yml: -------------------------------------------------------------------------------- 1 | - all: null 2 | doc: '' 3 | full_name: test 4 | type: module 5 | - annotation: str 6 | doc: '' 7 | full_name: test.a 8 | range: 9 | - 1 10 | - 1 11 | type: data 12 | value: null 13 | -------------------------------------------------------------------------------- /tests/test_analyse_module/test_basic_assign_annotation_union_.yml: -------------------------------------------------------------------------------- 1 | - all: null 2 | doc: '' 3 | full_name: test 4 | type: module 5 | - annotation: str | int 6 | doc: '' 7 | full_name: test.a 8 | range: 9 | - 1 10 | - 1 11 | type: data 12 | value: null 13 | -------------------------------------------------------------------------------- /tests/test_analyse_module/test_basic_assign_bytes_.yml: -------------------------------------------------------------------------------- 1 | - all: null 2 | doc: '' 3 | full_name: test 4 | type: module 5 | - annotation: bytes 6 | doc: '' 7 | full_name: test.a 8 | range: 9 | - 1 10 | - 1 11 | type: data 12 | value: !!binary | 13 | SGVsbG8gV29ybGQ= 14 | -------------------------------------------------------------------------------- /tests/test_analyse_module/test_basic_assign_class_.yml: -------------------------------------------------------------------------------- 1 | - all: null 2 | doc: '' 3 | full_name: test 4 | type: module 5 | - bases: [] 6 | doc: '' 7 | full_name: test.Foo 8 | range: 9 | - 1 10 | - 1 11 | type: class 12 | - annotation: null 13 | doc: '' 14 | full_name: test.a 15 | range: 16 | - 2 17 | - 2 18 | type: data 19 | value: Foo(...) 20 | -------------------------------------------------------------------------------- /tests/test_analyse_module/test_basic_assign_dict_.yml: -------------------------------------------------------------------------------- 1 | - all: null 2 | doc: '' 3 | full_name: test 4 | type: module 5 | - annotation: dict[str, int] 6 | doc: '' 7 | full_name: test.a 8 | range: 9 | - 1 10 | - 1 11 | type: data 12 | value: null 13 | -------------------------------------------------------------------------------- /tests/test_analyse_module/test_basic_assign_float_.yml: -------------------------------------------------------------------------------- 1 | - all: null 2 | doc: '' 3 | full_name: test 4 | type: module 5 | - annotation: float 6 | doc: '' 7 | full_name: test.a 8 | range: 9 | - 1 10 | - 1 11 | type: data 12 | value: 3.14 13 | -------------------------------------------------------------------------------- /tests/test_analyse_module/test_basic_assign_int_.yml: -------------------------------------------------------------------------------- 1 | - all: null 2 | doc: '' 3 | full_name: test 4 | type: module 5 | - annotation: int 6 | doc: '' 7 | full_name: test.a 8 | range: 9 | - 1 10 | - 1 11 | type: data 12 | value: 42 13 | -------------------------------------------------------------------------------- /tests/test_analyse_module/test_basic_assign_list_.yml: -------------------------------------------------------------------------------- 1 | - all: null 2 | doc: '' 3 | full_name: test 4 | type: module 5 | - annotation: list 6 | doc: '' 7 | full_name: test.a 8 | range: 9 | - 1 10 | - 1 11 | type: data 12 | value: 13 | - 1 14 | - 2 15 | - 3 16 | -------------------------------------------------------------------------------- /tests/test_analyse_module/test_basic_assign_set_.yml: -------------------------------------------------------------------------------- 1 | - all: null 2 | doc: '' 3 | full_name: test 4 | type: module 5 | - annotation: set[int] 6 | doc: '' 7 | full_name: test.a 8 | range: 9 | - 1 10 | - 1 11 | type: data 12 | value: null 13 | -------------------------------------------------------------------------------- /tests/test_analyse_module/test_basic_assign_string_.yml: -------------------------------------------------------------------------------- 1 | - all: null 2 | doc: '' 3 | full_name: test 4 | type: module 5 | - annotation: str 6 | doc: Docstring 7 | full_name: test.a 8 | range: 9 | - 1 10 | - 1 11 | type: data 12 | value: Hello World 13 | -------------------------------------------------------------------------------- /tests/test_analyse_module/test_basic_assign_tuple_.yml: -------------------------------------------------------------------------------- 1 | - all: null 2 | doc: '' 3 | full_name: test 4 | type: module 5 | - annotation: tuple 6 | doc: '' 7 | full_name: test.a 8 | range: 9 | - 1 10 | - 1 11 | type: data 12 | value: 13 | - 1 14 | - 2 15 | - 3 16 | -------------------------------------------------------------------------------- /tests/test_analyse_module/test_basic_assign_with_docstring_.yml: -------------------------------------------------------------------------------- 1 | - all: null 2 | doc: '' 3 | full_name: test 4 | type: module 5 | - annotation: str 6 | doc: Docstring 7 | full_name: test.a 8 | range: 9 | - 1 10 | - 1 11 | type: data 12 | value: Hello World 13 | -------------------------------------------------------------------------------- /tests/test_analyse_module/test_basic_class_abstractmethod_basic_.yml: -------------------------------------------------------------------------------- 1 | - all: null 2 | doc: '' 3 | full_name: test 4 | type: module 5 | - bases: [] 6 | doc: '' 7 | full_name: test.A 8 | range: 9 | - 3 10 | - 5 11 | type: class 12 | - args: [] 13 | doc: '' 14 | full_name: test.A.a 15 | properties: 16 | - abstractmethod 17 | range: 18 | - 5 19 | - 5 20 | return_annotation: str 21 | type: method 22 | -------------------------------------------------------------------------------- /tests/test_analyse_module/test_basic_class_attribute_.yml: -------------------------------------------------------------------------------- 1 | - all: null 2 | doc: '' 3 | full_name: test 4 | type: module 5 | - bases: [] 6 | doc: '' 7 | full_name: test.A 8 | range: 9 | - 1 10 | - 2 11 | type: class 12 | - annotation: str 13 | doc: '' 14 | full_name: test.A.a 15 | range: 16 | - 2 17 | - 2 18 | type: attribute 19 | value: null 20 | -------------------------------------------------------------------------------- /tests/test_analyse_module/test_basic_class_attribute_with_docstring_.yml: -------------------------------------------------------------------------------- 1 | - all: null 2 | doc: '' 3 | full_name: test 4 | type: module 5 | - bases: [] 6 | doc: '' 7 | full_name: test.A 8 | range: 9 | - 1 10 | - 3 11 | type: class 12 | - annotation: str 13 | doc: Docstring 14 | full_name: test.A.a 15 | range: 16 | - 2 17 | - 2 18 | type: attribute 19 | value: null 20 | -------------------------------------------------------------------------------- /tests/test_analyse_module/test_basic_class_basic_.yml: -------------------------------------------------------------------------------- 1 | - all: null 2 | doc: '' 3 | full_name: test 4 | type: module 5 | - bases: [] 6 | doc: '' 7 | full_name: test.A 8 | range: 9 | - 1 10 | - 1 11 | type: class 12 | -------------------------------------------------------------------------------- /tests/test_analyse_module/test_basic_class_classmethod_basic_.yml: -------------------------------------------------------------------------------- 1 | - all: null 2 | doc: '' 3 | full_name: test 4 | type: module 5 | - bases: [] 6 | doc: '' 7 | full_name: test.A 8 | range: 9 | - 1 10 | - 3 11 | type: class 12 | - args: [] 13 | doc: '' 14 | full_name: test.A.a 15 | properties: 16 | - classmethod 17 | range: 18 | - 3 19 | - 3 20 | return_annotation: str 21 | type: method 22 | -------------------------------------------------------------------------------- /tests/test_analyse_module/test_basic_class_docstring_.yml: -------------------------------------------------------------------------------- 1 | - all: null 2 | doc: '' 3 | full_name: test 4 | type: module 5 | - bases: [] 6 | doc: Docstring 7 | full_name: test.A 8 | range: 9 | - 1 10 | - 2 11 | type: class 12 | -------------------------------------------------------------------------------- /tests/test_analyse_module/test_basic_class_inherit_.yml: -------------------------------------------------------------------------------- 1 | - all: null 2 | doc: '' 3 | full_name: test 4 | type: module 5 | - bases: 6 | - B 7 | doc: '' 8 | full_name: test.A 9 | range: 10 | - 1 11 | - 1 12 | type: class 13 | -------------------------------------------------------------------------------- /tests/test_analyse_module/test_basic_class_inherit_generic_.yml: -------------------------------------------------------------------------------- 1 | - all: null 2 | doc: '' 3 | full_name: test 4 | type: module 5 | - bases: 6 | - B[int] 7 | doc: '' 8 | full_name: test.A 9 | range: 10 | - 1 11 | - 1 12 | type: class 13 | -------------------------------------------------------------------------------- /tests/test_analyse_module/test_basic_class_inherit_multi_.yml: -------------------------------------------------------------------------------- 1 | - all: null 2 | doc: '' 3 | full_name: test 4 | type: module 5 | - bases: 6 | - B 7 | - C 8 | doc: '' 9 | full_name: test.A 10 | range: 11 | - 1 12 | - 1 13 | type: class 14 | -------------------------------------------------------------------------------- /tests/test_analyse_module/test_basic_class_inherited_.yml: -------------------------------------------------------------------------------- 1 | - all: null 2 | doc: '' 3 | full_name: test 4 | type: module 5 | - bases: [] 6 | doc: '' 7 | full_name: test.A 8 | range: 9 | - 1 10 | - 2 11 | type: class 12 | - args: [] 13 | doc: '' 14 | full_name: test.A.a 15 | range: 16 | - 2 17 | - 2 18 | return_annotation: str 19 | type: method 20 | - bases: 21 | - test.A 22 | doc: '' 23 | full_name: test.B 24 | range: 25 | - 3 26 | - 3 27 | type: class 28 | - args: [] 29 | doc: '' 30 | full_name: test.B.a 31 | inherited: test.A 32 | range: 33 | - 2 34 | - 2 35 | return_annotation: str 36 | type: method 37 | -------------------------------------------------------------------------------- /tests/test_analyse_module/test_basic_class_inherited_with_docstring_.yml: -------------------------------------------------------------------------------- 1 | - all: null 2 | doc: '' 3 | full_name: test 4 | type: module 5 | - bases: [] 6 | doc: Docstring 7 | full_name: test.A 8 | range: 9 | - 1 10 | - 4 11 | type: class 12 | - args: [] 13 | doc: '' 14 | full_name: test.A.a 15 | range: 16 | - 4 17 | - 4 18 | return_annotation: str 19 | type: method 20 | - bases: 21 | - test.A 22 | doc: Docstring 23 | doc_inherited: test.A 24 | full_name: test.B 25 | range: 26 | - 5 27 | - 5 28 | type: class 29 | - args: [] 30 | doc: '' 31 | full_name: test.B.a 32 | inherited: test.A 33 | range: 34 | - 4 35 | - 4 36 | return_annotation: str 37 | type: method 38 | -------------------------------------------------------------------------------- /tests/test_analyse_module/test_basic_class_method_basic_.yml: -------------------------------------------------------------------------------- 1 | - all: null 2 | doc: '' 3 | full_name: test 4 | type: module 5 | - bases: [] 6 | doc: '' 7 | full_name: test.A 8 | range: 9 | - 1 10 | - 2 11 | type: class 12 | - args: [] 13 | doc: '' 14 | full_name: test.A.a 15 | range: 16 | - 2 17 | - 2 18 | return_annotation: str 19 | type: method 20 | -------------------------------------------------------------------------------- /tests/test_analyse_module/test_basic_class_property_basic_.yml: -------------------------------------------------------------------------------- 1 | - all: null 2 | doc: '' 3 | full_name: test 4 | type: module 5 | - bases: [] 6 | doc: '' 7 | full_name: test.A 8 | range: 9 | - 1 10 | - 3 11 | type: class 12 | - args: [] 13 | doc: '' 14 | full_name: test.A.a 15 | range: 16 | - 3 17 | - 3 18 | return_annotation: str 19 | type: property 20 | -------------------------------------------------------------------------------- /tests/test_analyse_module/test_basic_class_staticmethod_basic_.yml: -------------------------------------------------------------------------------- 1 | - all: null 2 | doc: '' 3 | full_name: test 4 | type: module 5 | - bases: [] 6 | doc: '' 7 | full_name: test.A 8 | range: 9 | - 1 10 | - 3 11 | type: class 12 | - args: [] 13 | doc: '' 14 | full_name: test.A.a 15 | properties: 16 | - staticmethod 17 | range: 18 | - 3 19 | - 3 20 | return_annotation: str 21 | type: method 22 | -------------------------------------------------------------------------------- /tests/test_analyse_module/test_basic_func_1arg_.yml: -------------------------------------------------------------------------------- 1 | - all: null 2 | doc: '' 3 | full_name: test 4 | type: module 5 | - args: 6 | - - null 7 | - b 8 | - int 9 | - null 10 | doc: '' 11 | full_name: test.a 12 | range: 13 | - 1 14 | - 1 15 | return_annotation: str 16 | type: function 17 | -------------------------------------------------------------------------------- /tests/test_analyse_module/test_basic_func_1kwarg_.yml: -------------------------------------------------------------------------------- 1 | - all: null 2 | doc: '' 3 | full_name: test 4 | type: module 5 | - args: 6 | - - '*' 7 | - null 8 | - null 9 | - null 10 | - - null 11 | - b 12 | - int 13 | - null 14 | doc: '' 15 | full_name: test.a 16 | range: 17 | - 1 18 | - 1 19 | return_annotation: str 20 | type: function 21 | -------------------------------------------------------------------------------- /tests/test_analyse_module/test_basic_func_args_.yml: -------------------------------------------------------------------------------- 1 | - all: null 2 | doc: '' 3 | full_name: test 4 | type: module 5 | - args: 6 | - - '*' 7 | - b 8 | - int 9 | - null 10 | doc: '' 11 | full_name: test.a 12 | range: 13 | - 1 14 | - 1 15 | return_annotation: str 16 | type: function 17 | -------------------------------------------------------------------------------- /tests/test_analyse_module/test_basic_func_async_.yml: -------------------------------------------------------------------------------- 1 | - all: null 2 | doc: '' 3 | full_name: test 4 | type: module 5 | - args: [] 6 | doc: '' 7 | full_name: test.a 8 | properties: 9 | - async 10 | range: 11 | - 1 12 | - 1 13 | return_annotation: str 14 | type: function 15 | -------------------------------------------------------------------------------- /tests/test_analyse_module/test_basic_func_basic_.yml: -------------------------------------------------------------------------------- 1 | - all: null 2 | doc: '' 3 | full_name: test 4 | type: module 5 | - args: [] 6 | doc: '' 7 | full_name: test.a 8 | range: 9 | - 1 10 | - 1 11 | return_annotation: str 12 | type: function 13 | -------------------------------------------------------------------------------- /tests/test_analyse_module/test_basic_func_docstring_.yml: -------------------------------------------------------------------------------- 1 | - all: null 2 | doc: '' 3 | full_name: test 4 | type: module 5 | - args: [] 6 | doc: Docstring 7 | full_name: test.a 8 | range: 9 | - 1 10 | - 2 11 | return_annotation: str 12 | type: function 13 | -------------------------------------------------------------------------------- /tests/test_analyse_module/test_basic_func_kwargs_.yml: -------------------------------------------------------------------------------- 1 | - all: null 2 | doc: '' 3 | full_name: test 4 | type: module 5 | - args: 6 | - - '**' 7 | - kw 8 | - float 9 | - null 10 | doc: '' 11 | full_name: test.a 12 | range: 13 | - 1 14 | - 1 15 | return_annotation: str 16 | type: function 17 | -------------------------------------------------------------------------------- /tests/test_analyse_module/test_basic_module_all_.yml: -------------------------------------------------------------------------------- 1 | - all: 2 | - a 3 | - b 4 | - c 5 | doc: '' 6 | full_name: test 7 | type: module 8 | - annotation: null 9 | doc: '' 10 | full_name: test.__all__ 11 | range: 12 | - 1 13 | - 1 14 | type: data 15 | value: 16 | - a 17 | - b 18 | - c 19 | -------------------------------------------------------------------------------- /tests/test_analyse_module/test_basic_module_docstring_.yml: -------------------------------------------------------------------------------- 1 | - all: null 2 | doc: Docstring 3 | full_name: test 4 | type: module 5 | -------------------------------------------------------------------------------- /tests/test_analyse_module/test_basic_overload_basic_.yml: -------------------------------------------------------------------------------- 1 | - all: null 2 | doc: '' 3 | full_name: test 4 | imports: 5 | - - typing.overload 6 | - null 7 | type: module 8 | - args: [] 9 | doc: '' 10 | full_name: test.a 11 | range: 12 | - 4 13 | - 4 14 | return_annotation: str 15 | type: overload 16 | - args: 17 | - - null 18 | - b 19 | - int 20 | - null 21 | doc: '' 22 | full_name: test.a 23 | range: 24 | - 6 25 | - 6 26 | return_annotation: str 27 | type: overload 28 | -------------------------------------------------------------------------------- /tests/test_analyse_module/test_package.yml: -------------------------------------------------------------------------------- 1 | a: 2 | - all: null 3 | doc: '' 4 | full_name: test.a 5 | type: module 6 | - annotation: str 7 | doc: '' 8 | full_name: test.a.a 9 | range: 10 | - 1 11 | - 1 12 | type: data 13 | value: Hello World 14 | b: 15 | - all: null 16 | doc: '' 17 | full_name: test.b 18 | imports: 19 | - - test.a.a 20 | - null 21 | - - test.a.a 22 | - x 23 | type: module 24 | - annotation: str 25 | doc: '' 26 | full_name: test.b.b 27 | range: 28 | - 3 29 | - 3 30 | type: data 31 | value: null 32 | init: 33 | - all: null 34 | doc: Docstring 35 | full_name: test 36 | type: package 37 | -------------------------------------------------------------------------------- /tests/test_database.py: -------------------------------------------------------------------------------- 1 | """Tests for the database.""" 2 | 3 | from pathlib import Path 4 | from textwrap import dedent 5 | 6 | from autodoc2.analysis import analyse_module 7 | from autodoc2.db import InMemoryDb 8 | from autodoc2.resolve_all import AllResolver 9 | from autodoc2.utils import yield_modules 10 | 11 | 12 | def test_all_resolution(tmp_path: Path, data_regression): 13 | """Test __all__ resolution""" 14 | package = tmp_path / "package" 15 | package.mkdir() 16 | package.joinpath("__init__.py").write_text( 17 | dedent( 18 | """\ 19 | from package.a import a1 20 | from package.a.c import ac1 as alias 21 | from unknown import something 22 | from .b import * 23 | from .d import * 24 | from other import * 25 | __all__ = ['p', 'a1', 'alias', 'something', 'unknown'] 26 | p = 1 27 | """ 28 | ), 29 | "utf-8", 30 | ) 31 | package.joinpath("a").mkdir() 32 | package.joinpath("a", "__init__.py").write_text( 33 | dedent( 34 | """\ 35 | from .c import * 36 | from .d import * 37 | __all__ = ['a1', 'ac1', 'ad1', 'ade1', 'adf1'] 38 | a1 = 1 39 | """ 40 | ), 41 | "utf-8", 42 | ) 43 | package.joinpath("a", "c.py").write_text( 44 | dedent( 45 | """\ 46 | __all__ = ['ac1'] 47 | ac1 = 1 48 | """ 49 | ), 50 | "utf-8", 51 | ) 52 | package.joinpath("b.py").touch() 53 | package.joinpath("d.py").write_text( 54 | # circular import 55 | dedent( 56 | """\ 57 | from package import * 58 | __all__ = ['p'] 59 | """ 60 | ), 61 | "utf-8", 62 | ) 63 | 64 | db = InMemoryDb() 65 | for path, modname in yield_modules(package): 66 | for item in analyse_module(path, modname): 67 | db.add(item) 68 | 69 | warnings = [] 70 | resolver = AllResolver(db, warnings.append) 71 | result = resolver.get_resolved_all("package") 72 | 73 | data_regression.check({"result": result, "warnings": warnings}) 74 | -------------------------------------------------------------------------------- /tests/test_database/test_all_resolution.yml: -------------------------------------------------------------------------------- 1 | result: 2 | errors: 3 | - - package 4 | - from package.b import *; does not have an __all__ 5 | - - package.d 6 | - from package import *; is a circular import 7 | - - package.d 8 | - '''p'' is unknown' 9 | - - package 10 | - from other import *; is unknown 11 | - - package 12 | - '''unknown'' is unknown' 13 | resolved: 14 | a1: package.a.a1 15 | alias: package.a.c.ac1 16 | p: package.p 17 | something: unknown.something 18 | warnings: 19 | - 'package.d: package.d: from package import *; is a circular import' 20 | - 'package.d: package.d: ''p'' is unknown' 21 | - 'package: package: from package.b import *; does not have an __all__' 22 | - 'package: package.d: from package import *; is a circular import' 23 | - 'package: package.d: ''p'' is unknown' 24 | - 'package: package: from other import *; is unknown' 25 | - 'package: package: ''unknown'' is unknown' 26 | -------------------------------------------------------------------------------- /tests/test_render.py: -------------------------------------------------------------------------------- 1 | """Tests for the rendering.""" 2 | 3 | import io 4 | from pathlib import Path 5 | from textwrap import dedent 6 | 7 | from autodoc2.analysis import analyse_module 8 | from autodoc2.config import Config 9 | from autodoc2.db import InMemoryDb 10 | from autodoc2.render.base import RendererBase 11 | from autodoc2.render.myst_ import MystRenderer 12 | from autodoc2.render.rst_ import RstRenderer 13 | from autodoc2.utils import yield_modules 14 | import pytest 15 | from sphinx.testing.util import SphinxTestApp 16 | from sphinx.testing.util import path as sphinx_path 17 | 18 | 19 | @pytest.mark.parametrize( 20 | "renderer,extension", 21 | [ 22 | (RstRenderer, ".rst"), 23 | (MystRenderer, ".md"), 24 | ], 25 | ids=["rst", "myst"], 26 | ) 27 | def test_basic(renderer: RendererBase, extension: str, tmp_path: Path, file_regression): 28 | """Test basic rendering.""" 29 | package = build_package(tmp_path) 30 | db = InMemoryDb() 31 | for path, modname in yield_modules(package): 32 | for item in analyse_module(path, modname): 33 | db.add(item) 34 | content = "\n".join(renderer(db, Config()).render_item(package.name)) 35 | file_regression.check(content, extension=extension) 36 | 37 | 38 | @pytest.mark.parametrize( 39 | "renderer,extension", 40 | [ 41 | (RstRenderer, ".rst"), 42 | (MystRenderer, ".md"), 43 | ], 44 | ids=["rst", "myst"], 45 | ) 46 | def test_config_options( 47 | renderer: RendererBase, extension: str, tmp_path: Path, file_regression 48 | ): 49 | """Test basic rendering.""" 50 | package = build_package(tmp_path) 51 | db = InMemoryDb() 52 | for path, modname in yield_modules(package): 53 | for item in analyse_module(path, modname): 54 | db.add(item) 55 | config = Config(no_index=True) 56 | content = "\n".join(renderer(db, config).render_item(package.name + ".func")) 57 | file_regression.check(content, extension=extension) 58 | 59 | 60 | @pytest.mark.parametrize( 61 | "with_rebuild", 62 | [True, False], 63 | ids=["with_rebuild", "without_rebuild"], 64 | ) 65 | def test_sphinx_build(tmp_path: Path, with_rebuild: bool): 66 | """Test building the Sphinx docs.""" 67 | build_package(tmp_path) 68 | source = tmp_path / "source" 69 | source.mkdir() 70 | source.joinpath("conf.py").write_text( 71 | dedent( 72 | """\ 73 | project = "tester" 74 | extensions = ["autodoc2"] 75 | autodoc2_packages = ["../package"] 76 | """ 77 | ), 78 | "utf-8", 79 | ) 80 | source.joinpath("index.rst").write_text( 81 | dedent( 82 | """\ 83 | Test 84 | ==== 85 | 86 | .. toctree:: 87 | 88 | apidocs/index 89 | """ 90 | ), 91 | "utf-8", 92 | ) 93 | warnings = io.StringIO() 94 | build = tmp_path / "build" 95 | app = SphinxTestApp( 96 | buildername="html", 97 | srcdir=sphinx_path(source), 98 | builddir=sphinx_path(build), 99 | warning=warnings, 100 | ) 101 | try: 102 | app.build() 103 | finally: 104 | app.cleanup() 105 | 106 | assertions = {} # catch all the assertion failures, before failing the test 107 | if warnings.getvalue(): 108 | assertions["warnings"] = warnings.getvalue() 109 | # print([p.relative_to(tmp_path).as_posix() for p in tmp_path.glob("**/*")]) 110 | package_source = source / "apidocs" / "package" / "package.rst" 111 | if not (source / "apidocs" / "package" / "package.rst").exists(): 112 | assertions["source/apidocs/package/package.rst"] = "not found" 113 | else: 114 | package_source_mtime = package_source.stat().st_mtime 115 | if not (build / "html" / "index.html").exists(): 116 | assertions["build/index.html"] = "not found" 117 | if not (build / "html" / "apidocs" / "index.html").exists(): 118 | assertions["build/apidocs/index.html"] = "not found" 119 | package_html = build / "html" / "apidocs" / "package" / "package.html" 120 | if not package_html.exists(): 121 | assertions["build/apidocs/package/package.html"] = "not found" 122 | else: 123 | package_html_mtime = package_html.stat().st_mtime 124 | 125 | if not hasattr(app.env, "autodoc2_cache"): 126 | assertions["autodoc2_cache"] = "not found" 127 | if not getattr(app.env, "autodoc2_cache"): # noqa: B009 128 | assertions["autodoc2_cache"] = "empty" 129 | 130 | if assertions: 131 | pytest.fail(f"Failed assertions {assertions}") 132 | 133 | if not with_rebuild: 134 | return 135 | 136 | # test rebuild 137 | rebuild_warnings = io.StringIO() 138 | rebuild_app = SphinxTestApp( 139 | buildername="html", 140 | srcdir=sphinx_path(source), 141 | builddir=sphinx_path(build), 142 | warning=rebuild_warnings, 143 | ) 144 | try: 145 | rebuild_app.build() 146 | finally: 147 | rebuild_app.cleanup() 148 | 149 | if rebuild_warnings.getvalue(): 150 | pytest.fail(f"Warnings on rebuild: {rebuild_warnings.getvalue()}") 151 | if package_source.stat().st_mtime != package_source_mtime: 152 | pytest.fail("Rebuild did not use cached source") 153 | if package_html.stat().st_mtime != package_html_mtime: 154 | pytest.fail("Rebuild did not use cached html") 155 | 156 | 157 | def test_sphinx_build_directives(tmp_path: Path, file_regression): 158 | """Test building the Sphinx docs, using directives.""" 159 | build_package(tmp_path) 160 | source = tmp_path / "source" 161 | source.mkdir() 162 | source.joinpath("conf.py").write_text( 163 | dedent( 164 | """\ 165 | project = "tester" 166 | extensions = ["autodoc2"] 167 | autodoc2_packages = [ 168 | { 169 | "path": "../package", 170 | "auto_mode": False, 171 | } 172 | ] 173 | """ 174 | ), 175 | "utf-8", 176 | ) 177 | source.joinpath("index.rst").write_text( 178 | dedent( 179 | """\ 180 | Test 181 | ==== 182 | 183 | .. autodoc2-docstring:: package.func 184 | :literal: 185 | :literal-linenos: 186 | :literal-lexer: restructuredtext 187 | 188 | .. autodoc2-docstring:: package.func 189 | 190 | .. autodoc2-object:: package.func 191 | :literal: 192 | :literal-lexer: restructuredtext 193 | 194 | .. autodoc2-object:: package.func 195 | :literal: 196 | 197 | render_plugin = "myst" 198 | 199 | .. autodoc2-object:: package.func 200 | 201 | .. autodoc2-summary:: 202 | 203 | package.func 204 | package.a1 205 | """ 206 | ), 207 | "utf-8", 208 | ) 209 | warnings = io.StringIO() 210 | build = tmp_path / "build" 211 | app = SphinxTestApp( 212 | buildername="html", 213 | srcdir=sphinx_path(source), 214 | builddir=sphinx_path(build), 215 | warning=warnings, 216 | ) 217 | try: 218 | app.build() 219 | finally: 220 | app.cleanup() 221 | 222 | assert not warnings.getvalue() 223 | 224 | doctree = app.env.get_doctree("index") 225 | doctree["source"] = "index.rst" 226 | content = "\n".join([line.rstrip() for line in doctree.pformat().splitlines()]) 227 | file_regression.check(content, extension=".xml") 228 | 229 | 230 | def build_package(tmp_path: Path) -> Path: 231 | """Build a simple package for testing.""" 232 | package = tmp_path / "package" 233 | package.mkdir() 234 | package.joinpath("__init__.py").write_text( 235 | dedent( 236 | """\ 237 | '''This is a test package.''' 238 | from package.a import a1 239 | from package.a.c import ac1 as alias 240 | __all__ = ['p', 'a1', 'alias'] 241 | p = 1 242 | '''p can be documented here.''' 243 | 244 | def func(a: str, b: int) -> alias: 245 | '''This is a function.''' 246 | 247 | class Class: 248 | '''This is a class.''' 249 | 250 | x: int = 1 251 | '''x can be documented here.''' 252 | 253 | def method(self, a: str, b: int) -> ...: 254 | '''This is a method.''' 255 | 256 | @property 257 | def prop(self) -> alias | None: 258 | '''This is a property.''' 259 | 260 | class Nested: 261 | '''This is a nested class.''' 262 | """ 263 | ), 264 | "utf-8", 265 | ) 266 | package.joinpath("a").mkdir() 267 | package.joinpath("a", "__init__.py").write_text( 268 | dedent( 269 | """\ 270 | '''This is a test module.''' 271 | from .c import * 272 | from .d import * 273 | __all__ = ['a1', 'ac1', 'ad1', 'ade1', 'adf1'] 274 | a1 = 1 275 | '''a1 can be documented here.''' 276 | """ 277 | ), 278 | "utf-8", 279 | ) 280 | package.joinpath("a", "c.py").write_text( 281 | dedent( 282 | """\ 283 | '''This is also a test module.''' 284 | __all__ = ['ac1'] 285 | ac1 = 1 286 | """ 287 | ), 288 | "utf-8", 289 | ) 290 | return package 291 | -------------------------------------------------------------------------------- /tests/test_render/test_basic_myst_.md: -------------------------------------------------------------------------------- 1 | # {py:mod}`package` 2 | 3 | ```{py:module} package 4 | ``` 5 | 6 | ```{autodoc2-docstring} package 7 | :allowtitles: 8 | ``` 9 | 10 | ## Subpackages 11 | 12 | ```{toctree} 13 | :titlesonly: 14 | :maxdepth: 3 15 | 16 | package.a 17 | ``` 18 | 19 | ## Package Contents 20 | 21 | ### Classes 22 | 23 | ````{list-table} 24 | :class: autosummary longtable 25 | :align: left 26 | 27 | * - {py:obj}`Class ` 28 | - ```{autodoc2-docstring} package.Class 29 | :summary: 30 | ``` 31 | ```` 32 | 33 | ### Functions 34 | 35 | ````{list-table} 36 | :class: autosummary longtable 37 | :align: left 38 | 39 | * - {py:obj}`func ` 40 | - ```{autodoc2-docstring} package.func 41 | :summary: 42 | ``` 43 | ```` 44 | 45 | ### Data 46 | 47 | ````{list-table} 48 | :class: autosummary longtable 49 | :align: left 50 | 51 | * - {py:obj}`__all__ ` 52 | - ```{autodoc2-docstring} package.__all__ 53 | :summary: 54 | ``` 55 | * - {py:obj}`p ` 56 | - ```{autodoc2-docstring} package.p 57 | :summary: 58 | ``` 59 | ```` 60 | 61 | ### API 62 | 63 | ````{py:data} __all__ 64 | :canonical: package.__all__ 65 | :value: > 66 | ['p', 'a1', 'alias'] 67 | 68 | ```{autodoc2-docstring} package.__all__ 69 | ``` 70 | 71 | ```` 72 | 73 | ````{py:data} p 74 | :canonical: package.p 75 | :value: > 76 | 1 77 | 78 | ```{autodoc2-docstring} package.p 79 | ``` 80 | 81 | ```` 82 | 83 | ````{py:function} func(a: str, b: int) -> package.a.c.ac1 84 | :canonical: package.func 85 | 86 | ```{autodoc2-docstring} package.func 87 | ``` 88 | ```` 89 | 90 | `````{py:class} Class 91 | :canonical: package.Class 92 | 93 | ```{autodoc2-docstring} package.Class 94 | ``` 95 | 96 | ````{py:attribute} x 97 | :canonical: package.Class.x 98 | :type: int 99 | :value: > 100 | 1 101 | 102 | ```{autodoc2-docstring} package.Class.x 103 | ``` 104 | 105 | ```` 106 | 107 | ````{py:method} method(a: str, b: int) -> ... 108 | :canonical: package.Class.method 109 | 110 | ```{autodoc2-docstring} package.Class.method 111 | ``` 112 | 113 | ```` 114 | 115 | ````{py:property} prop 116 | :canonical: package.Class.prop 117 | :type: package.a.c.ac1 | None 118 | 119 | ```{autodoc2-docstring} package.Class.prop 120 | ``` 121 | 122 | ```` 123 | 124 | ````{py:class} Nested 125 | :canonical: package.Class.Nested 126 | 127 | ```{autodoc2-docstring} package.Class.Nested 128 | ``` 129 | 130 | ```` 131 | 132 | ````` 133 | -------------------------------------------------------------------------------- /tests/test_render/test_basic_rst_.rst: -------------------------------------------------------------------------------- 1 | :py:mod:`package` 2 | ================= 3 | 4 | .. py:module:: package 5 | 6 | .. autodoc2-docstring:: package 7 | :allowtitles: 8 | 9 | Subpackages 10 | ----------- 11 | 12 | .. toctree:: 13 | :titlesonly: 14 | :maxdepth: 3 15 | 16 | package.a 17 | 18 | Package Contents 19 | ---------------- 20 | 21 | Classes 22 | ~~~~~~~ 23 | 24 | .. list-table:: 25 | :class: autosummary longtable 26 | :align: left 27 | 28 | * - :py:obj:`Class ` 29 | - .. autodoc2-docstring:: package.Class 30 | :summary: 31 | 32 | Functions 33 | ~~~~~~~~~ 34 | 35 | .. list-table:: 36 | :class: autosummary longtable 37 | :align: left 38 | 39 | * - :py:obj:`func ` 40 | - .. autodoc2-docstring:: package.func 41 | :summary: 42 | 43 | Data 44 | ~~~~ 45 | 46 | .. list-table:: 47 | :class: autosummary longtable 48 | :align: left 49 | 50 | * - :py:obj:`__all__ ` 51 | - .. autodoc2-docstring:: package.__all__ 52 | :summary: 53 | * - :py:obj:`p ` 54 | - .. autodoc2-docstring:: package.p 55 | :summary: 56 | 57 | API 58 | ~~~ 59 | 60 | .. py:data:: __all__ 61 | :canonical: package.__all__ 62 | :value: ['p', 'a1', 'alias'] 63 | 64 | .. autodoc2-docstring:: package.__all__ 65 | 66 | .. py:data:: p 67 | :canonical: package.p 68 | :value: 1 69 | 70 | .. autodoc2-docstring:: package.p 71 | 72 | .. py:function:: func(a: str, b: int) -> package.a.c.ac1 73 | :canonical: package.func 74 | 75 | .. autodoc2-docstring:: package.func 76 | 77 | .. py:class:: Class 78 | :canonical: package.Class 79 | 80 | .. autodoc2-docstring:: package.Class 81 | 82 | .. py:attribute:: x 83 | :canonical: package.Class.x 84 | :type: int 85 | :value: 1 86 | 87 | .. autodoc2-docstring:: package.Class.x 88 | 89 | .. py:method:: method(a: str, b: int) -> ... 90 | :canonical: package.Class.method 91 | 92 | .. autodoc2-docstring:: package.Class.method 93 | 94 | .. py:property:: prop 95 | :canonical: package.Class.prop 96 | :type: package.a.c.ac1 | None 97 | 98 | .. autodoc2-docstring:: package.Class.prop 99 | 100 | .. py:class:: Nested 101 | :canonical: package.Class.Nested 102 | 103 | .. autodoc2-docstring:: package.Class.Nested 104 | -------------------------------------------------------------------------------- /tests/test_render/test_config_options_myst_.md: -------------------------------------------------------------------------------- 1 | ````{py:function} func(a: str, b: int) -> package.a.c.ac1 2 | :canonical: package.func 3 | :noindex: 4 | 5 | ```{autodoc2-docstring} package.func 6 | ``` 7 | ```` 8 | -------------------------------------------------------------------------------- /tests/test_render/test_config_options_rst_.rst: -------------------------------------------------------------------------------- 1 | .. py:function:: func(a: str, b: int) -> package.a.c.ac1 2 | :canonical: package.func 3 | :noindex: 4 | 5 | .. autodoc2-docstring:: package.func 6 | -------------------------------------------------------------------------------- /tests/test_render/test_sphinx_build_directives.xml: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | Test 5 | <literal_block highlight_args="{'linenostart': 9}" language="restructuredtext" linenos="True" xml:space="preserve"> 6 | This is a function. 7 | <paragraph> 8 | This is a function. 9 | <literal_block language="restructuredtext" xml:space="preserve"> 10 | .. py:function:: func(a: str, b: int) -> package.a.c.ac1 11 | :canonical: package.func 12 | 13 | .. autodoc2-docstring:: package.func 14 | <literal_block xml:space="preserve"> 15 | ````{py:function} func(a: str, b: int) -> package.a.c.ac1 16 | :canonical: package.func 17 | 18 | ```{autodoc2-docstring} package.func 19 | ``` 20 | ```` 21 | <index entries="('single',\ 'func()\ (in\ module\ package)',\ 'package.func',\ '',\ None)"> 22 | <desc classes="py function" desctype="function" domain="py" nocontentsentry="False" noindex="False" noindexentry="False" objtype="function"> 23 | <desc_signature _toc_name="func()" _toc_parts="('package', 'func')" class="" classes="sig sig-object" fullname="func" ids="package.func" module="package"> 24 | <desc_addname classes="sig-prename descclassname" xml:space="preserve"> 25 | package. 26 | <desc_name classes="sig-name descname" xml:space="preserve"> 27 | func 28 | <desc_parameterlist xml:space="preserve"> 29 | <desc_parameter xml:space="preserve"> 30 | <desc_sig_name classes="n"> 31 | a 32 | <desc_sig_punctuation classes="p"> 33 | : 34 | <desc_sig_space classes="w"> 35 | 36 | <desc_sig_name classes="n"> 37 | <pending_xref py:class="True" py:module="package" refdomain="py" refspecific="False" reftarget="str" reftype="class"> 38 | str 39 | <desc_parameter xml:space="preserve"> 40 | <desc_sig_name classes="n"> 41 | b 42 | <desc_sig_punctuation classes="p"> 43 | : 44 | <desc_sig_space classes="w"> 45 | 46 | <desc_sig_name classes="n"> 47 | <pending_xref py:class="True" py:module="package" refdomain="py" refspecific="False" reftarget="int" reftype="class"> 48 | int 49 | <desc_returns xml:space="preserve"> 50 | <pending_xref py:class="True" py:module="package" refdomain="py" refspecific="False" reftarget="package.a.c.ac1" reftype="class"> 51 | package.a.c.ac1 52 | <desc_content> 53 | <paragraph> 54 | This is a function. 55 | <table align="left" classes="autosummary longtable"> 56 | <tgroup cols="2"> 57 | <colspec colwidth="50"> 58 | <colspec colwidth="50"> 59 | <tbody> 60 | <row> 61 | <entry> 62 | <paragraph> 63 | <pending_xref py:class="True" py:module="True" refdoc="index" refdomain="py" refexplicit="False" reftarget="package.func" reftype="obj" refwarn="False"> 64 | <literal classes="xref py py-obj"> 65 | package.func 66 | <entry> 67 | <paragraph> 68 | This is a function. 69 | <row> 70 | <entry> 71 | <paragraph> 72 | <pending_xref py:class="True" py:module="True" refdoc="index" refdomain="py" refexplicit="True" reftarget="package.a.a1" reftype="obj" refwarn="False"> 73 | <literal classes="xref py py-obj"> 74 | package.a1 75 | <entry> 76 | <paragraph> 77 | a1 can be documented here. --------------------------------------------------------------------------------