pax_global_header 0000666 0000000 0000000 00000000064 14106520141 0014504 g ustar 00root root 0000000 0000000 52 comment=19d217e177d76b40318a30a7cd25195d09530551
sphinx-autoapi-1.8.4/ 0000775 0000000 0000000 00000000000 14106520141 0014467 5 ustar 00root root 0000000 0000000 sphinx-autoapi-1.8.4/.github/ 0000775 0000000 0000000 00000000000 14106520141 0016027 5 ustar 00root root 0000000 0000000 sphinx-autoapi-1.8.4/.github/workflows/ 0000775 0000000 0000000 00000000000 14106520141 0020064 5 ustar 00root root 0000000 0000000 sphinx-autoapi-1.8.4/.github/workflows/main.yml 0000664 0000000 0000000 00000001671 14106520141 0021540 0 ustar 00root root 0000000 0000000 name: tests
on: [push, pull_request]
jobs:
test:
strategy:
matrix:
python-version: [3.6, 3.7, 3.8, 3.9]
platform: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip setuptools wheel
python -m pip install tox
- name: Run tests
run: tox -e py
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
- name: Install dependencies
run: |
python -m pip install --upgrade pip setuptools wheel
python -m pip install tox
- name: Lint
run: tox -e formatting,lint
sphinx-autoapi-1.8.4/.gitignore 0000664 0000000 0000000 00000000312 14106520141 0016453 0 ustar 00root root 0000000 0000000 *.egg-info
*.pyc
*.swp
.doctrees
_build_rtd
_build
docs/autoapi
readthedocs_build
tests/*/autoapi
tests/dotnetexample/example/Identity/
_api_
.tox
.eggs
.ropeproject/
.cache
.pytest_cache/
build/
dist/
sphinx-autoapi-1.8.4/.pre-commit-config.yaml 0000664 0000000 0000000 00000000560 14106520141 0020751 0 ustar 00root root 0000000 0000000 repos:
- repo: https://github.com/psf/black
rev: 19.10b0
hooks:
- id: black
language_version: python3
- repo: https://github.com/PyCQA/pylint
rev: 'pylint-2.5.3'
hooks:
- id: pylint
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.1.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
sphinx-autoapi-1.8.4/.readthedocs.yml 0000664 0000000 0000000 00000000705 14106520141 0017557 0 ustar 00root root 0000000 0000000 version: 2
# Build documentation in the docs/ directory with Sphinx
sphinx:
configuration: docs/conf.py
# Build documentation with MkDocs
#mkdocs:
# configuration: mkdocs.yml
# Optionally build your docs in additional formats such as PDF
formats:
- pdf
# Optionally set the version of Python and requirements required to build your docs
python:
version: 3.8
install:
- method: pip
path: .
extra_requirements:
- docs
sphinx-autoapi-1.8.4/CHANGELOG.rst 0000664 0000000 0000000 00000040330 14106520141 0016510 0 ustar 00root root 0000000 0000000 Changelog
=========
Versions follow `Semantic Versioning `_ (``..``).
v1.8.4 (2021-08-16)
-------------------
Bug Fixes
^^^^^^^^^
* `#301 `: (Python)
Fixed compatibility with astroid 2.7+.
v1.8.3 (2021-07-31)
-------------------
Bug Fixes
^^^^^^^^^
* `#299 `: (Python)
Fixed incorrect indentation in generated documentation when a class with no
constructor has a summary line spanning multiple lines.
Trivial/Internal Changes
^^^^^^^^^^^^^^^^^^^^^^^^
* Fixed broken link to Jinja objects.inv.
v1.8.2 (2021-07-26)
-------------------
Bug Fixes
^^^^^^^^^
* Fixed error when parsing a class with no constructor.
* `#293 `:
Fixed failure to build out of source conf.py files.
Configuration values using relative values are now relative to the source directory
instead of relative to the conf.py file.
* `#289 `: (Python)
Fixed AttributeError using inheritance diagrams on a module with plain imports.
* `#292 `:
Explicitly use the domain for generated directives.
v1.8.1 (2021-04-24)
-------------------
Bug Fixes
^^^^^^^^^
* `#273 `:
Fixed type annotations being shown for only a single module.
v1.8.0 (2021-04-12)
-------------------
Features
^^^^^^^^
* Expandable value for multi-line string attributes.
* `#265 `:
Can resolve the qualified paths of parameters to generics.
* `#275 `:
Warnings have been categorised and can be suppressed through ``suppress_warnings``.
* `#280 `:
Data attributes are documentated in module summaries.
Bug Fixes
^^^^^^^^^
* `#273 `:
Fixed setting ``autodoc_typehints`` to ``none`` or ``description``
not turning off signature type hints.
``autodoc_typehints`` integration is consisidered experimental until
the extension properly supports overload functions.
* `#261 `:
Fixed data annotations causing pickle or deepcopy errors.
* Documentation can be generated when multiple source directories
share a single ``conf.py`` file.
Trivial/Internal Changes
^^^^^^^^^^^^^^^^^^^^^^^^
* Fixed ``DeprecationWarning`` for invalid escape sequence ``\s`` in tests.
* Fixed ``FutureWarning`` for ``Node.traverse()`` becoming an iterator instead of list.
* New example implementation of ``autoapi-skip-member`` Sphinx event.
* Can run tests with tox 4.
* Updated packaging to use PEP-517.
* All unittest style tests have been converted to pytest style tests.
* An exception raised by docfx is raised directly instead of wrapping it.
* Started using Github Actions for continuous integration.
V1.7.0 (2021-01-31)
-------------------
Features
^^^^^^^^
* The fully qualified path of objects are included type annotations
so that Sphinx can link to them.
* Added support for Sphinx 3.3. and 3.4.
* `#240 `:
The docstrings of ``object.__init__``, ``object.__new__``,
``type.__init__``, and ``type.__new__`` are not inherited.
Bug Fixes
^^^^^^^^^
* `#260 `:
The overload signatures of ``__init__`` methods are documented.
V1.6.0 (2021-01-20)
-------------------
Breaking Changes
^^^^^^^^^^^^^^^^
* Dropped support for Python 2 and Sphinx 1.x/2.x.
Python 2 source code can still be parsed.
Features
^^^^^^^^
* (Python) Added support for using type hints as parameter types and return types
via the ``sphinx.ext.autodoc.typehints`` extension.
* `#191 `:
Basic incremental build support is enabled ``autoapi_keep_files`` is enabled.
Providing none of the source files have changed,
AutoAPI will skip parsing the source code and regenerating the API documentation.
* `#200 `:
Can pass a callback that edits the Jinja Environment object before
template rendering begins.
This allows custom filters, tests, and globals to be added to the environment.
* Added support for Python 3.9.
Bug Fixes
^^^^^^^^^
* `#246 `: (Python)
Fixed TypeError when parsing a class that inherits from ``type``.
* `#244 `:
Fixed an unnecessary deprecation warning being raised when running
sphinx-build from the same directory as conf.py.
* (Python) Fixed properties documented by Autodoc directives geting documented as methods.
V1.5.1 (2020-10-01)
-------------------
Bug Fixes
^^^^^^^^^
* Fixed AttributeError when generating an inheritance diagram for a module.
V1.5.0 (2020-08-31)
-------------------
This will be the last minor version to support Python 2 and Sphinx 1.x/2.x.
Features
^^^^^^^^
* `#222 `:
Declare the extension as parallel unsafe.
* `#217 `: (Python)
All overload signatures are documented.
* `#243 `:
Files are found in order of preference according to ``autoapi_file_patterns``.
* Added support for Sphinx 3.2.
Bug Fixes
^^^^^^^^^
* `#219 `: (Python)
Fixed return types not showing for methods.
* (Python) Fixed incorrect formatting of properties on generated method directives.
* Fixed every toctree entry getting added as a new list.
* `#234 `:
Fixed only some entries getting added to the toctree.
Trivial/Internal Changes
^^^^^^^^^^^^^^^^^^^^^^^^
* autoapisummary directive inherits from autosummary for future stability.
v1.4.0 (2020-06-07)
-------------------
Features
^^^^^^^^
* `#197 `: Added
``autoapi.__version__`` and ``autoapi.__version_info__`` attributes
for accessing version information.
* `#201 `: (Python)
Added the ``autoapi_member_order`` option to allow the order that members
are documentated to be configurable.
* `#203 `: (Python)
A class without a docstring inherits one from its parent.
A methods without a docstring inherits one from the method that it overrides.
* `#204 `: (Python)
Added the ``imported-members`` AutoAPI option to be able to enable or disable
documenting objects imported from the same top-level package or module
without needing to override templates.
Bug Fixes
^^^^^^^^^
* `#198 `:
Documentation describes the required layout for template override directories.
* `#195 `: (Python)
Fixed incorrect formatting when ``show-inheritance-diagram``
and ``private-members`` are turned on.
* `#193 ` and
`#208 `: (Python)
Inheritance diagrams can follow imports to find classes to document.
* `#213 `: (Python)
Fixed module summary never showing.
Trivial/Internal Changes
^^^^^^^^^^^^^^^^^^^^^^^^
* black shows diffs by default
* `#207 `:
Fixed a typo in the code of the golang tutorial.
v1.3.0 (2020-04-05)
-------------------
Breaking Changes
^^^^^^^^^^^^^^^^
* Dropped support for Python 3.4 and 3.5.
Features
^^^^^^^^
* `#151 `: (Python)
Added the ``autoapi_python_use_implicit_namespaces`` option to allow
AutoAPI to search for implicit namespace packages.
* Added support for Sphinx 2.2 and 2.3.
* Added support for Python 3.8.
* `#140 `: (Python)
Added the ``autoapi-inheritance-diagram`` directive to create
inheritance diagrams without importing modules.
Enable the ``show-inheritance-diagram`` AutoAPI option to
turn the diagrams on in generated documentation.
* `#183 `: (Python)
Added the ``show-inheritance`` AutoAPI option to be able to enable or disable
the display of a list of base classes in generated documentation about a class.
Added the ``inherited-members`` AutoAPI option to be able to enable or disable
the display of members inherited from a base class
in generated documentation about a class.
* The ``autoapi_include_summaries`` option has been replaced with the
``show-module-summary`` AutoAPI option.
``autoapi_include_summaries`` will stop working in the next major version.
* Added support for Sphinx 2.4 and 3.0
Bug Fixes
^^^^^^^^^
* `#186 `: (Python)
Fixed an exception when there are too many argument type annotations
in a type comment.
* (Python) args and kwargs type annotations can be read from
the function type comment.
Trivial/Internal Changes
^^^^^^^^^^^^^^^^^^^^^^^^
* Tests are now included in the sdist.
v1.2.1 (2019-10-09)
-------------------
Bug Fixes
^^^^^^^^^
* (Python) "Invalid desc node" warning no longer raised for autodoc-style
directives.
v1.2.0 (2019-10-05)
-------------------
Features
^^^^^^^^
* (Python) Can read per argument type comments with astroid > 2.2.5.
* (Python) Added autoapidecorator directive with Sphinx >= 2.0.
* (Python) Can use autodoc_docstring_signature with Autodoc-style directives.
* (Python) Added autoapi-skip-member event.
* Made it more clear which file causes an error, when an error occurs.
* Sphinx language domains are now optional dependencies.
Bug Fixes
^^^^^^^^^
* (Python) Forward reference annotations are no longer rendered as strings.
* (Python) autoapifunction directive no longer documents async functions as
a normal function.
* (Python) Fixed unicode decode errors in some Python 3 situations.
* Documentation more accurately describes what configuration accepts
relative paths and where they are relative to.
v1.1.0 (2019-06-23)
-------------------
Features
^^^^^^^^
* (Python) Can override ignoring local imports in modules by using __all__.
Bug Fixes
^^^^^^^^^
* (Python) Fixed incorrect formatting of functions and methods.
* Added support for Sphinx 2.1.
Trivial/Internal Changes
^^^^^^^^^^^^^^^^^^^^^^^^
* Fixed some dead links in the README.
* Fixed lint virtualenv.
v1.0.0 (2019-04-24)
-------------------
Features
^^^^^^^^
* `#100 `: (Python)
Added support for documenting C extensions via ``.pyi`` stub files.
* Added support for Sphinx 2.0.
* Toned down the API reference index page.
* (Go) Patterns configured in ``autoapi_ignore`` are passed to godocjson.
* New and improved documentation.
* No longer need to set ``autoapi_add_toctree_entry`` to False when ``autoapi_generate_api_docs`` is False.
* `#139 `
Added support for basic type annotations in documentation generation and autodoc-style directives.
Bug Fixes
^^^^^^^^^
* `#159 `: (Python)
Fixed ``UnicodeDecodeError`` on Python 2 when a documenting an attribute that contains binary data.
* (Python) Fixed private submodules displaying when ``private-members`` is turned off.
* Templates no longer produce excessive whitespace.
* (Python) Fixed an error when giving an invalid object to an autodoc-style directive.
Trivial/Internal Changes
^^^^^^^^^^^^^^^^^^^^^^^^
* No longer pin the version of black.
* Added missing test environments to travis.
v0.7.1 (2019-02-04)
-------------------
Bug Fixes
^^^^^^^^^
* (Python) Fixed a false warning when importing a local module.
v0.7.0 (2019-01-30)
-------------------
Breaking Changes
^^^^^^^^^^^^^^^^
* Dropped support for Sphinx<1.6.
Features
^^^^^^^^
* Added debug messages about what AutoAPI is doing.
Bug Fixes
^^^^^^^^^
* `#156 `: (Python) Made import resolution more stable.
Also capable of giving more detailed warnings.
Trivial/Internal Changes
^^^^^^^^^^^^^^^^^^^^^^^^
* Code is now formatted using black.
* Removed references to old css and js files.
* Replaced usage of deprecated Sphinx features.
* Reorganised tests to be more pytest-like.
v0.6.2 (2018-11-15)
-------------------
Bug Fixes
^^^^^^^^^
* (Python) Fixed some import chains failing to resolve depending on resolution order.
v0.6.1 (2018-11-14)
-------------------
Bug Fixes
^^^^^^^^^
* (Python) Fixed unicode decoding on Python 3.7.
* (Python) Fixed autodoc directives not documenting anything in submodules or subpackages.
* (Python) Fixed error parsing files with unicode docstrings.
* (Python) Fixed error when documenting something that's imported in more than one place.
Trivial/Internal Changes
^^^^^^^^^^^^^^^^^^^^^^^^
* (Python) Added Python 3.7 testing.
* Started testing against stable version of Sphinx 1.8.
* Fixed all "no title" warnings during tests.
v0.6.0 (2018-08-20)
-------------------
Breaking Changes
^^^^^^^^^^^^^^^^
* `#152 `: Removed the ``autoapi_add_api_root_toctree`` option.
This has been replaced with the ``autoapi_add_toctree_entry`` option.
* `#25 `: Removed distutils support.
* Removed redundant ``package_dir`` and ``package_data`` options.
Features
^^^^^^^^
* (Python) Added viewcode support for imported members.
* `#146 `: (Python) No longer documents ``__init__()`` attributes without a docstring.
* `#153 `: (Python) Can document a public python API.
* `#111 `: (Python) Can opt to write manual documentation through new autodoc-style directives.
* `#152 `: Made it easier to remove default index page.
Also removed autoapi_add_api_root_toctree config option
* `#150 `: (Python) ``private-members`` also controls private subpackages and submodules.
* (Python) Added support for static and class methods.
* (Python) Methods include ``self`` in their arguments.
This more closely matches autodoc behaviour.
* `#145 `: (Python) Added support for detecting Python exceptions.
* (Python) Can control how __init__ docstring is displayed.
* (Python) Added support for viewcode.
* (Python) Source files no longer need to be in ``sys.path``.
Bug Fixes
^^^^^^^^^
* (Python) Fixed linking to builtin bases.
* (Python) Fixed properties being documented more than once when set in ``__init__()``.
* (Python) Fixed nested classes not getting displayed.
* `#148 `: (Python) Fixed astroid 2.0 compatibility.
* (Python) Fixed filtered classes and attributes getting displayed.
* (Python) Fixed incorrect display of long lists.
* `#125 `: (Javacript) Fixed running incorrect jsdoc command on Windows.
* `#125 `: (Python) Support specifying package directories in ``autoapi_dirs``.
Trivial/Internal Changes
^^^^^^^^^^^^^^^^^^^^^^^^
* Added Sphinx 1.7 and 1.8.0b1 testing.
* `#120 `: Updated documentation to remove outdated references.
* Removed old testing dependencies.
* `#143 `: Removed unnecessary wheel dependency.
sphinx-autoapi-1.8.4/LICENSE.rst 0000664 0000000 0000000 00000002124 14106520141 0016302 0 ustar 00root root 0000000 0000000 The MIT License (MIT)
=====================
Copyright (c) 2015 Read the Docs, Inc
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
sphinx-autoapi-1.8.4/MANIFEST.in 0000664 0000000 0000000 00000000134 14106520141 0016223 0 ustar 00root root 0000000 0000000 recursive-include autoapi *.rst
include *.rst
include LICENSE.mit
recursive-include tests *
sphinx-autoapi-1.8.4/README.rst 0000664 0000000 0000000 00000010207 14106520141 0016156 0 ustar 00root root 0000000 0000000 Sphinx AutoAPI
==============
.. image:: https://readthedocs.org/projects/sphinx-autoapi/badge/?version=latest
:target: https://sphinx-autoapi.readthedocs.org
:alt: Documentation
.. image:: https://github.com/readthedocs/sphinx-autoapi/actions/workflows/main.yml/badge.svg?branch=master
:target: https://github.com/readthedocs/sphinx-autoapi/actions/workflows/main.yml?query=branch%3Amaster
:alt: Github Build Status
.. image:: https://img.shields.io/pypi/v/sphinx-autoapi.svg
:target: https://pypi.org/project/sphinx-autoapi/
:alt: PyPI Version
.. image:: https://img.shields.io/pypi/pyversions/sphinx-autoapi.svg
:target: https://pypi.org/project/sphinx-autoapi/
:alt: Supported Python Versions
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
:target: https://github.com/python/black
:alt: Formatted with Black
Sphinx AutoAPI provides "autodoc" style documentation for multiple programming languages
without needing to load, run, or import the project being documented.
In contrast to the traditional `Sphinx autodoc `_,
which is Python-only and uses code imports,
AutoAPI finds and generates documentation by parsing source code.
Language Support
----------------
========== ====== ==========================================================
Language Status Parser
========== ====== ==========================================================
Python Stable Custom using `astroid `_
Go Alpha `godocjson `_
Javascript Alpha `jsdoc `_
.NET Alpha `docfx `_
========== ====== ==========================================================
Getting Started
---------------
The following steps will walk through how to add AutoAPI to an existing Sphinx project.
For instructions on how to set up a Sphinx project,
see Sphinx's documentation on
`Getting Started `_.
Installation
~~~~~~~~~~~~
AutoAPI can be installed through pip:
.. code-block:: bash
pip install sphinx-autoapi
Next, add and configure AutoAPI in your Sphinx project's `conf.py`.
Other languages may require
`further configuration `_:
.. code-block:: python
extensions.append('autoapi.extension')
autoapi_type = 'python'
autoapi_dirs = ['path/to/source/files', 'src']
Where `autoapi_type` can be one of any of the supported languages:
========== ================
Language ``autoapi_type``
========== ================
Python ``'python'``
Go ``'go'``
Javascript ``'javascript'``
.NET ``'dotnet'``
========== ================
When the documentation is built,
AutoAPI will now generate API documentation into an `autoapi/` directory and add an entry to the documentation in your top level table of contents!
To configure AutoAPI behaviour further,
see the `Configuration documentation `_.
Contributing
------------
Running the tests
~~~~~~~~~~~~~~~~~
Tests are executed through `tox `_.
.. code-block:: bash
tox
Code Style
~~~~~~~~~~
Code is formatted using `black `_.
You can check your formatting using black's check mode:
.. code-block:: bash
tox -e formatting
You can also get black to format your changes for you:
.. code-block:: bash
black autoapi/ tests/
You can even get black to format changes automatically when you commit using `pre-commit `_:
.. code-block:: bash
pip install pre-commit
pre-commit install
Versioning
----------
We use `SemVer `_ for versioning. For the versions available, see the `tags on this repository `_.
License
-------
This project is licensed under the MIT License.
See the `LICENSE.rst `_ file for details.
sphinx-autoapi-1.8.4/autoapi/ 0000775 0000000 0000000 00000000000 14106520141 0016131 5 ustar 00root root 0000000 0000000 sphinx-autoapi-1.8.4/autoapi/__init__.py 0000664 0000000 0000000 00000000150 14106520141 0020236 0 ustar 00root root 0000000 0000000 """Sphinx AutoAPI"""
from .extension import setup
__version__ = "1.8.4"
__version_info__ = (1, 8, 4)
sphinx-autoapi-1.8.4/autoapi/backends.py 0000664 0000000 0000000 00000001716 14106520141 0020262 0 ustar 00root root 0000000 0000000 from .mappers import (
DotNetSphinxMapper,
PythonSphinxMapper,
GoSphinxMapper,
JavaScriptSphinxMapper,
)
DEFAULT_FILE_PATTERNS = {
"python": ["*.py", "*.pyi"],
"dotnet": ["project.json", "*.csproj", "*.vbproj"],
"go": ["*.go"],
"javascript": ["*.js"],
}
DEFAULT_IGNORE_PATTERNS = {
"dotnet": ["*toc.yml", "*index.yml"],
"python": ["*migrations*"],
"go": ["_test.go"],
}
LANGUAGE_MAPPERS = {
"python": PythonSphinxMapper,
"dotnet": DotNetSphinxMapper,
"go": GoSphinxMapper,
"javascript": JavaScriptSphinxMapper,
}
#: describes backend requirements in form
#: {'backend name': (('1st package name in pypi', '1st package import name'), ...)}
LANGUAGE_REQUIREMENTS = {
"python": (),
"javascript": (),
"go": (("sphinxcontrib-golangdomain", "sphinxcontrib.golangdomain"),),
"dotnet": (("sphinxcontrib-dotnetdomain", "sphinxcontrib.dotnetdomain"),),
} # type: Dict[str, Sequence[Tuple[str, str]]]
sphinx-autoapi-1.8.4/autoapi/directives.py 0000664 0000000 0000000 00000003602 14106520141 0020645 0 ustar 00root root 0000000 0000000 """AutoAPI directives"""
from docutils.parsers.rst import Directive
from docutils import nodes
from sphinx.ext.autosummary import Autosummary
from sphinx.util.nodes import nested_parse_with_titles
from .mappers.python.objects import PythonFunction
class AutoapiSummary(Autosummary): # pylint: disable=too-few-public-methods
"""A version of autosummary that uses static analysis."""
def get_items(self, names):
items = []
env = self.state.document.settings.env
all_objects = env.autoapi_all_objects
for name in names:
obj = all_objects[name]
if isinstance(obj, PythonFunction):
if obj.overloads:
sig = "(\u2026)"
else:
sig = "({})".format(obj.args)
if obj.return_annotation is not None:
sig += " \u2192 {}".format(obj.return_annotation)
else:
sig = ""
item = (obj.short_name, sig, obj.summary, obj.id)
items.append(item)
return items
class NestedParse(Directive): # pylint: disable=too-few-public-methods
"""Nested parsing to remove the first heading of included rST
This is used to handle the case where we like to remove user supplied
headings from module docstrings. This is required to reduce the number of
duplicate headings on sections.
"""
has_content = 1
required_arguments = 0
optional_arguments = 0
final_argument_whitespace = False
option_spec = {}
def run(self):
node = nodes.container()
node.document = self.state.document
nested_parse_with_titles(self.state, self.content, node)
try:
title_node = node[0][0]
if isinstance(title_node, nodes.title):
del node[0][0]
except IndexError:
pass
return node.children
sphinx-autoapi-1.8.4/autoapi/documenters.py 0000664 0000000 0000000 00000023332 14106520141 0021036 0 ustar 00root root 0000000 0000000 import re
from sphinx.ext import autodoc
from .mappers.python import (
PythonFunction,
PythonClass,
PythonMethod,
PythonData,
PythonAttribute,
PythonException,
)
# pylint: disable=attribute-defined-outside-init,no-self-use,unused-argument
class AutoapiDocumenter(autodoc.Documenter):
def get_attr(self, obj, name, *defargs):
attrgetters = self.env.app.registry.autodoc_attrgettrs
for type_, func in attrgetters.items():
if isinstance(obj, type_):
return func(obj, name, *defargs)
if name == "__doc__":
return obj.docstring
for child in obj.children:
if child.name == name:
return child
if defargs:
return defargs[0]
raise AttributeError(name)
def import_object(self):
max_splits = self.fullname.count(".")
for num_splits in range(max_splits, -1, -1):
path_stack = list(reversed(self.fullname.rsplit(".", num_splits)))
objects = self.env.autoapi_objects
parent = None
current = objects.get(path_stack.pop())
while current and path_stack:
parent = current
current = self.get_attr(current, path_stack.pop(), None)
if current:
self.object = current
self.object_name = current.name
self._method_parent = parent
return True
return False
def get_real_modname(self):
# Return a fake modname so that nothing can be imported
return None
def get_doc(self, encoding=None, ignore=1):
return [self.object.docstring.splitlines()]
def process_doc(self, docstrings):
for docstring in docstrings:
for line in docstring:
yield line
yield ""
def get_object_members(self, want_all):
children = ((child.name, child) for child in self.object.children)
if not want_all:
if not self.options.members:
return False, []
children = (child for child in children if child[0] in self.options.members)
elif not self.options.inherited_members:
children = (child for child in children if not child[1].inherited)
return False, sorted(children)
class _AutoapiDocstringSignatureMixin: # pylint: disable=too-few-public-methods
def format_signature(self, **kwargs):
# Set "manual" attributes at the last possible moment.
# This is to let a manual entry or docstring searching happen first,
# and falling back to the discovered signature only when necessary.
if self.args is None:
self.args = self.object.args
if self.retann is None:
self.retann = self.object.return_annotation
return super(_AutoapiDocstringSignatureMixin, self).format_signature(**kwargs)
class AutoapiFunctionDocumenter(
AutoapiDocumenter, autodoc.FunctionDocumenter, _AutoapiDocstringSignatureMixin
):
objtype = "apifunction"
directivetype = "function"
# Always prefer AutoapiDocumenters
priority = autodoc.FunctionDocumenter.priority * 100 + 100
@classmethod
def can_document_member(cls, member, membername, isattr, parent):
return isinstance(member, PythonFunction)
def format_args(self, **kwargs):
return "(" + self.object.args + ")"
def add_directive_header(self, sig):
autodoc.Documenter.add_directive_header(self, sig)
if "async" in self.object.properties:
sourcename = self.get_sourcename()
self.add_line(" :async:", sourcename)
class AutoapiDecoratorDocumenter(
AutoapiFunctionDocumenter, AutoapiDocumenter, autodoc.DecoratorDocumenter
):
objtype = "apidecorator"
directivetype = "decorator"
priority = autodoc.DecoratorDocumenter.priority * 100 + 100
def format_signature(self, **kwargs):
if self.args is None:
self.args = self.format_args(**kwargs)
return super(AutoapiDecoratorDocumenter, self).format_signature(**kwargs)
def format_args(self, **kwargs):
to_format = self.object.args
if re.match(r"func\W", to_format) or to_format == "func":
if "," not in to_format:
return None
# We need to do better stripping here.
# An annotation with a comma will mess this up.
to_format = self.object.args.split(",", 1)[1]
return "(" + to_format + ")"
class AutoapiClassDocumenter(
AutoapiDocumenter, autodoc.ClassDocumenter, _AutoapiDocstringSignatureMixin
):
objtype = "apiclass"
directivetype = "class"
doc_as_attr = False
priority = autodoc.ClassDocumenter.priority * 100 + 100
@classmethod
def can_document_member(cls, member, membername, isattr, parent):
return isinstance(member, PythonClass)
def format_args(self, **kwargs):
return "(" + self.object.args + ")"
def add_directive_header(self, sig):
autodoc.Documenter.add_directive_header(self, sig)
if self.options.show_inheritance:
sourcename = self.get_sourcename()
self.add_line(u"", sourcename)
# TODO: Change sphinx to allow overriding of getting base names
if self.object.bases:
bases = [":class:`{}`".format(base) for base in self.object.bases]
self.add_line(" " + "Bases: {}".format(", ".join(bases)), sourcename)
class AutoapiMethodDocumenter(
AutoapiDocumenter, autodoc.MethodDocumenter, _AutoapiDocstringSignatureMixin
):
objtype = "apimethod"
directivetype = "method"
priority = autodoc.MethodDocumenter.priority * 100 + 100
@classmethod
def can_document_member(cls, member, membername, isattr, parent):
return isinstance(member, PythonMethod)
def format_args(self, **kwargs):
return "(" + self.object.args + ")"
def import_object(self):
result = super(AutoapiMethodDocumenter, self).import_object()
if result:
self.parent = self._method_parent
if self.object.method_type != "method":
# document class and static members before ordinary ones
self.member_order = self.member_order - 1
return result
def add_directive_header(self, sig):
autodoc.Documenter.add_directive_header(self, sig)
sourcename = self.get_sourcename()
for property_type in (
"abstractmethod",
"async",
"classmethod",
"staticmethod",
):
if property_type in self.object.properties:
self.add_line(" :{}:".format(property_type), sourcename)
class AutoapiPropertyDocumenter(
AutoapiMethodDocumenter, AutoapiDocumenter, autodoc.PropertyDocumenter
):
objtype = "apiproperty"
directivetype = "method"
# Always prefer AutoapiDocumenters
priority = autodoc.MethodDocumenter.priority * 100 + 100 + 1
@classmethod
def can_document_member(cls, member, membername, isattr, parent):
return isinstance(member, PythonMethod) and "property" in member.properties
def add_directive_header(self, sig):
super(AutoapiPropertyDocumenter, self).add_directive_header(sig)
sourcename = self.get_sourcename()
self.add_line(" :property:", sourcename)
class AutoapiDataDocumenter(AutoapiDocumenter, autodoc.DataDocumenter):
objtype = "apidata"
directivetype = "data"
priority = autodoc.DataDocumenter.priority * 100 + 100
@classmethod
def can_document_member(cls, member, membername, isattr, parent):
return isinstance(member, PythonData)
def add_directive_header(self, sig):
autodoc.ModuleLevelDocumenter.add_directive_header(self, sig)
sourcename = self.get_sourcename()
if not self.options.annotation:
# TODO: Change sphinx to allow overriding of object description
if self.object.value is not None:
self.add_line(
" :annotation: = {}".format(self.object.value), sourcename
)
elif self.options.annotation is autodoc.SUPPRESS:
pass
else:
self.add_line(" :annotation: %s" % self.options.annotation, sourcename)
class AutoapiAttributeDocumenter(AutoapiDocumenter, autodoc.AttributeDocumenter):
objtype = "apiattribute"
directivetype = "attribute"
_datadescriptor = True
priority = autodoc.AttributeDocumenter.priority * 100 + 100
@classmethod
def can_document_member(cls, member, membername, isattr, parent):
return isinstance(member, PythonAttribute)
def add_directive_header(self, sig):
autodoc.ClassLevelDocumenter.add_directive_header(self, sig)
sourcename = self.get_sourcename()
if not self.options.annotation:
# TODO: Change sphinx to allow overriding of object description
if self.object.value is not None:
self.add_line(
" :annotation: = {}".format(self.object.value), sourcename
)
elif self.options.annotation is autodoc.SUPPRESS:
pass
else:
self.add_line(" :annotation: %s" % self.options.annotation, sourcename)
class AutoapiModuleDocumenter(AutoapiDocumenter, autodoc.ModuleDocumenter):
objtype = "apimodule"
directivetype = "module"
priority = autodoc.ModuleDocumenter.priority * 100 + 100
class AutoapiExceptionDocumenter(
AutoapiClassDocumenter, AutoapiDocumenter, autodoc.ExceptionDocumenter
):
objtype = "apiexception"
directivetype = "exception"
priority = autodoc.ExceptionDocumenter.priority * 100 + 100
@classmethod
def can_document_member(cls, member, membername, isattr, parent):
return isinstance(member, PythonException)
sphinx-autoapi-1.8.4/autoapi/extension.py 0000664 0000000 0000000 00000027237 14106520141 0020532 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
"""
Sphinx Auto-API Top-level Extension.
This extension allows you to automagically generate API documentation from your project.
"""
import io
import os
import shutil
import sys
import warnings
import sphinx
from sphinx.util.console import darkgreen, bold
from sphinx.addnodes import toctree
from sphinx.errors import ExtensionError
import sphinx.util.logging
from docutils.parsers.rst import directives
from . import documenters
from .backends import (
DEFAULT_FILE_PATTERNS,
DEFAULT_IGNORE_PATTERNS,
LANGUAGE_MAPPERS,
LANGUAGE_REQUIREMENTS,
)
from .directives import AutoapiSummary, NestedParse
from .inheritance_diagrams import AutoapiInheritanceDiagram
from .settings import API_ROOT
from .toctree import add_domain_to_toctree
LOGGER = sphinx.util.logging.getLogger(__name__)
_DEFAULT_OPTIONS = [
"members",
"undoc-members",
"private-members",
"show-inheritance",
"show-module-summary",
"special-members",
"imported-members",
]
_VIEWCODE_CACHE = {}
"""Caches a module's parse results for use in viewcode.
:type: dict(str, tuple)
"""
class RemovedInAutoAPI2Warning(DeprecationWarning):
"""Indicates something that will be removed in sphinx-autoapi v2."""
if "PYTHONWARNINGS" not in os.environ:
warnings.filterwarnings("default", category=RemovedInAutoAPI2Warning)
def _normalise_autoapi_dirs(autoapi_dirs, srcdir):
normalised_dirs = []
if isinstance(autoapi_dirs, str):
autoapi_dirs = [autoapi_dirs]
for path in autoapi_dirs:
if os.path.isabs(path):
normalised_dirs.append(path)
else:
normalised_dirs.append(os.path.normpath(os.path.join(srcdir, path)))
return normalised_dirs
def run_autoapi(app): # pylint: disable=too-many-branches
"""
Load AutoAPI data from the filesystem.
"""
if app.config.autoapi_type not in LANGUAGE_MAPPERS:
raise ExtensionError(
"Invalid autoapi_type setting, "
"following values is allowed: {}".format(
", ".join(
'"{}"'.format(api_type) for api_type in sorted(LANGUAGE_MAPPERS)
)
)
)
if not app.config.autoapi_dirs:
raise ExtensionError("You must configure an autoapi_dirs setting")
if app.config.autoapi_include_summaries is not None:
warnings.warn(
"autoapi_include_summaries has been replaced by "
"the show-module-summary AutoAPI option\n",
RemovedInAutoAPI2Warning,
)
if app.config.autoapi_include_summaries:
app.config.autoapi_options.append("show-module-summary")
# Make sure the paths are full
normalised_dirs = _normalise_autoapi_dirs(app.config.autoapi_dirs, app.srcdir)
for _dir in normalised_dirs:
if not os.path.exists(_dir):
raise ExtensionError(
"AutoAPI Directory `{dir}` not found. "
"Please check your `autoapi_dirs` setting.".format(dir=_dir)
)
normalized_root = os.path.normpath(
os.path.join(app.srcdir, app.config.autoapi_root)
)
url_root = os.path.join("/", app.config.autoapi_root)
if not all(
import_name in sys.modules
for _, import_name in LANGUAGE_REQUIREMENTS[app.config.autoapi_type]
):
raise ExtensionError(
"AutoAPI of type `{type}` requires following "
"packages to be installed and included in extensions list: "
"{packages}".format(
type=app.config.autoapi_type,
packages=", ".join(
'{import_name} (available as "{pkg_name}" on PyPI)'.format(
pkg_name=pkg_name, import_name=import_name
)
for pkg_name, import_name in LANGUAGE_REQUIREMENTS[
app.config.autoapi_type
]
),
)
)
sphinx_mapper = LANGUAGE_MAPPERS[app.config.autoapi_type]
template_dir = app.config.autoapi_template_dir
if template_dir and not os.path.isabs(template_dir):
if not os.path.isdir(template_dir):
template_dir = os.path.join(app.srcdir, app.config.autoapi_template_dir)
elif app.srcdir != os.getcwd():
warnings.warn(
"autoapi_template_dir will be expected to be "
"relative to the Sphinx source directory instead of "
"relative to where sphinx-build is run\n",
RemovedInAutoAPI2Warning,
)
sphinx_mapper_obj = sphinx_mapper(app, template_dir=template_dir, url_root=url_root)
if app.config.autoapi_file_patterns:
file_patterns = app.config.autoapi_file_patterns
else:
file_patterns = DEFAULT_FILE_PATTERNS.get(app.config.autoapi_type, [])
if app.config.autoapi_ignore:
ignore_patterns = app.config.autoapi_ignore
else:
ignore_patterns = DEFAULT_IGNORE_PATTERNS.get(app.config.autoapi_type, [])
if ".rst" in app.config.source_suffix:
out_suffix = ".rst"
elif ".txt" in app.config.source_suffix:
out_suffix = ".txt"
else:
# Fallback to first suffix listed
out_suffix = app.config.source_suffix[0]
if sphinx_mapper_obj.load(
patterns=file_patterns, dirs=normalised_dirs, ignore=ignore_patterns
):
sphinx_mapper_obj.map(options=app.config.autoapi_options)
if app.config.autoapi_generate_api_docs:
sphinx_mapper_obj.output_rst(root=normalized_root, source_suffix=out_suffix)
def build_finished(app, exception):
if not app.config.autoapi_keep_files and app.config.autoapi_generate_api_docs:
normalized_root = os.path.normpath(
os.path.join(app.srcdir, app.config.autoapi_root)
)
if app.verbosity > 1:
LOGGER.info(bold("[AutoAPI] ") + darkgreen("Cleaning generated .rst files"))
shutil.rmtree(normalized_root)
sphinx_mapper = LANGUAGE_MAPPERS[app.config.autoapi_type]
if hasattr(sphinx_mapper, "build_finished"):
sphinx_mapper.build_finished(app, exception)
def source_read(app, docname, source): # pylint: disable=unused-argument
# temp_data is cleared after each source file has been processed,
# so populate the annotations at the beginning of every file read.
app.env.temp_data["annotations"] = getattr(app.env, "autoapi_annotations", {})
def doctree_read(app, doctree):
"""
Inject AutoAPI into the TOC Tree dynamically.
"""
add_domain_to_toctree(app, doctree, app.env.docname)
if app.env.docname == "index":
all_docs = set()
insert = True
nodes = list(doctree.traverse(toctree))
toc_entry = "%s/index" % app.config.autoapi_root
add_entry = (
nodes
and app.config.autoapi_generate_api_docs
and app.config.autoapi_add_toctree_entry
)
if not add_entry:
return
# Capture all existing toctree entries
for node in nodes:
for entry in node["entries"]:
all_docs.add(entry[1])
# Don't insert autoapi it's already present
for doc in all_docs:
if doc.find(app.config.autoapi_root) != -1:
insert = False
if insert and app.config.autoapi_add_toctree_entry:
# Insert AutoAPI index
nodes[-1]["entries"].append((None, u"%s/index" % app.config.autoapi_root))
nodes[-1]["includefiles"].append(u"%s/index" % app.config.autoapi_root)
message_prefix = bold("[AutoAPI] ")
message = darkgreen(
"Adding AutoAPI TOCTree [{0}] to index.rst".format(toc_entry)
)
LOGGER.info(message_prefix + message)
def viewcode_find(app, modname):
objects = app.env.autoapi_objects
if modname not in objects:
return None
if modname in _VIEWCODE_CACHE:
return _VIEWCODE_CACHE[modname]
locations = {}
module = objects[modname]
for child in module.children:
stack = [("", child)]
while stack:
prefix, obj = stack.pop()
type_ = "other"
if obj.type == "class":
type_ = "class"
elif obj.type in ("function", "method"):
type_ = "def"
full_name = prefix + obj.name
if "from_line_no" in obj.obj:
locations[full_name] = (
type_,
obj.obj["from_line_no"],
obj.obj["to_line_no"],
)
children = getattr(obj, "children", ())
stack.extend((full_name + ".", gchild) for gchild in children)
if module.obj["encoding"]:
source = io.open(
module.obj["file_path"], encoding=module.obj["encoding"]
).read()
else:
source = open(module.obj["file_path"]).read()
result = (source, locations)
_VIEWCODE_CACHE[modname] = result
return result
def viewcode_follow_imported(app, modname, attribute):
fullname = "{}.{}".format(modname, attribute)
all_objects = app.env.autoapi_all_objects
if fullname not in all_objects:
return None
orig_path = all_objects[fullname].obj.get("original_path", "")
if orig_path.endswith(attribute):
return orig_path[: -len(attribute) - 1]
return modname
def setup(app):
app.connect("builder-inited", run_autoapi)
app.connect("source-read", source_read)
app.connect("doctree-read", doctree_read)
app.connect("build-finished", build_finished)
if "viewcode-find-source" in app.events.events:
app.connect("viewcode-find-source", viewcode_find)
if "viewcode-follow-imported" in app.events.events:
app.connect("viewcode-follow-imported", viewcode_follow_imported)
app.add_config_value("autoapi_type", "python", "html")
app.add_config_value("autoapi_root", API_ROOT, "html")
app.add_config_value("autoapi_ignore", [], "html")
app.add_config_value("autoapi_options", _DEFAULT_OPTIONS, "html")
app.add_config_value("autoapi_member_order", "bysource", "html")
app.add_config_value("autoapi_file_patterns", None, "html")
app.add_config_value("autoapi_dirs", [], "html")
app.add_config_value("autoapi_keep_files", False, "html")
app.add_config_value("autoapi_add_toctree_entry", True, "html")
app.add_config_value("autoapi_template_dir", None, "html")
app.add_config_value("autoapi_include_summaries", None, "html")
app.add_config_value("autoapi_python_use_implicit_namespaces", False, "html")
app.add_config_value("autoapi_python_class_content", "class", "html")
app.add_config_value("autoapi_generate_api_docs", True, "html")
app.add_config_value("autoapi_prepare_jinja_env", None, "html")
app.add_autodocumenter(documenters.AutoapiFunctionDocumenter)
app.add_autodocumenter(documenters.AutoapiPropertyDocumenter)
app.add_autodocumenter(documenters.AutoapiDecoratorDocumenter)
app.add_autodocumenter(documenters.AutoapiClassDocumenter)
app.add_autodocumenter(documenters.AutoapiMethodDocumenter)
app.add_autodocumenter(documenters.AutoapiDataDocumenter)
app.add_autodocumenter(documenters.AutoapiAttributeDocumenter)
app.add_autodocumenter(documenters.AutoapiModuleDocumenter)
app.add_autodocumenter(documenters.AutoapiExceptionDocumenter)
directives.register_directive("autoapi-nested-parse", NestedParse)
directives.register_directive("autoapisummary", AutoapiSummary)
app.setup_extension("sphinx.ext.autosummary")
app.add_event("autoapi-skip-member")
app.setup_extension("sphinx.ext.inheritance_diagram")
app.add_directive("autoapi-inheritance-diagram", AutoapiInheritanceDiagram)
return {
"parallel_read_safe": False,
"parallel_write_safe": True,
}
sphinx-autoapi-1.8.4/autoapi/inheritance_diagrams.py 0000664 0000000 0000000 00000010450 14106520141 0022643 0 ustar 00root root 0000000 0000000 import astroid
import sphinx.ext.inheritance_diagram
def _do_import_class(name, currmodule=None):
path_stack = list(reversed(name.split(".")))
if not currmodule:
currmodule = path_stack.pop()
try:
target = astroid.MANAGER.ast_from_module_name(currmodule)
while target and path_stack:
path_part = path_stack.pop()
target = (target.getattr(path_part) or (None,))[0]
while isinstance(target, (astroid.ImportFrom, astroid.Import)):
try:
target = target.do_import_module(path_part)
except astroid.AstroidImportError:
target = target.do_import_module()
target = (target.getattr(path_part) or (None,))[0]
break
except astroid.AstroidError:
target = None
return target
def _import_class(name, currmodule):
target = None
if currmodule:
target = _do_import_class(name, currmodule)
if target is None:
target = _do_import_class(name)
if not target:
raise sphinx.ext.inheritance_diagram.InheritanceException(
"Could not import class or module {} specified for inheritance diagram".format(
name
)
)
if isinstance(target, astroid.ClassDef):
return [target]
if isinstance(target, astroid.Module):
classes = []
for child in target.get_children():
if isinstance(child, astroid.ClassDef):
classes.append(child)
return classes
raise sphinx.ext.inheritance_diagram.InheritanceException(
"{} specified for inheritance diagram is not a class or module".format(name)
)
class _AutoapiInheritanceGraph(sphinx.ext.inheritance_diagram.InheritanceGraph):
@staticmethod
def _import_classes(class_names, currmodule):
classes = []
for name in class_names:
classes.extend(_import_class(name, currmodule))
return classes
def _class_info(
self, classes, show_builtins, private_bases, parts, aliases, top_classes
): # pylint: disable=too-many-arguments
all_classes = {}
def recurse(cls):
if cls in all_classes:
return
if not show_builtins and cls.root().name == "builtins":
return
if not private_bases and cls.name.startswith("_"):
return
nodename = self.class_name(cls, parts, aliases)
fullname = self.class_name(cls, 0, aliases)
tooltip = None
if cls.doc:
doc = cls.doc.strip().split("\n")[0]
if doc:
tooltip = '"%s"' % doc.replace('"', '\\"')
baselist = []
all_classes[cls] = (nodename, fullname, baselist, tooltip)
if fullname in top_classes:
return
for base in cls.ancestors(recurs=False):
if not show_builtins and base.root().name == "builtins":
continue
if not private_bases and base.name.startswith("_"):
continue
baselist.append(self.class_name(base, parts, aliases))
if base not in all_classes:
recurse(base)
for cls in classes:
recurse(cls)
return list(all_classes.values())
@staticmethod
def class_name(node, parts=0, aliases=None):
fullname = node.qname()
if fullname.startswith(("__builtin__.", "builtins")):
fullname = fullname.split(".", 1)[-1]
if parts == 0:
result = fullname
else:
name_parts = fullname.split(".")
result = ".".join(name_parts[-parts:])
if aliases is not None and result in aliases:
return aliases[result]
return result
class AutoapiInheritanceDiagram(sphinx.ext.inheritance_diagram.InheritanceDiagram):
def run(self):
# Yucky! Monkeypatch InheritanceGraph to use our own
old_graph = sphinx.ext.inheritance_diagram.InheritanceGraph
sphinx.ext.inheritance_diagram.InheritanceGraph = _AutoapiInheritanceGraph
try:
return super(AutoapiInheritanceDiagram, self).run()
finally:
sphinx.ext.inheritance_diagram.InheritanceGraph = old_graph
sphinx-autoapi-1.8.4/autoapi/mappers/ 0000775 0000000 0000000 00000000000 14106520141 0017600 5 ustar 00root root 0000000 0000000 sphinx-autoapi-1.8.4/autoapi/mappers/__init__.py 0000664 0000000 0000000 00000000234 14106520141 0021710 0 ustar 00root root 0000000 0000000 from .dotnet import DotNetSphinxMapper
from .python import PythonSphinxMapper
from .go import GoSphinxMapper
from .javascript import JavaScriptSphinxMapper
sphinx-autoapi-1.8.4/autoapi/mappers/base.py 0000664 0000000 0000000 00000025130 14106520141 0021065 0 ustar 00root root 0000000 0000000 import os
import fnmatch
from collections import OrderedDict, namedtuple
import re
from jinja2 import Environment, FileSystemLoader, TemplateNotFound
import sphinx
import sphinx.util
from sphinx.util.console import darkgreen, bold
from sphinx.util.osutil import ensuredir
import sphinx.util.logging
import unidecode
from ..settings import API_ROOT, TEMPLATE_DIR
LOGGER = sphinx.util.logging.getLogger(__name__)
Path = namedtuple("Path", ["absolute", "relative"])
class PythonMapperBase:
"""
Base object for JSON -> Python object mapping.
Subclasses of this object will handle their language specific JSON input,
and map that onto this standard Python object.
Subclasses may also include language-specific attributes on this object.
Arguments:
:param obj: JSON object representing this object
:param jinja_env: A template environment for rendering this object
Required attributes:
:var str id: A globally unique indentifier for this object.
Generally a fully qualified name, including namespace.
:var str name: A short "display friendly" name for this object.
Optional attributes:
:var str docstring: The documentation for this object
:var list imports: Imports in this object
:var list children: Children of this object
:var list parameters: Parameters to this object
:var list methods: Methods on this object
"""
language = "base"
type = "base"
# Create a page in the output for this object.
top_level_object = False
_RENDER_LOG_LEVEL = "VERBOSE"
def __init__(self, obj, jinja_env, app, options=None):
self.app = app
self.obj = obj
self.options = options
self.jinja_env = jinja_env
self.url_root = os.path.join("/", API_ROOT)
self.name = None
self.id = None
def __getstate__(self):
"""Obtains serialisable data for pickling."""
__dict__ = self.__dict__.copy()
__dict__.update(app=None, jinja_env=None) # clear unpickable attributes
return __dict__
def render(self, **kwargs):
LOGGER.log(self._RENDER_LOG_LEVEL, "Rendering %s", self.id)
ctx = {}
try:
template = self.jinja_env.get_template(
"{language}/{type}.rst".format(language=self.language, type=self.type)
)
except TemplateNotFound:
# Use a try/except here so we fallback to language specific defaults, over base defaults
template = self.jinja_env.get_template(
"base/{type}.rst".format(type=self.type)
)
ctx.update(**self.get_context_data())
ctx.update(**kwargs)
return template.render(**ctx)
@property
def rendered(self):
"""Shortcut to render an object in templates."""
return self.render()
def get_context_data(self):
return {
"autoapi_options": self.app.config.autoapi_options,
"include_summaries": self.app.config.autoapi_include_summaries,
"obj": self,
"sphinx_version": sphinx.version_info,
}
def __lt__(self, other):
"""Object sorting comparison"""
if isinstance(other, PythonMapperBase):
return self.id < other.id
return super(PythonMapperBase, self).__lt__(other)
def __str__(self):
return "<{cls} {id}>".format(cls=self.__class__.__name__, id=self.id)
@property
def short_name(self):
"""Shorten name property"""
return self.name.split(".")[-1]
@property
def pathname(self):
"""Sluggified path for filenames
Slugs to a filename using the follow steps
* Decode unicode to approximate ascii
* Remove existing hypens
* Substitute hyphens for non-word characters
* Break up the string as paths
"""
slug = self.name
slug = unidecode.unidecode(slug)
slug = slug.replace("-", "")
slug = re.sub(r"[^\w\.]+", "-", slug).strip("-")
return os.path.join(*slug.split("."))
def include_dir(self, root):
"""Return directory of file"""
parts = [root]
parts.extend(self.pathname.split(os.path.sep))
return "/".join(parts)
@property
def include_path(self):
"""Return 'absolute' path without regarding OS path separator
This is used in ``toctree`` directives, as Sphinx always expects Unix
path separators
"""
parts = [self.include_dir(root=self.url_root)]
parts.append("index")
return "/".join(parts)
@property
def display(self):
"""Whether to display this object or not.
:type: bool
"""
return True
@property
def ref_type(self):
return self.type
@property
def ref_directive(self):
return self.type
class SphinxMapperBase:
"""Base class for mapping `PythonMapperBase` objects to Sphinx.
:param app: Sphinx application instance
"""
def __init__(self, app, template_dir=None, url_root=None):
self.app = app
template_paths = [TEMPLATE_DIR]
if template_dir:
# Put at the front so it's loaded first
template_paths.insert(0, template_dir)
self.jinja_env = Environment(
loader=FileSystemLoader(template_paths),
trim_blocks=True,
lstrip_blocks=True,
)
def _wrapped_prepare(value):
return value
self.jinja_env.filters["prepare_docstring"] = _wrapped_prepare
if self.app.config.autoapi_prepare_jinja_env:
self.app.config.autoapi_prepare_jinja_env(self.jinja_env)
self.url_root = url_root
# Mapping of {filepath -> raw data}
self.paths = OrderedDict()
# Mapping of {object id -> Python Object}
self.objects = OrderedDict()
# Mapping of {object id -> Python Object}
self.all_objects = OrderedDict()
# Mapping of {namespace id -> Python Object}
self.namespaces = OrderedDict()
# Mapping of {namespace id -> Python Object}
self.top_level_objects = OrderedDict()
def load(self, patterns, dirs, ignore=None):
"""
Load objects from the filesystem into the ``paths`` dictionary.
"""
paths = list(self.find_files(patterns=patterns, dirs=dirs, ignore=ignore))
for path in sphinx.util.status_iterator(
paths, bold("[AutoAPI] Reading files... "), "darkgreen", len(paths)
):
data = self.read_file(path=path)
if data:
self.paths[path] = data
return True
@staticmethod
def find_files(patterns, dirs, ignore):
# pylint: disable=too-many-nested-blocks
if not ignore:
ignore = []
pattern_regexes = []
for pattern in patterns:
regex = re.compile(fnmatch.translate(pattern).replace(".*", "(.*)"))
pattern_regexes.append((pattern, regex))
for _dir in dirs:
for root, _, filenames in os.walk(_dir):
seen = set()
for pattern, pattern_re in pattern_regexes:
for filename in fnmatch.filter(filenames, pattern):
skip = False
match = re.match(pattern_re, filename)
norm_name = match.groups()
if norm_name in seen:
continue
# Skip ignored files
for ignore_pattern in ignore:
if fnmatch.fnmatch(
os.path.join(root, filename), ignore_pattern
):
LOGGER.info(
bold("[AutoAPI] ")
+ darkgreen("Ignoring %s/%s" % (root, filename))
)
skip = True
if skip:
continue
# Make sure the path is full
if not os.path.isabs(filename):
filename = os.path.join(root, filename)
yield filename
seen.add(norm_name)
def read_file(self, path, **kwargs):
"""Read file input into memory
:param path: Path of file to read
"""
# TODO support JSON here
# TODO sphinx way of reporting errors in logs?
raise NotImplementedError
def add_object(self, obj):
"""
Add object to local and app environment storage
:param obj: Instance of a AutoAPI object
"""
self.objects[obj.id] = obj
self.all_objects[obj.id] = obj
child_stack = list(obj.children)
while child_stack:
child = child_stack.pop()
self.all_objects[child.id] = child
child_stack.extend(getattr(child, "children", ()))
def map(self, options=None):
"""Trigger find of serialized sources and build objects"""
for _, data in sphinx.util.status_iterator(
self.paths.items(),
bold("[AutoAPI] ") + "Mapping Data... ",
length=len(self.paths),
stringify_func=(lambda x: x[0]),
):
for obj in self.create_class(data, options=options):
self.add_object(obj)
def create_class(self, data, options=None, **kwargs):
"""
Create class object.
:param data: Instance of a AutoAPI object
"""
raise NotImplementedError
def output_rst(self, root, source_suffix):
for _, obj in sphinx.util.status_iterator(
self.objects.items(),
bold("[AutoAPI] ") + "Rendering Data... ",
length=len(self.objects),
verbosity="INFO",
stringify_func=(lambda x: x[0]),
):
rst = obj.render()
if not rst:
continue
detail_dir = obj.include_dir(root=root)
ensuredir(detail_dir)
path = os.path.join(detail_dir, "%s%s" % ("index", source_suffix))
with open(path, "wb+") as detail_file:
detail_file.write(rst.encode("utf-8"))
if self.app.config.autoapi_add_toctree_entry:
self._output_top_rst(root)
def _output_top_rst(self, root):
# Render Top Index
top_level_index = os.path.join(root, "index.rst")
pages = self.objects.values()
with open(top_level_index, "wb") as top_level_file:
content = self.jinja_env.get_template("index.rst")
top_level_file.write(content.render(pages=pages).encode("utf-8"))
sphinx-autoapi-1.8.4/autoapi/mappers/dotnet.py 0000664 0000000 0000000 00000046726 14106520141 0021466 0 ustar 00root root 0000000 0000000 import re
import os
import subprocess
import traceback
import shutil
from collections import defaultdict
import unidecode
import yaml
from sphinx.util.osutil import ensuredir
from sphinx.util.console import darkgreen, bold
import sphinx.util.logging
from sphinx.errors import ExtensionError
from .base import PythonMapperBase, SphinxMapperBase
LOGGER = sphinx.util.logging.getLogger(__name__)
# Doc comment patterns
DOC_COMMENT_PATTERN = r"""
\<%(tag)s
\s+%(attr)s="(?P[^"]*?)"
\s*?
(?:
\/\>|
\>(?P[^\<]*?)\<\/%(tag)s\>
)
"""
DOC_COMMENT_SEE_PATTERN = re.compile(
DOC_COMMENT_PATTERN % {"tag": "(?:see|seealso)", "attr": "cref"}, re.X
)
DOC_COMMENT_PARAM_PATTERN = re.compile(
DOC_COMMENT_PATTERN % {"tag": "(?:paramref|typeparamref)", "attr": "name"}, re.X
)
# Comment member identities
# From: https://msdn.microsoft.com/en-us/library/vstudio/fsbx0t7x(v=VS.100).aspx
DOC_COMMENT_IDENTITIES = {
"N": "dn:ns",
"T": "any", # can be any type (class, delegate, enum, etc), so use any
"F": "dn:field",
"P": "dn:prop",
"M": "dn:meth",
"E": "dn:event",
}
class DotNetSphinxMapper(SphinxMapperBase):
"""Auto API domain handler for .NET
Searches for YAML files, and soon to be JSON files as well, for auto API
sources. If no pattern configuration was explicitly specified, then default
to looking up a ``docfx.json`` file.
:param app: Sphinx application passed in as part of the extension
"""
top_namespaces = {}
DOCFX_OUTPUT_PATH = "_api"
# pylint: disable=arguments-differ
def load(self, patterns, dirs, ignore=None):
"""Load objects from the filesystem into the ``paths`` dictionary.
If the setting ``autoapi_patterns`` was not specified, look for a
``docfx.json`` file by default. A ``docfx.json`` should be treated as
the canonical source before the default patterns. Fallback to default
pattern matches if no ``docfx.json`` files are found.
"""
LOGGER.info(bold("[AutoAPI] ") + darkgreen("Loading Data"))
all_files = set()
if not self.app.config.autoapi_file_patterns:
all_files = set(
self.find_files(patterns=["docfx.json"], dirs=dirs, ignore=ignore)
)
if not all_files:
all_files = set(
self.find_files(patterns=patterns, dirs=dirs, ignore=ignore)
)
if all_files:
command = ["docfx", "metadata", "--raw", "--force"]
command.extend(all_files)
proc = subprocess.Popen(
" ".join(command),
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
shell=True,
env=dict(
(key, os.environ[key])
for key in [
"PATH",
"HOME",
"SYSTEMROOT",
"USERPROFILE",
"WINDIR",
]
if key in os.environ
),
)
_, error_output = proc.communicate()
if error_output:
LOGGER.warning(error_output, type="autoapi", subtype="not_readable")
# We now have yaml files
for xdoc_path in self.find_files(
patterns=["*.yml"], dirs=[self.DOCFX_OUTPUT_PATH], ignore=ignore
):
data = self.read_file(path=xdoc_path)
if data:
self.paths[xdoc_path] = data
return True
def read_file(self, path, **kwargs):
"""Read file input into memory, returning deserialized objects
:param path: Path of file to read
"""
try:
with open(path, "r") as handle:
parsed_data = yaml.safe_load(handle)
return parsed_data
except IOError:
LOGGER.warning(
"Error reading file: {0}".format(path),
type="autoapi",
subtype="not_readable",
)
except TypeError:
LOGGER.warning(
"Error reading file: {0}".format(path),
type="autoapi",
subtype="not_readable",
)
return None
# Subclassed to iterate over items
def map(self, options=None):
"""Trigger find of serialized sources and build objects"""
for _, data in sphinx.util.status_iterator(
self.paths.items(),
bold("[AutoAPI] ") + "Mapping Data... ",
length=len(self.paths),
stringify_func=(lambda x: x[0]),
):
references = data.get("references", [])
for item in data["items"]:
for obj in self.create_class(item, options, references=references):
self.add_object(obj)
self.organize_objects()
def create_class(self, data, options=None, **kwargs):
"""
Return instance of class based on Roslyn type property
Data keys handled here:
type
Set the object class
items
Recurse into :py:meth:`create_class` to create child object
instances
:param data: dictionary data from Roslyn output artifact
"""
kwargs.pop("path", None)
obj_map = {cls.type: cls for cls in ALL_CLASSES}
try:
cls = obj_map[data["type"].lower()]
except KeyError:
# this warning intentionally has no (sub-)type
LOGGER.warning("Unknown type: %s" % data)
else:
obj = cls(
data, jinja_env=self.jinja_env, app=self.app, options=options, **kwargs
)
obj.url_root = self.url_root
# Append child objects
# TODO this should recurse in the case we're getting back more
# complex argument listings
yield obj
def add_object(self, obj):
"""Add object to local and app environment storage
:param obj: Instance of a .NET object
"""
if obj.top_level_object:
if isinstance(obj, DotNetNamespace):
self.namespaces[obj.name] = obj
self.objects[obj.id] = obj
def organize_objects(self):
"""Organize objects and namespaces"""
def _render_children(obj):
for child in obj.children_strings:
child_object = self.objects.get(child)
if child_object:
obj.item_map[child_object.plural].append(child_object)
obj.children.append(child_object)
for key in obj.item_map:
obj.item_map[key].sort()
def _recurse_ns(obj):
if not obj:
return
namespace = obj.top_namespace
if namespace is not None:
ns_obj = self.top_namespaces.get(namespace)
if ns_obj is None or not isinstance(ns_obj, DotNetNamespace):
for ns_obj in self.create_class(
{"uid": namespace, "type": "namespace"}
):
self.top_namespaces[ns_obj.id] = ns_obj
if obj not in ns_obj.children and namespace != obj.id:
ns_obj.children.append(obj)
for obj in self.objects.values():
_render_children(obj)
_recurse_ns(obj)
# Clean out dead namespaces
for key, namespace in self.top_namespaces.copy().items():
if not namespace.children:
del self.top_namespaces[key]
for key, namespace in self.namespaces.copy().items():
if not namespace.children:
del self.namespaces[key]
def output_rst(self, root, source_suffix):
if not self.objects:
raise ExtensionError("No API objects exist. Can't continue")
for _, obj in sphinx.util.status_iterator(
self.objects.items(),
bold("[AutoAPI] ") + "Rendering Data... ",
length=len(self.objects),
stringify_func=(lambda x: x[0]),
):
if not obj or not obj.top_level_object:
continue
rst = obj.render()
if not rst:
continue
detail_dir = os.path.join(root, obj.pathname)
ensuredir(detail_dir)
path = os.path.join(detail_dir, "%s%s" % ("index", source_suffix))
with open(path, "wb") as detail_file:
detail_file.write(rst.encode("utf-8"))
# Render Top Index
top_level_index = os.path.join(root, "index.rst")
with open(top_level_index, "wb") as top_level_file:
content = self.jinja_env.get_template("index.rst")
top_level_file.write(
content.render(pages=self.namespaces.values()).encode("utf-8")
)
@staticmethod
def build_finished(app, _):
if app.verbosity > 1:
LOGGER.info(bold("[AutoAPI] ") + darkgreen("Cleaning generated .yml files"))
if os.path.exists(DotNetSphinxMapper.DOCFX_OUTPUT_PATH):
shutil.rmtree(DotNetSphinxMapper.DOCFX_OUTPUT_PATH)
class DotNetPythonMapper(PythonMapperBase):
"""Base .NET object representation
:param references: object reference list from docfx
:type references: list of dict objects
"""
language = "dotnet"
def __init__(self, obj, **kwargs):
self.references = dict(
(obj.get("uid"), obj)
for obj in kwargs.pop("references", [])
if "uid" in obj
)
super(DotNetPythonMapper, self).__init__(obj, **kwargs)
# Always exist
self.id = obj.get("uid", obj.get("id"))
self.definition = obj.get("definition", self.id)
self.name = obj.get("fullName", self.definition)
# Optional
self.fullname = obj.get("fullName")
self.summary = self.transform_doc_comments(obj.get("summary", ""))
self.parameters = []
self.items = obj.get("items", [])
self.children_strings = obj.get("children", [])
self.children = []
self.item_map = defaultdict(list)
self.inheritance = []
self.assemblies = obj.get("assemblies", [])
# Syntax example and parameter list
syntax = obj.get("syntax", None)
self.example = ""
if syntax is not None:
# Code example
try:
self.example = syntax["content"]
except (KeyError, TypeError):
traceback.print_exc()
self.parameters = []
for param in syntax.get("parameters", []):
if "id" in param:
self.parameters.append(
{
"name": param.get("id"),
"type": self.resolve_spec_identifier(param.get("type")),
"desc": self.transform_doc_comments(
param.get("description", "")
),
}
)
self.returns = {}
self.returns["type"] = self.resolve_spec_identifier(
syntax.get("return", {}).get("type")
)
self.returns["description"] = self.transform_doc_comments(
syntax.get("return", {}).get("description")
)
# Inheritance
# TODO Support more than just a class type here, should support enum/etc
self.inheritance = [
DotNetClass(
{"uid": name, "name": name}, jinja_env=self.jinja_env, app=self.app
)
for name in obj.get("inheritance", [])
]
def __str__(self):
return "<{cls} {id}>".format(cls=self.__class__.__name__, id=self.id)
@property
def pathname(self):
"""Sluggified path for filenames
Slugs to a filename using the follow steps
* Decode unicode to approximate ascii
* Remove existing hypens
* Substitute hyphens for non-word characters
* Break up the string as paths
"""
slug = self.name
try:
slug = self.name.split("(")[0]
except IndexError:
pass
slug = unidecode.unidecode(slug)
slug = slug.replace("-", "")
slug = re.sub(r"[^\w\.]+", "-", slug).strip("-")
return os.path.join(*slug.split("."))
@property
def short_name(self):
"""Shorten name property"""
return self.name.split(".")[-1]
@property
def edit_link(self):
try:
repo = self.source["remote"]["repo"].replace(".git", "")
path = self.path
return "{repo}/blob/master/{path}".format(repo=repo, path=path)
except KeyError:
return ""
@property
def source(self):
return self.obj.get("source")
@property
def path(self):
return self.source["path"]
@property
def namespace(self):
pieces = self.id.split(".")[:-1]
if pieces:
return ".".join(pieces)
return None
@property
def top_namespace(self):
pieces = self.id.split(".")[:2]
if pieces:
return ".".join(pieces)
return None
@property
def ref_type(self):
return self.type
@property
def ref_directive(self):
return self.type
@property
def ref_name(self):
"""Return object name suitable for use in references
Escapes several known strings that cause problems, including the
following reference syntax::
:dotnet:cls:`Foo.Bar`
As the `` notation is also special syntax in references, indicating
the reference to Foo.Bar should be named T.
See: http://sphinx-doc.org/domains.html#role-cpp:any
"""
return self.name.replace("<", r"\<").replace("`", r"\`")
@property
def ref_short_name(self):
"""Same as above, return the truncated name instead"""
return self.ref_name.split(".")[-1]
@staticmethod
def transform_doc_comments(text):
"""
Parse XML content for references and other syntax.
This avoids an LXML dependency, we only need to parse out a small subset
of elements here. Iterate over string to reduce regex pattern complexity
and make substitutions easier
.. seealso::
`Doc comment reference `
Reference on XML documentation comment syntax
"""
try:
while True:
found = DOC_COMMENT_SEE_PATTERN.search(text)
if found is None:
break
ref = found.group("attr_value").replace("<", r"\<").replace("`", r"\`")
reftype = "any"
replacement = ""
# Given the pattern of `\w:\w+`, inspect first letter of
# reference for identity type
if ref[1] == ":" and ref[0] in DOC_COMMENT_IDENTITIES:
reftype = DOC_COMMENT_IDENTITIES[ref[:1]]
ref = ref[2:]
replacement = ":{reftype}:`{ref}`".format(reftype=reftype, ref=ref)
elif ref[:2] == "!:":
replacement = ref[2:]
else:
replacement = ":any:`{ref}`".format(ref=ref)
# Escape following text
text_end = text[found.end() :]
text_start = text[: found.start()]
text_end = re.sub(r"^(\S)", r"\\\1", text_end)
text_start = re.sub(r"(\S)$", r"\1 ", text_start)
text = "".join([text_start, replacement, text_end])
while True:
found = DOC_COMMENT_PARAM_PATTERN.search(text)
if found is None:
break
# Escape following text
text_end = text[found.end() :]
text_start = text[: found.start()]
text_end = re.sub(r"^(\S)", r"\\\1", text_end)
text_start = re.sub(r"(\S)$", r"\1 ", text_start)
text = "".join(
[text_start, "``", found.group("attr_value"), "``", text_end]
)
except TypeError:
pass
return text
def resolve_spec_identifier(self, obj_name):
"""Find reference name based on spec identifier
Spec identifiers are used in parameter and return type definitions, but
should be a user-friendly version instead. Use docfx ``references``
lookup mapping for resolution.
If the spec identifier reference has a ``spec.csharp`` key, this implies
a compound reference that should be linked in a special way. Resolve to
a nested reference, with the corrected nodes.
.. note::
This uses a special format that is interpreted by the domain for
parameter type and return type fields.
:param obj_name: spec identifier to resolve to a correct reference
:returns: resolved string with one or more references
:rtype: str
"""
ref = self.references.get(obj_name)
if ref is None:
return obj_name
resolved = ref.get("fullName", obj_name)
spec = ref.get("spec.csharp", [])
parts = []
for part in spec:
if part.get("name") == "<":
parts.append("{")
elif part.get("name") == ">":
parts.append("}")
elif "fullName" in part and "uid" in part:
parts.append("{fullName}<{uid}>".format(**part))
elif "uid" in part:
parts.append(part["uid"])
elif "fullName" in part:
parts.append(part["fullName"])
if parts:
resolved = "".join(parts)
return resolved
class DotNetNamespace(DotNetPythonMapper):
type = "namespace"
ref_directive = "ns"
plural = "namespaces"
top_level_object = True
class DotNetMethod(DotNetPythonMapper):
type = "method"
ref_directive = "meth"
plural = "methods"
class DotNetOperator(DotNetPythonMapper):
type = "operator"
ref_directive = "op"
plural = "operators"
class DotNetProperty(DotNetPythonMapper):
type = "property"
ref_directive = "prop"
plural = "properties"
class DotNetEnum(DotNetPythonMapper):
type = "enum"
ref_type = "enumeration"
ref_directive = "enum"
plural = "enumerations"
top_level_object = True
class DotNetStruct(DotNetPythonMapper):
type = "struct"
ref_type = "structure"
ref_directive = "struct"
plural = "structures"
top_level_object = True
class DotNetConstructor(DotNetPythonMapper):
type = "constructor"
ref_directive = "ctor"
plural = "constructors"
class DotNetInterface(DotNetPythonMapper):
type = "interface"
ref_directive = "iface"
plural = "interfaces"
top_level_object = True
class DotNetDelegate(DotNetPythonMapper):
type = "delegate"
ref_directive = "del"
plural = "delegates"
top_level_object = True
class DotNetClass(DotNetPythonMapper):
type = "class"
ref_directive = "cls"
plural = "classes"
top_level_object = True
class DotNetField(DotNetPythonMapper):
type = "field"
plural = "fields"
class DotNetEvent(DotNetPythonMapper):
type = "event"
plural = "events"
ALL_CLASSES = [
DotNetNamespace,
DotNetClass,
DotNetEnum,
DotNetStruct,
DotNetInterface,
DotNetDelegate,
DotNetOperator,
DotNetProperty,
DotNetMethod,
DotNetConstructor,
DotNetField,
DotNetEvent,
]
sphinx-autoapi-1.8.4/autoapi/mappers/go.py 0000664 0000000 0000000 00000014156 14106520141 0020566 0 ustar 00root root 0000000 0000000 import json
import subprocess
from sphinx.util.console import bold
import sphinx.util.logging
from .base import PythonMapperBase, SphinxMapperBase
LOGGER = sphinx.util.logging.getLogger(__name__)
class GoSphinxMapper(SphinxMapperBase):
"""Auto API domain handler for Go
Parses directly from Go files.
:param app: Sphinx application passed in as part of the extension
"""
def load(self, patterns, dirs, ignore=None):
"""
Load objects from the filesystem into the ``paths`` dictionary.
"""
for _dir in sphinx.util.status_iterator(
dirs, bold("[AutoAPI] Loading Data "), "darkgreen", len(dirs)
):
data = self.read_file(_dir, ignore=ignore)
if data:
self.paths[_dir] = data
return True
def read_file(self, path, **kwargs):
"""Read file input into memory, returning deserialized objects
:param path: Path of file to read
:param **kwargs:
* ignore (``list``): List of file patterns to ignore
"""
# TODO support JSON here
# TODO sphinx way of reporting errors in logs?
parser_command = ["godocjson"]
_ignore = kwargs.get("ignore")
if _ignore:
parser_command.extend(["-e", "{0}".format("|".join(_ignore))])
parser_command.append(path)
try:
parsed_data = json.loads(subprocess.check_output(parser_command))
return parsed_data
except IOError:
LOGGER.warning(
"Error reading file: {0}".format(path),
type="autoapi",
subtype="not_readable",
)
except TypeError:
LOGGER.warning(
"Error reading file: {0}".format(path),
type="autoapi",
subtype="not_readable",
)
return None
def create_class(self, data, options=None, **kwargs):
"""Return instance of class based on Go data
Data keys handled here:
_type
Set the object class
consts, types, vars, funcs, methods
Recurse into :py:meth:`create_class` to create child object
instances
:param data: dictionary data from godocjson output
"""
_type = kwargs.get("_type")
obj_map = dict((cls.type, cls) for cls in ALL_CLASSES)
try:
# Contextual type data from children recursion
if _type:
LOGGER.debug("Forcing Go Type %s" % _type)
cls = obj_map[_type]
else:
cls = obj_map[data["type"]]
except KeyError:
# this warning intentionally has no (sub-)type
LOGGER.warning("Unknown type: %s" % data)
else:
if cls.inverted_names and "names" in data:
# Handle types that have reversed names parameter
for name in data["names"]:
data_inv = {}
data_inv.update(data)
data_inv["name"] = name
if "names" in data_inv:
del data_inv["names"]
for obj in self.create_class(data_inv):
yield obj
else:
# Recurse for children
obj = cls(data, jinja_env=self.jinja_env, app=self.app)
for child_type in ["consts", "types", "vars", "funcs", "methods"]:
for child_data in data.get(child_type, []):
obj.children += list(
self.create_class(
child_data,
_type=child_type.replace("consts", "const")
.replace("types", "type")
.replace("vars", "variable")
.replace("funcs", "func")
.replace("methods", "method"),
)
)
yield obj
class GoPythonMapper(PythonMapperBase):
language = "go"
inverted_names = False
def __init__(self, obj, **kwargs):
super(GoPythonMapper, self).__init__(obj, **kwargs)
self.name = obj.get("name") or obj.get("packageName")
self.id = self.name
# Second level
self.imports = obj.get("imports", [])
self.children = []
temp_parameters = map(
lambda n: {"name": n["name"], "type": n["type"].lstrip("*")},
obj.get("parameters", []),
)
self.parameters = list(temp_parameters)
self.results = obj.get("results", [])
self.docstring = obj.get("doc", "")
# Go Specific
self.notes = obj.get("notes", {})
self.filenames = obj.get("filenames", [])
self.bugs = obj.get("bugs", [])
def __str__(self):
return "<{cls} {id}>".format(cls=self.__class__.__name__, id=self.id)
@property
def short_name(self):
"""Shorten name property"""
return self.name.split(".")[-1]
@property
def namespace(self):
pieces = self.id.split(".")[:-1]
if pieces:
return ".".join(pieces)
return None
@property
def ref_type(self):
return self.type
@property
def ref_directive(self):
return self.type
@property
def methods(self):
return self.obj.get("methods", [])
class GoVariable(GoPythonMapper):
type = "var"
inverted_names = True
class GoMethod(GoPythonMapper):
type = "method"
ref_directive = "meth"
def __init__(self, obj, **kwargs):
super(GoMethod, self).__init__(obj, **kwargs)
self.receiver = obj.get("recv")
class GoConstant(GoPythonMapper):
type = "const"
inverted_names = True
class GoFunction(GoPythonMapper):
type = "func"
ref_type = "function"
class GoPackage(GoPythonMapper):
type = "package"
ref_directive = "pkg"
top_level_object = True
_RENDER_LOG_LEVEL = "VERBOSE"
class GoType(GoPythonMapper):
type = "type"
ALL_CLASSES = [GoConstant, GoFunction, GoPackage, GoVariable, GoType, GoMethod]
sphinx-autoapi-1.8.4/autoapi/mappers/javascript.py 0000664 0000000 0000000 00000010433 14106520141 0022321 0 ustar 00root root 0000000 0000000 import json
import subprocess
import os
from sphinx.util.console import bold
import sphinx.util.logging
from .base import PythonMapperBase, SphinxMapperBase
LOGGER = sphinx.util.logging.getLogger(__name__)
class JavaScriptSphinxMapper(SphinxMapperBase):
"""Auto API domain handler for Javascript
Parses directly from Javascript files.
:param app: Sphinx application passed in as part of the extension
"""
def read_file(self, path, **kwargs):
"""Read file input into memory, returning deserialized objects
:param path: Path of file to read
"""
# TODO support JSON here
# TODO sphinx way of reporting errors in logs?
subcmd = "jsdoc"
if os.name == "nt":
subcmd = ".".join([subcmd, "cmd"])
try:
parsed_data = json.loads(subprocess.check_output([subcmd, "-X", path]))
return parsed_data
except IOError:
LOGGER.warning(
"Error reading file: {0}".format(path),
type="autoapi",
subtype="not_readable",
)
except TypeError:
LOGGER.warning(
"Error reading file: {0}".format(path),
type="autoapi",
subtype="not_readable",
)
return None
# Subclassed to iterate over items
def map(self, options=None):
"""Trigger find of serialized sources and build objects"""
for _, data in sphinx.util.status_iterator(
self.paths.items(),
bold("[AutoAPI] ") + "Mapping Data... ",
length=len(self.paths),
stringify_func=(lambda x: x[0]),
):
for item in data:
for obj in self.create_class(item, options):
obj.jinja_env = self.jinja_env
self.add_object(obj)
def create_class(self, data, options=None, **kwargs):
"""Return instance of class based on Javascript data
Data keys handled here:
type
Set the object class
consts, types, vars, funcs
Recurse into :py:meth:`create_class` to create child object
instances
:param data: dictionary data from godocjson output
"""
obj_map = dict((cls.type, cls) for cls in ALL_CLASSES)
try:
cls = obj_map[data["kind"]]
except (KeyError, TypeError):
# this warning intentionally has no (sub-)type
LOGGER.warning("Unknown type: %s" % data)
else:
# Recurse for children
obj = cls(data, jinja_env=self.jinja_env, app=self.app)
if "children" in data:
for child_data in data["children"]:
for child_obj in self.create_class(child_data, options=options):
obj.children.append(child_obj)
yield obj
class JavaScriptPythonMapper(PythonMapperBase):
language = "javascript"
def __init__(self, obj, **kwargs):
"""
Map JSON data into Python object.
This is the standard object that will be rendered into the templates,
so we try and keep standard naming to keep templates more re-usable.
"""
super(JavaScriptPythonMapper, self).__init__(obj, **kwargs)
self.name = obj.get("name")
self.id = self.name
# Second level
self.docstring = obj.get("description", "")
# self.docstring = obj.get('comment', '')
self.imports = obj.get("imports", [])
self.children = []
self.parameters = map(
lambda n: {"name": n["name"], "type": n["type"][0]}, obj.get("param", [])
)
class JavaScriptClass(JavaScriptPythonMapper):
type = "class"
ref_directive = "class"
top_level_object = True
class JavaScriptFunction(JavaScriptPythonMapper):
type = "function"
ref_type = "func"
class JavaScriptData(JavaScriptPythonMapper):
type = "data"
ref_directive = "data"
class JavaScriptMember(JavaScriptPythonMapper):
type = "member"
ref_directive = "member"
class JavaScriptAttribute(JavaScriptPythonMapper):
type = "attribute"
ref_directive = "attr"
ALL_CLASSES = [
JavaScriptFunction,
JavaScriptClass,
JavaScriptData,
JavaScriptAttribute,
JavaScriptMember,
]
sphinx-autoapi-1.8.4/autoapi/mappers/python/ 0000775 0000000 0000000 00000000000 14106520141 0021121 5 ustar 00root root 0000000 0000000 sphinx-autoapi-1.8.4/autoapi/mappers/python/__init__.py 0000664 0000000 0000000 00000000326 14106520141 0023233 0 ustar 00root root 0000000 0000000 from .mapper import PythonSphinxMapper
from .objects import (
PythonClass,
PythonFunction,
PythonModule,
PythonMethod,
PythonPackage,
PythonAttribute,
PythonData,
PythonException,
)
sphinx-autoapi-1.8.4/autoapi/mappers/python/astroid_utils.py 0000664 0000000 0000000 00000045333 14106520141 0024370 0 ustar 00root root 0000000 0000000 import builtins
import itertools
import re
import sys
import astroid
import astroid.nodes
# Disable until pylint uses astroid 2.7
import astroid.nodes.node_classes # pylint: disable=no-name-in-module
import sphinx.util.logging
_LOGGER = sphinx.util.logging.getLogger(__name__)
def resolve_import_alias(name, import_names):
"""Resolve a name from an aliased import to its original name.
:param name: The potentially aliased name to resolve.
:type name: str
:param import_names: The pairs of original names and aliases
from the import.
:type import_names: iterable(tuple(str, str or None))
:returns: The original name.
:rtype: str
"""
resolved_name = name
for import_name, imported_as in import_names:
if import_name == name:
break
if imported_as == name:
resolved_name = import_name
break
return resolved_name
def get_full_import_name(import_from, name):
"""Get the full path of a name from a ``from x import y`` statement.
:param import_from: The astroid node to resolve the name of.
:type import_from: astroid.nodes.ImportFrom
:param name:
:type name: str
:returns: The full import path of the name.
:rtype: str
"""
partial_basename = resolve_import_alias(name, import_from.names)
module_name = import_from.modname
if import_from.level:
module = import_from.root()
assert isinstance(module, astroid.nodes.Module)
module_name = module.relative_to_absolute_name(
import_from.modname, level=import_from.level
)
return "{}.{}".format(module_name, partial_basename)
def resolve_qualname(node, basename):
"""Resolve where a node is defined to get its fully qualified name.
:param node: The node representing the base name.
:type node: astroid.NodeNG
:param basename: The partial base name to resolve.
:type basename: str
:returns: The fully resolved base name.
:rtype: str
"""
full_basename = basename
top_level_name = re.sub(r"\(.*\)", "", basename).split(".", 1)[0]
# Disable until pylint uses astroid 2.7
if isinstance(
node, astroid.nodes.node_classes.LookupMixIn # pylint: disable=no-member
):
lookup_node = node
else:
lookup_node = node.scope()
assigns = lookup_node.lookup(top_level_name)[1]
for assignment in assigns:
if isinstance(assignment, astroid.nodes.ImportFrom):
import_name = get_full_import_name(assignment, top_level_name)
full_basename = basename.replace(top_level_name, import_name, 1)
break
if isinstance(assignment, astroid.nodes.Import):
import_name = resolve_import_alias(top_level_name, assignment.names)
full_basename = basename.replace(top_level_name, import_name, 1)
break
if isinstance(assignment, astroid.nodes.ClassDef):
full_basename = assignment.qname()
break
if isinstance(assignment, astroid.nodes.AssignName):
full_basename = "{}.{}".format(assignment.scope().qname(), assignment.name)
if isinstance(node, astroid.nodes.Call):
full_basename = re.sub(r"\(.*\)", "()", full_basename)
if full_basename.startswith("builtins."):
return full_basename[len("builtins.") :]
if full_basename.startswith("__builtin__."):
return full_basename[len("__builtin__.") :]
return full_basename
def get_full_basenames(node):
"""Resolve the partial names of a class' bases to fully qualified names.
:param node: The class definition node to resolve the bases of.
:type: astroid.ClassDef
:returns: The full names.
:rtype: iterable(str)
"""
for base in node.bases:
yield _resolve_annotation(base)
def _get_const_values(node):
value = None
if isinstance(node, (astroid.nodes.List, astroid.nodes.Tuple)):
new_value = []
for element in node.elts:
if isinstance(element, astroid.nodes.Const):
new_value.append(element.value)
elif isinstance(element, (astroid.nodes.List, astroid.nodes.Tuple)):
new_value.append(_get_const_values(element))
else:
break
else:
value = new_value
elif isinstance(node, astroid.nodes.Const):
value = node.value
return value
def get_assign_value(node):
"""Get the name and value of the assignment of the given node.
Assignments to multiple names are ignored, as per PEP 257.
:param node: The node to get the assignment value from.
:type node: astroid.nodes.Assign or astroid.nodes.AnnAssign
:returns: The name that is assigned to,
and the value assigned to the name (if it can be converted).
:rtype: tuple(str, object or None) or None
"""
try:
targets = node.targets
except AttributeError:
targets = [node.target]
if len(targets) == 1:
target = targets[0]
if isinstance(target, astroid.nodes.AssignName):
name = target.name
elif isinstance(target, astroid.nodes.AssignAttr):
name = target.attrname
else:
return None
return (name, _get_const_values(node.value))
return None
def get_assign_annotation(node):
"""Get the type annotation of the assignment of the given node.
:param node: The node to get the annotation for.
:type node: astroid.nodes.Assign or astroid.nodes.AnnAssign
:returns: The type annotation as a string, or None if one does not exist.
:rtype: str or None
"""
annotation_node = None
try:
annotation_node = node.annotation
except AttributeError:
annotation_node = node.type_annotation
return format_annotation(annotation_node)
def is_decorated_with_property(node):
"""Check if the function is decorated as a property.
:param node: The node to check.
:type node: astroid.nodes.FunctionDef
:returns: True if the function is a property, False otherwise.
:rtype: bool
"""
if not node.decorators:
return False
for decorator in node.decorators.nodes:
if not isinstance(decorator, astroid.Name):
continue
try:
if _is_property_decorator(decorator):
return True
except astroid.InferenceError:
pass
return False
def _is_property_decorator(decorator):
def _is_property_class(class_node):
return (
class_node.name == "property"
and class_node.root().name == builtins.__name__
)
for inferred in decorator.infer():
if not isinstance(inferred, astroid.nodes.ClassDef):
continue
if _is_property_class(inferred):
return True
if any(_is_property_class(ancestor) for ancestor in inferred.ancestors()):
return True
return False
def is_decorated_with_property_setter(node):
"""Check if the function is decorated as a property setter.
:param node: The node to check.
:type node: astroid.nodes.FunctionDef
:returns: True if the function is a property setter, False otherwise.
:rtype: bool
"""
if not node.decorators:
return False
for decorator in node.decorators.nodes:
if (
isinstance(decorator, astroid.nodes.Attribute)
and decorator.attrname == "setter"
):
return True
return False
def is_decorated_with_overload(node):
"""Check if the function is decorated as an overload definition.
:param node: The node to check.
:type node: astroid.nodes.FunctionDef
:returns: True if the function is an overload definition, False otherwise.
:rtype: bool
"""
if not node.decorators:
return False
for decorator in node.decorators.nodes:
if not isinstance(decorator, (astroid.Name, astroid.Attribute)):
continue
try:
if _is_overload_decorator(decorator):
return True
except astroid.InferenceError:
pass
return False
def _is_overload_decorator(decorator):
for inferred in decorator.infer():
if not isinstance(inferred, astroid.nodes.FunctionDef):
continue
if inferred.name == "overload" and inferred.root().name == "typing":
return True
return False
def is_constructor(node):
"""Check if the function is a constructor.
:param node: The node to check.
:type node: astroid.nodes.FunctionDef
:returns: True if the function is a constructor, False otherwise.
:rtype: bool
"""
return (
node.parent
and isinstance(node.parent.scope(), astroid.nodes.ClassDef)
and node.name == "__init__"
)
def is_exception(node):
"""Check if a class is an exception.
:param node: The node to check.
:type node: astroid.nodes.ClassDef
:returns: True if the class is an exception, False otherwise.
:rtype: bool
"""
if node.name in ("Exception", "BaseException") and node.root().name == "builtins":
return True
if not hasattr(node, "ancestors"):
return False
return any(is_exception(parent) for parent in node.ancestors(recurs=True))
def is_local_import_from(node, package_name):
"""Check if a node is an import from the local package.
:param node: The node to check.
:type node: astroid.node.NodeNG
:param package_name: The name of the local package.
:type package_name: str
:returns: True if the node is an import from the local package,
False otherwise.
:rtype: bool
"""
if not isinstance(node, astroid.ImportFrom):
return False
return (
node.level
or node.modname == package_name
or node.modname.startswith(package_name + ".")
)
def get_module_all(node):
"""Get the contents of the ``__all__`` variable from a module.
:param node: The module to get ``__all__`` from.
:type node: astroid.nodes.Module
:returns: The contents of ``__all__`` if defined. Otherwise None.
:rtype: list(str) or None
"""
all_ = None
if "__all__" in node.locals:
assigned = next(node.igetattr("__all__"))
if assigned is not astroid.Uninferable:
all_ = []
for elt in getattr(assigned, "elts", ()):
try:
elt_name = next(elt.infer())
except astroid.InferenceError:
continue
if elt_name is astroid.Uninferable:
continue
if isinstance(elt_name, astroid.Const) and isinstance(
elt_name.value, str
):
all_.append(elt_name.value)
return all_
def _is_ellipsis(node):
if sys.version_info < (3, 8):
return isinstance(node, astroid.Ellipsis)
return isinstance(node, astroid.Const) and node.value == Ellipsis
def merge_annotations(annotations, comment_annotations):
for ann, comment_ann in itertools.zip_longest(annotations, comment_annotations):
if ann and not _is_ellipsis(ann):
yield ann
elif comment_ann and not _is_ellipsis(comment_ann):
yield comment_ann
else:
yield None
def _resolve_annotation(annotation):
resolved = None
if isinstance(annotation, astroid.Const):
resolved = resolve_qualname(annotation, str(annotation.value))
elif isinstance(annotation, astroid.Name):
resolved = resolve_qualname(annotation, annotation.name)
elif isinstance(annotation, astroid.Attribute):
resolved = resolve_qualname(annotation, annotation.as_string())
elif isinstance(annotation, astroid.Subscript):
value = _resolve_annotation(annotation.value)
slice_node = annotation.slice
if isinstance(slice_node, astroid.Index):
slice_node = slice_node.value
if isinstance(slice_node, astroid.Tuple):
slice_ = ", ".join(_resolve_annotation(elt) for elt in slice_node.elts)
else:
slice_ = _resolve_annotation(slice_node)
resolved = f"{value}[{slice_}]"
elif isinstance(annotation, astroid.Tuple):
resolved = (
"(" + ", ".join(_resolve_annotation(elt) for elt in annotation.elts) + ")"
)
elif isinstance(annotation, astroid.List):
resolved = (
"[" + ", ".join(_resolve_annotation(elt) for elt in annotation.elts) + "]"
)
else:
resolved = annotation.as_string()
if resolved.startswith("typing."):
return resolved[len("typing.") :]
# Sphinx is capable of linking anything in the same module
# without needing a fully qualified path.
module_prefix = annotation.root().name + "."
if resolved.startswith(module_prefix):
return resolved[len(module_prefix) :]
return resolved
def format_annotation(annotation):
if annotation:
return _resolve_annotation(annotation)
return annotation
def _iter_args(args, annotations, defaults):
default_offset = len(args) - len(defaults)
packed = itertools.zip_longest(args, annotations)
for i, (arg, annotation) in enumerate(packed):
default = None
if defaults is not None and i >= default_offset:
if defaults[i - default_offset] is not None:
default = defaults[i - default_offset].as_string()
name = arg.name
if isinstance(arg, astroid.Tuple):
name = "({})".format(", ".join(x.name for x in arg.elts))
yield (name, format_annotation(annotation), default)
def get_args_info(args_node): # pylint: disable=too-many-branches,too-many-statements
result = []
positional_only_defaults = []
positional_or_keyword_defaults = args_node.defaults
if args_node.defaults:
args = args_node.args or []
positional_or_keyword_defaults = args_node.defaults[-len(args) :]
positional_only_defaults = args_node.defaults[
: len(args_node.defaults) - len(args)
]
plain_annotations = args_node.annotations or ()
func_comment_annotations = args_node.parent.type_comment_args or ()
comment_annotations = args_node.type_comment_posonlyargs
comment_annotations += args_node.type_comment_args or []
comment_annotations += args_node.type_comment_kwonlyargs
annotations = list(
merge_annotations(
plain_annotations,
merge_annotations(func_comment_annotations, comment_annotations),
)
)
annotation_offset = 0
if args_node.posonlyargs:
posonlyargs_annotations = args_node.posonlyargs_annotations
if not any(args_node.posonlyargs_annotations):
num_args = len(args_node.posonlyargs)
posonlyargs_annotations = annotations[
annotation_offset : annotation_offset + num_args
]
for arg, annotation, default in _iter_args(
args_node.posonlyargs, posonlyargs_annotations, positional_only_defaults
):
result.append((None, arg, annotation, default))
result.append(("/", None, None, None))
if not any(args_node.posonlyargs_annotations):
annotation_offset += num_args
if args_node.args:
num_args = len(args_node.args)
for arg, annotation, default in _iter_args(
args_node.args,
annotations[annotation_offset : annotation_offset + num_args],
positional_or_keyword_defaults,
):
result.append((None, arg, annotation, default))
annotation_offset += num_args
if args_node.vararg:
annotation = None
if args_node.varargannotation:
annotation = format_annotation(args_node.varargannotation)
elif len(annotations) > annotation_offset and annotations[annotation_offset]:
annotation = format_annotation(annotations[annotation_offset])
annotation_offset += 1
result.append(("*", args_node.vararg, annotation, None))
if args_node.kwonlyargs:
if not args_node.vararg:
result.append(("*", None, None, None))
kwonlyargs_annotations = args_node.kwonlyargs_annotations
if not any(args_node.kwonlyargs_annotations):
num_args = len(args_node.kwonlyargs)
kwonlyargs_annotations = annotations[
annotation_offset : annotation_offset + num_args
]
for arg, annotation, default in _iter_args(
args_node.kwonlyargs,
kwonlyargs_annotations,
args_node.kw_defaults,
):
result.append((None, arg, annotation, default))
if not any(args_node.kwonlyargs_annotations):
annotation_offset += num_args
if args_node.kwarg:
annotation = None
if args_node.kwargannotation:
annotation = format_annotation(args_node.kwargannotation)
elif len(annotations) > annotation_offset and annotations[annotation_offset]:
annotation = format_annotation(annotations[annotation_offset])
annotation_offset += 1
result.append(("**", args_node.kwarg, annotation, None))
return result
def get_return_annotation(node):
"""Get the return annotation of a node.
:type node: astroid.nodes.FunctionDef
"""
return_annotation = None
if node.returns:
return_annotation = format_annotation(node.returns)
elif node.type_comment_returns:
return_annotation = format_annotation(node.type_comment_returns)
return return_annotation
def get_func_docstring(node):
"""Get the docstring of a node, using a parent docstring if needed.
:param node: The node to get a docstring for.
:type node: astroid.nodes.FunctionDef
"""
doc = node.doc
if doc is None and isinstance(node.parent, astroid.nodes.ClassDef):
for base in node.parent.ancestors():
if node.name in ("__init__", "__new__") and base.qname() in (
"__builtins__.object",
"builtins.object",
"builtins.type",
):
continue
for child in base.get_children():
if (
isinstance(child, node.__class__)
and child.name == node.name
and child.doc is not None
):
return child.doc
return doc or ""
def get_class_docstring(node):
"""Get the docstring of a node, using a parent docstring if needed.
:param node: The node to get a docstring for.
:type node: astroid.nodes.ClassDef
"""
doc = node.doc
if doc is None:
for base in node.ancestors():
if base.qname() in (
"__builtins__.object",
"builtins.object",
"builtins.type",
):
continue
if base.doc is not None:
return base.doc
return doc or ""
sphinx-autoapi-1.8.4/autoapi/mappers/python/mapper.py 0000664 0000000 0000000 00000036317 14106520141 0022771 0 ustar 00root root 0000000 0000000 import collections
import copy
import operator
import os
import re
import sphinx.environment
import sphinx.util
from sphinx.util.console import bold
import sphinx.util.docstrings
import sphinx.util.logging
from ..base import SphinxMapperBase
from .parser import Parser
from .objects import (
PythonClass,
PythonFunction,
PythonModule,
PythonMethod,
PythonPackage,
PythonAttribute,
PythonData,
PythonException,
)
LOGGER = sphinx.util.logging.getLogger(__name__)
def _expand_wildcard_placeholder(original_module, originals_map, placeholder):
"""Expand a wildcard placeholder to a sequence of named placeholders.
:param original_module: The data dictionary of the module
that the placeholder is imported from.
:type original_module: dict
:param originals_map: A map of the names of children under the module
to their data dictionaries.
:type originals_map: dict(str, dict)
:param placeholder: The wildcard placeholder to expand.
:type placeholder: dict
:returns: The placeholders that the wildcard placeholder represents.
:rtype: list(dict)
"""
originals = originals_map.values()
if original_module["all"] is not None:
originals = []
for name in original_module["all"]:
if name == "__all__":
continue
if name not in originals_map:
msg = "Invalid __all__ entry {0} in {1}".format(
name, original_module["name"]
)
LOGGER.warning(msg, type="autoapi", subtype="python_import_resolution")
continue
originals.append(originals_map[name])
placeholders = []
for original in originals:
new_full_name = placeholder["full_name"].replace("*", original["name"])
new_original_path = placeholder["original_path"].replace("*", original["name"])
if "original_path" in original:
new_original_path = original["original_path"]
new_placeholder = dict(
placeholder,
name=original["name"],
full_name=new_full_name,
original_path=new_original_path,
)
placeholders.append(new_placeholder)
return placeholders
def _resolve_module_placeholders(modules, module_name, visit_path, resolved):
"""Resolve all placeholder children under a module.
:param modules: A mapping of module names to their data dictionary.
Placeholders are resolved in place.
:type modules: dict(str, dict)
:param module_name: The name of the module to resolve.
:type module_name: str
:param visit_path: An ordered set of visited module names.
:type visited: collections.OrderedDict
:param resolved: A set of already resolved module names.
:type resolved: set(str)
"""
if module_name in resolved:
return
visit_path[module_name] = True
module, children = modules[module_name]
for child in list(children.values()):
if child["type"] != "placeholder":
continue
if child["original_path"] in modules:
module["children"].remove(child)
children.pop(child["name"])
continue
imported_from, original_name = child["original_path"].rsplit(".", 1)
if imported_from in visit_path:
msg = "Cannot resolve cyclic import: {0}, {1}".format(
", ".join(visit_path), imported_from
)
LOGGER.warning(msg, type="autoapi", subtype="python_import_resolution")
module["children"].remove(child)
children.pop(child["name"])
continue
if imported_from not in modules:
msg = "Cannot resolve import of unknown module {0} in {1}".format(
imported_from, module_name
)
LOGGER.warning(msg, type="autoapi", subtype="python_import_resolution")
module["children"].remove(child)
children.pop(child["name"])
continue
_resolve_module_placeholders(modules, imported_from, visit_path, resolved)
if original_name == "*":
original_module, originals_map = modules[imported_from]
# Replace the wildcard placeholder
# with a list of named placeholders.
new_placeholders = _expand_wildcard_placeholder(
original_module, originals_map, child
)
child_index = module["children"].index(child)
module["children"][child_index : child_index + 1] = new_placeholders
children.pop(child["name"])
for new_placeholder in new_placeholders:
if new_placeholder["name"] not in children:
children[new_placeholder["name"]] = new_placeholder
original = originals_map[new_placeholder["name"]]
_resolve_placeholder(new_placeholder, original)
elif original_name not in modules[imported_from][1]:
msg = "Cannot resolve import of {0} in {1}".format(
child["original_path"], module_name
)
LOGGER.warning(msg, type="autoapi", subtype="python_import_resolution")
module["children"].remove(child)
children.pop(child["name"])
continue
else:
original = modules[imported_from][1][original_name]
_resolve_placeholder(child, original)
del visit_path[module_name]
resolved.add(module_name)
def _resolve_placeholder(placeholder, original):
"""Resolve a placeholder to the given original object.
:param placeholder: The placeholder to resolve, in place.
:type placeholder: dict
:param original: The object that the placeholder represents.
:type original: dict
"""
new = copy.deepcopy(original)
# We are supposed to be resolving the placeholder,
# not replacing it with another.
assert original["type"] != "placeholder"
# The name remains the same.
new["name"] = placeholder["name"]
new["full_name"] = placeholder["full_name"]
# Record where the placeholder originally came from.
new["original_path"] = original["full_name"]
# The source lines for this placeholder do not exist in this file.
# The keys might not exist if original is a resolved placeholder.
new.pop("from_line_no", None)
new.pop("to_line_no", None)
# Resolve the children
stack = list(new.get("children", ()))
while stack:
child = stack.pop()
# Relocate the child to the new location
assert child["full_name"].startswith(original["full_name"])
suffix = child["full_name"][len(original["full_name"]) :]
child["full_name"] = new["full_name"] + suffix
# The source lines for this placeholder do not exist in this file.
# The keys might not exist if original is a resolved placeholder.
child.pop("from_line_no", None)
child.pop("to_line_no", None)
# Resolve the remaining children
stack.extend(child.get("children", ()))
placeholder.clear()
placeholder.update(new)
def _link_objs(value):
result = ""
delims = r"(\s*[\[\]\(\),]\s*)"
delims_re = re.compile(delims)
sub_targets = re.split(delims, value.strip())
for sub_target in sub_targets:
sub_target = sub_target.strip()
if delims_re.match(sub_target):
result += f"{sub_target}"
if sub_target.endswith(","):
result += " "
else:
result += "\\ "
elif sub_target:
result += f":py:obj:`{sub_target}`\\ "
# Strip off the extra "\ "
return result[:-2]
class PythonSphinxMapper(SphinxMapperBase):
"""Auto API domain handler for Python
Parses directly from Python files.
:param app: Sphinx application passed in as part of the extension
"""
_OBJ_MAP = {
cls.type: cls
for cls in (
PythonClass,
PythonFunction,
PythonModule,
PythonMethod,
PythonPackage,
PythonAttribute,
PythonData,
PythonException,
)
}
_OBJ_MAP["property"] = PythonMethod
def __init__(self, app, template_dir=None, url_root=None):
super(PythonSphinxMapper, self).__init__(app, template_dir, url_root)
self.jinja_env.filters["link_objs"] = _link_objs
self._use_implicit_namespace = (
self.app.config.autoapi_python_use_implicit_namespaces
)
def _need_to_load(self, files):
last_files = getattr(self.app.env, "autoapi_source_files", [])
self.app.env.autoapi_source_files = files
last_mtime = getattr(self.app.env, "autoapi_max_mtime", 0)
this_mtime = max(os.path.getmtime(file) for _, file in files)
self.app.env.autoapi_max_mtime = this_mtime
if not self.app.config.autoapi_keep_files:
return True
if self.app.env.config_status != sphinx.environment.CONFIG_OK:
return True
return last_files != files or not last_mtime or last_mtime < this_mtime
def _find_files(self, patterns, dirs, ignore):
for dir_ in dirs:
dir_root = dir_
if (
os.path.exists(os.path.join(dir_, "__init__.py"))
or self._use_implicit_namespace
):
dir_root = os.path.abspath(os.path.join(dir_, os.pardir))
for path in self.find_files(patterns=patterns, dirs=[dir_], ignore=ignore):
yield dir_root, path
def load(self, patterns, dirs, ignore=None):
"""Load objects from the filesystem into the ``paths`` dictionary
Also include an attribute on the object, ``relative_path`` which is the
shortened, relative path the package/module
"""
dir_root_files = list(self._find_files(patterns, dirs, ignore))
if not self._need_to_load(dir_root_files):
LOGGER.debug(
"[AutoAPI] Skipping read stage because source files have not changed."
)
return False
for dir_root, path in sphinx.util.status_iterator(
dir_root_files,
bold("[AutoAPI] Reading files... "),
length=len(dir_root_files),
stringify_func=(lambda x: x[1]),
):
data = self.read_file(path=path, dir_root=dir_root)
if data:
data["relative_path"] = os.path.relpath(path, dir_root)
self.paths[path] = data
return True
def read_file(self, path, **kwargs):
"""Read file input into memory, returning deserialized objects
:param path: Path of file to read
"""
dir_root = kwargs.get("dir_root")
try:
if self._use_implicit_namespace:
parsed_data = Parser().parse_file_in_namespace(path, dir_root)
else:
parsed_data = Parser().parse_file(path)
return parsed_data
except (IOError, TypeError, ImportError):
LOGGER.debug("Reason:", exc_info=True)
LOGGER.warning(
"Unable to read file: {0}".format(path),
type="autoapi",
subtype="not_readable",
)
return None
def _resolve_placeholders(self):
"""Resolve objects that have been imported from elsewhere."""
modules = {}
for module in self.paths.values():
children = {child["name"]: child for child in module["children"]}
modules[module["name"]] = (module, children)
resolved = set()
for module_name in modules:
visit_path = collections.OrderedDict()
_resolve_module_placeholders(modules, module_name, visit_path, resolved)
def map(self, options=None):
self._resolve_placeholders()
self.app.env.autoapi_annotations = {}
super(PythonSphinxMapper, self).map(options)
parents = {obj.name: obj for obj in self.objects.values()}
for obj in self.objects.values():
parent_name = obj.name.rsplit(".", 1)[0]
if parent_name in parents and parent_name != obj.name:
parent = parents[parent_name]
attr = "sub{}s".format(obj.type)
getattr(parent, attr).append(obj)
for obj in self.objects.values():
obj.submodules.sort()
obj.subpackages.sort()
self.app.env.autoapi_objects = self.objects
self.app.env.autoapi_all_objects = self.all_objects
def create_class(self, data, options=None, **kwargs):
"""Create a class from the passed in data
:param data: dictionary data of parser output
"""
try:
cls = self._OBJ_MAP[data["type"]]
except KeyError:
# this warning intentionally has no (sub-)type
LOGGER.warning("Unknown type: %s" % data["type"])
else:
obj = cls(
data,
class_content=self.app.config.autoapi_python_class_content,
options=self.app.config.autoapi_options,
jinja_env=self.jinja_env,
app=self.app,
**kwargs,
)
obj.url_root = self.url_root
for child_data in data.get("children", []):
for child_obj in self.create_class(
child_data, options=options, **kwargs
):
obj.children.append(child_obj)
# Some objects require children to establish their docstring
# or type annotations (eg classes with inheritance),
# so do this after all children have been created.
lines = obj.docstring.splitlines()
lines.append("") # Add back the trailing newline that .splitlines removes
if lines and "autodoc-process-docstring" in self.app.events.events:
self.app.emit(
"autodoc-process-docstring", cls.type, obj.name, None, None, lines
)
obj.docstring = "\n".join(lines)
self._record_typehints(obj)
# Parser gives children in source order already
if self.app.config.autoapi_member_order == "alphabetical":
obj.children.sort(key=operator.attrgetter("name"))
elif self.app.config.autoapi_member_order == "groupwise":
obj.children.sort(key=lambda x: (x.member_order, x.name))
yield obj
def _record_typehints(self, obj):
if (
isinstance(obj, (PythonClass, PythonFunction, PythonMethod))
and not obj.overloads
):
obj_annotations = {}
include_return_annotation = True
obj_data = obj.obj
if isinstance(obj, PythonClass):
constructor = obj.constructor
if constructor:
include_return_annotation = False
obj_data = constructor.obj
else:
return
for _, name, annotation, _ in obj_data["args"]:
if name and annotation:
obj_annotations[name] = annotation
return_annotation = obj_data["return_annotation"]
if include_return_annotation and return_annotation:
obj_annotations["return"] = return_annotation
self.app.env.autoapi_annotations[obj.id] = obj_annotations
sphinx-autoapi-1.8.4/autoapi/mappers/python/objects.py 0000664 0000000 0000000 00000030326 14106520141 0023130 0 ustar 00root root 0000000 0000000 import functools
from typing import Optional
import sphinx.util.logging
from ..base import PythonMapperBase
LOGGER = sphinx.util.logging.getLogger(__name__)
def _format_args(args_info, include_annotations=True, ignore_self=None):
result = []
for i, (prefix, name, annotation, default) in enumerate(args_info):
if i == 0 and name == ignore_self:
continue
formatted = "{}{}{}{}".format(
prefix or "",
name or "",
": {}".format(annotation) if annotation and include_annotations else "",
(" = {}" if annotation else "={}").format(default) if default else "",
)
result.append(formatted)
return ", ".join(result)
class PythonPythonMapper(PythonMapperBase):
"""A base class for all types of representations of Python objects.
:var name: The name given to this object.
:vartype name: str
:var id: A unique identifier for this object.
:vartype id: str
:var children: The members of this object.
:vartype children: list(PythonPythonMapper)
"""
language = "python"
is_callable = False
member_order = 0
def __init__(self, obj, class_content="class", **kwargs):
super(PythonPythonMapper, self).__init__(obj, **kwargs)
self.name = obj["name"]
self.id = obj.get("full_name", self.name)
# Optional
self.children = []
self._docstring = obj["doc"]
self._docstring_resolved = False
self.imported = "original_path" in obj
self.inherited = obj.get("inherited", False)
"""Whether this was inherited from an ancestor of the parent class.
:type: bool
"""
# For later
self._class_content = class_content
self._display_cache = None # type: Optional[bool]
@property
def docstring(self):
"""The docstring for this object.
If a docstring did not exist on the object,
this will be the empty string.
For classes this will also depend on the
:confval:`autoapi_python_class_content` option.
:type: str
"""
return self._docstring
@docstring.setter
def docstring(self, value):
self._docstring = value
self._docstring_resolved = True
@property
def is_undoc_member(self):
"""Whether this object has a docstring (False) or not (True).
:type: bool
"""
return not bool(self.docstring)
@property
def is_private_member(self):
"""Whether this object is private (True) or not (False).
:type: bool
"""
return self.short_name.startswith("_") and not self.short_name.endswith("__")
@property
def is_special_member(self):
"""Whether this object is a special member (True) or not (False).
:type: bool
"""
return self.short_name.startswith("__") and self.short_name.endswith("__")
@property
def display(self):
"""Whether this object should be displayed in documentation.
This attribute depends on the configuration options given in
:confval:`autoapi_options` and the result of :event:`autoapi-skip-member`.
:type: bool
"""
if self._display_cache is None:
self._display_cache = not self._ask_ignore(self._should_skip())
return self._display_cache
@property
def summary(self):
"""The summary line of the docstring.
The summary line is the first non-empty line, as-per :pep:`257`.
This will be the empty string if the object does not have a docstring.
:type: str
"""
for line in self.docstring.splitlines():
line = line.strip()
if line:
return line
return ""
def _should_skip(self): # type: () -> bool
skip_undoc_member = self.is_undoc_member and "undoc-members" not in self.options
skip_private_member = (
self.is_private_member and "private-members" not in self.options
)
skip_special_member = (
self.is_special_member and "special-members" not in self.options
)
skip_imported_member = self.imported and "imported-members" not in self.options
return (
skip_undoc_member
or skip_private_member
or skip_special_member
or skip_imported_member
)
def _ask_ignore(self, skip): # type: (bool) -> bool
ask_result = self.app.emit_firstresult(
"autoapi-skip-member", self.type, self.id, self, skip, self.options
)
return ask_result if ask_result is not None else skip
def _children_of_type(self, type_):
return list(child for child in self.children if child.type == type_)
class PythonFunction(PythonPythonMapper):
"""The representation of a function."""
type = "function"
is_callable = True
member_order = 40
def __init__(self, obj, **kwargs):
super(PythonFunction, self).__init__(obj, **kwargs)
autodoc_typehints = getattr(self.app.config, "autodoc_typehints", "signature")
show_annotations = autodoc_typehints != "none" and not (
autodoc_typehints == "description" and not obj["overloads"]
)
self.args = _format_args(obj["args"], show_annotations)
"""The arguments to this object, formatted as a string.
:type: str
"""
self.return_annotation = obj["return_annotation"] if show_annotations else None
"""The type annotation for the return type of this function.
This will be ``None`` if an annotation
or annotation comment was not given.
:type: str or None
"""
self.properties = obj["properties"]
"""The properties that describe what type of function this is.
Can be only be: async
:type: list(str)
"""
self.overloads = [
(_format_args(args), return_annotation)
for args, return_annotation in obj["overloads"]
]
"""The list of overloaded signatures ``[(args, return_annotation), ...]`` of this function.
:type: list(tuple(str, str))
"""
class PythonMethod(PythonFunction):
"""The representation of a method."""
type = "method"
is_callable = True
member_order = 50
def __init__(self, obj, **kwargs):
super(PythonMethod, self).__init__(obj, **kwargs)
self.method_type = obj.get("method_type")
"""The type of method that this object represents.
This can be one of: method, staticmethod, or classmethod.
:type: str
"""
self.properties = obj["properties"]
"""The properties that describe what type of method this is.
Can be any of: abstractmethod, async, classmethod, property, staticmethod
:type: list(str)
"""
def _should_skip(self): # type: () -> bool
skip = super(PythonMethod, self)._should_skip() or self.name in (
"__new__",
"__init__",
)
return self._ask_ignore(skip)
class PythonData(PythonPythonMapper):
"""Global, module level data."""
type = "data"
member_order = 10
def __init__(self, obj, **kwargs):
super(PythonData, self).__init__(obj, **kwargs)
self.value = obj.get("value")
"""The value of this attribute.
This will be ``None`` if the value is not constant.
:type: str or None
"""
self.annotation = obj.get("annotation")
"""The type annotation of this attribute.
This will be ``None`` if an annotation
or annotation comment was not given.
:type: str or None
"""
class PythonAttribute(PythonData):
"""An object/class level attribute."""
type = "attribute"
member_order = 10
class TopLevelPythonPythonMapper(PythonPythonMapper):
"""A common base class for modules and packages."""
_RENDER_LOG_LEVEL = "VERBOSE"
def __init__(self, obj, **kwargs):
super(TopLevelPythonPythonMapper, self).__init__(obj, **kwargs)
self.top_level_object = "." not in self.name
"""Whether this object is at the very top level (True) or not (False).
This will be False for subpackages and submodules.
:type: bool
"""
self.subpackages = []
self.submodules = []
self.all = obj["all"]
"""The contents of ``__all__`` if assigned to.
Only constants are included.
This will be ``None`` if no ``__all__`` was set.
:type: list(str) or None
"""
@property
def functions(self):
"""All of the member functions.
:type: list(PythonFunction)
"""
return self._children_of_type("function")
@property
def classes(self):
"""All of the member classes.
:type: list(PythonClass)
"""
return self._children_of_type("class")
class PythonModule(TopLevelPythonPythonMapper):
"""The representation of a module."""
type = "module"
class PythonPackage(TopLevelPythonPythonMapper):
"""The representation of a package."""
type = "package"
class PythonClass(PythonPythonMapper):
"""The representation of a class."""
type = "class"
member_order = 30
def __init__(self, obj, **kwargs):
super(PythonClass, self).__init__(obj, **kwargs)
self.bases = obj["bases"]
"""The fully qualified names of all base classes.
:type: list(str)
"""
@property
def args(self):
"""The arguments to this object, formatted as a string.
:type: str
"""
args = ""
if self.constructor:
autodoc_typehints = getattr(
self.app.config, "autodoc_typehints", "signature"
)
show_annotations = autodoc_typehints != "none" and not (
autodoc_typehints == "description" and not self.constructor.overloads
)
args_data = self.constructor.obj["args"]
args = _format_args(args_data, show_annotations, ignore_self="self")
return args
@property
def overloads(self):
overloads = []
if self.constructor:
overload_data = self.constructor.obj["overloads"]
autodoc_typehints = getattr(
self.app.config, "autodoc_typehints", "signature"
)
show_annotations = autodoc_typehints not in ("none", "description")
overloads = [
(
_format_args(args, show_annotations, ignore_self="self"),
return_annotation,
)
for args, return_annotation in overload_data
]
return overloads
@property
def docstring(self):
docstring = super().docstring
if not self._docstring_resolved and self._class_content in ("both", "init"):
constructor_docstring = self.constructor_docstring
if constructor_docstring:
if self._class_content == "both":
docstring = "{0}\n{1}".format(docstring, constructor_docstring)
else:
docstring = constructor_docstring
return docstring
@docstring.setter
def docstring(self, value):
super(PythonClass, self.__class__).docstring.fset(self, value)
@property
def methods(self):
return self._children_of_type("method")
@property
def attributes(self):
return self._children_of_type("attribute")
@property
def classes(self):
return self._children_of_type("class")
@property
@functools.lru_cache()
def constructor(self):
for child in self.children:
if child.short_name == "__init__":
return child
return None
@property
def constructor_docstring(self):
docstring = ""
constructor = self.constructor
if constructor and constructor.docstring:
docstring = constructor.docstring
else:
for child in self.children:
if child.short_name == "__new__":
docstring = child.docstring
break
return docstring
class PythonException(PythonClass):
"""The representation of an exception class."""
type = "exception"
member_order = 20
sphinx-autoapi-1.8.4/autoapi/mappers/python/parser.py 0000664 0000000 0000000 00000021674 14106520141 0023001 0 ustar 00root root 0000000 0000000 import collections
import itertools
import os
import astroid
import astroid.builder
import sphinx.util.docstrings
from . import astroid_utils
def _prepare_docstring(doc):
return "\n".join(sphinx.util.docstrings.prepare_docstring(doc))
class Parser:
def __init__(self):
self._name_stack = []
self._encoding = None
def _get_full_name(self, name):
return ".".join(self._name_stack + [name])
def _parse_file(self, file_path, condition):
directory, filename = os.path.split(file_path)
module_parts = []
if filename != "__init__.py":
module_part = os.path.splitext(filename)[0]
module_parts = [module_part]
module_parts = collections.deque(module_parts)
while directory and condition(directory):
directory, module_part = os.path.split(directory)
if module_part:
module_parts.appendleft(module_part)
module_name = ".".join(module_parts)
node = astroid.builder.AstroidBuilder().file_build(file_path, module_name)
return self.parse(node)
def parse_file(self, file_path):
return self._parse_file(
file_path,
lambda directory: os.path.isfile(os.path.join(directory, "__init__.py")),
)
def parse_file_in_namespace(self, file_path, dir_root):
return self._parse_file(
file_path, lambda directory: os.path.abspath(directory) != dir_root
)
def parse_annassign(self, node):
return self.parse_assign(node)
def parse_assign(self, node):
doc = ""
doc_node = node.next_sibling()
if isinstance(doc_node, astroid.nodes.Expr) and isinstance(
doc_node.value, astroid.nodes.Const
):
doc = doc_node.value.value
type_ = "data"
if isinstance(
node.scope(), astroid.nodes.ClassDef
) or astroid_utils.is_constructor(node.scope()):
type_ = "attribute"
assign_value = astroid_utils.get_assign_value(node)
if not assign_value:
return []
target = assign_value[0]
value = assign_value[1]
annotation = astroid_utils.get_assign_annotation(node)
data = {
"type": type_,
"name": target,
"full_name": self._get_full_name(target),
"doc": _prepare_docstring(doc),
"value": value,
"from_line_no": node.fromlineno,
"to_line_no": node.tolineno,
"annotation": annotation,
}
return [data]
def parse_classdef(self, node, data=None):
type_ = "class"
if astroid_utils.is_exception(node):
type_ = "exception"
basenames = list(astroid_utils.get_full_basenames(node))
data = {
"type": type_,
"name": node.name,
"full_name": self._get_full_name(node.name),
"bases": basenames,
"doc": _prepare_docstring(astroid_utils.get_class_docstring(node)),
"from_line_no": node.fromlineno,
"to_line_no": node.tolineno,
"children": [],
}
self._name_stack.append(node.name)
overridden = set()
overloads = {}
for base in itertools.chain(iter((node,)), node.ancestors()):
seen = set()
if base.qname() in (
"__builtins__.object",
"builtins.object",
"builtins.type",
):
continue
for child in base.get_children():
name = getattr(child, "name", None)
if isinstance(child, (astroid.Assign, astroid.AnnAssign)):
assign_value = astroid_utils.get_assign_value(child)
if not assign_value:
continue
name = assign_value[0]
if not name or name in overridden:
continue
seen.add(name)
child_data = self.parse(child)
data["children"].extend(
_parse_child(node, child_data, overloads, base, name)
)
overridden.update(seen)
self._name_stack.pop()
return [data]
def parse_asyncfunctiondef(self, node):
return self.parse_functiondef(node)
def parse_functiondef(self, node): # pylint: disable=too-many-branches
if astroid_utils.is_decorated_with_property_setter(node):
return []
type_ = "method"
properties = []
if node.type == "function":
type_ = "function"
elif astroid_utils.is_decorated_with_property(node):
type_ = "property"
properties.append("property")
else:
# "__new__" method is implicit classmethod
if node.type in ("staticmethod", "classmethod") and node.name != "__new__":
properties.append(node.type)
if node.is_abstract(pass_is_abstract=False):
properties.append("abstractmethod")
if isinstance(node, astroid.AsyncFunctionDef):
properties.append("async")
data = {
"type": type_,
"name": node.name,
"full_name": self._get_full_name(node.name),
"args": astroid_utils.get_args_info(node.args),
"doc": _prepare_docstring(astroid_utils.get_func_docstring(node)),
"from_line_no": node.fromlineno,
"to_line_no": node.tolineno,
"return_annotation": astroid_utils.get_return_annotation(node),
"properties": properties,
"is_overload": astroid_utils.is_decorated_with_overload(node),
"overloads": [],
}
if type_ in ("method", "property"):
data["method_type"] = node.type
result = [data]
if node.name == "__init__":
for child in node.get_children():
if isinstance(child, (astroid.nodes.Assign, astroid.nodes.AnnAssign)):
child_data = self.parse_assign(child)
result.extend(data for data in child_data if data["doc"])
return result
def _parse_local_import_from(self, node):
result = []
for name, alias in node.names:
is_wildcard = (alias or name) == "*"
full_name = self._get_full_name(alias or name)
original_path = astroid_utils.get_full_import_name(node, alias or name)
data = {
"type": "placeholder",
"name": original_path if is_wildcard else (alias or name),
"full_name": full_name,
"original_path": original_path,
}
result.append(data)
return result
def parse_module(self, node):
path = node.path
if isinstance(node.path, list):
path = node.path[0] if node.path else None
type_ = "module"
if node.package:
type_ = "package"
self._name_stack = [node.name]
self._encoding = node.file_encoding
data = {
"type": type_,
"name": node.name,
"full_name": node.name,
"doc": _prepare_docstring(node.doc or ""),
"children": [],
"file_path": path,
"encoding": node.file_encoding,
"all": astroid_utils.get_module_all(node),
}
overloads = {}
top_name = node.name.split(".", 1)[0]
for child in node.get_children():
if astroid_utils.is_local_import_from(child, top_name):
child_data = self._parse_local_import_from(child)
else:
child_data = self.parse(child)
data["children"].extend(_parse_child(node, child_data, overloads))
return data
def parse(self, node):
data = {}
node_type = node.__class__.__name__.lower()
parse_func = getattr(self, "parse_" + node_type, None)
if parse_func:
data = parse_func(node)
else:
for child in node.get_children():
data = self.parse(child)
if data:
break
return data
def _parse_child(node, child_data, overloads, base=None, name=None):
result = []
for single_data in child_data:
if single_data["type"] in ("function", "method", "property"):
if name is None:
name = single_data["name"]
if name in overloads:
grouped = overloads[name]
grouped["doc"] = single_data["doc"]
if single_data["is_overload"]:
grouped["overloads"].append(
(single_data["args"], single_data["return_annotation"])
)
continue
if single_data["is_overload"] and name not in overloads:
overloads[name] = single_data
if base:
single_data["inherited"] = base is not node
result.append(single_data)
return result
sphinx-autoapi-1.8.4/autoapi/settings.py 0000664 0000000 0000000 00000000337 14106520141 0020346 0 ustar 00root root 0000000 0000000 """
Basic settings for AutoAPI projects.
You shouldn't need to touch this.
"""
import os
SITE_ROOT = os.path.dirname(os.path.realpath(__file__))
TEMPLATE_DIR = os.path.join(SITE_ROOT, "templates")
API_ROOT = "autoapi"
sphinx-autoapi-1.8.4/autoapi/templates/ 0000775 0000000 0000000 00000000000 14106520141 0020127 5 ustar 00root root 0000000 0000000 sphinx-autoapi-1.8.4/autoapi/templates/base/ 0000775 0000000 0000000 00000000000 14106520141 0021041 5 ustar 00root root 0000000 0000000 sphinx-autoapi-1.8.4/autoapi/templates/base/base.rst 0000664 0000000 0000000 00000000130 14106520141 0022477 0 ustar 00root root 0000000 0000000 .. {{ obj.type }}:: {{ obj.name }}
{% if summary %}
{{ obj.summary }}
{% endif %}
sphinx-autoapi-1.8.4/autoapi/templates/dotnet/ 0000775 0000000 0000000 00000000000 14106520141 0021424 5 ustar 00root root 0000000 0000000 sphinx-autoapi-1.8.4/autoapi/templates/dotnet/base_detail.rst 0000664 0000000 0000000 00000002534 14106520141 0024416 0 ustar 00root root 0000000 0000000 {% block title %}
{{ obj.short_name }} {{ obj.type.title()}}
{{ "=" * (obj.short_name|length + obj.type|length + 1) }}
{% endblock %}
{% block summary %}
{% if obj.summary %}
{{ obj.summary }}
{% endif %}
{% endblock %}
{% if obj.namespace %}
Namespace
:dn:ns:`{{ obj.namespace }}`
{% endif %}
{% if obj.assemblies %}
Assemblies
{% for assembly in obj.assemblies %}
* {{ assembly }}
{% endfor %}
{% endif %}
----
.. contents::
:local:
{% block inheritance %}
{% if obj.inheritance %}
Inheritance Hierarchy
---------------------
{% for item in obj.inheritance %}
* :dn:{{ item.ref_directive }}:`{{ item.ref_name }}`
{% endfor %}
* :dn:{{ obj.ref_directive }}:`{{ obj.ref_name }}`
{% endif %}
{% endblock %}
{% block syntax %}
{% if obj.example %}
Syntax
------
.. code-block:: csharp
{{ obj.example|indent(4) }}
{% endif %}
{% endblock %}
{% block content %}
.. dn:{{ obj.ref_type }}:: {{ obj.definition }}
:hidden:
.. dn:{{ obj.ref_type }}:: {{ obj.name }}
{% for item_type in obj.item_map.keys() %}
{% if item_type in obj.item_map %}
{{ item_type.title() }}
{{ "-" * item_type|length }}
.. dn:{{ obj.ref_type }}:: {{ obj.name }}
:noindex:
:hidden:
{% for obj_item in obj.item_map.get(item_type, []) %}
{{ obj_item.render()|indent(4) }}
{% endfor %}
{% endif %}
{% endfor %}
{% endblock %}
sphinx-autoapi-1.8.4/autoapi/templates/dotnet/base_embed.rst 0000664 0000000 0000000 00000001235 14106520141 0024225 0 ustar 00root root 0000000 0000000 .. dn:{{ obj.ref_type }}:: {{ obj.name }}
{% if obj.summary %}
{{ obj.summary|indent(4) }}
{% endif %}
{% for param in obj.parameters %}
{% if param.desc %}
:param {{ param.name }}: {{ param.desc|indent(8) }}
{% endif %}
{% if param.type %}
:type {{ param.name }}: {{ param.type|indent(8) }}
{% endif %}
{% endfor %}
{% if obj.returns.type %}
:rtype: {{ obj.returns.type|indent(8) }}
{% endif %}
{% if obj.returns.description %}
:return: {{ obj.returns.description|indent(8) }}
{% endif %}
{% if obj.example %}
.. code-block:: csharp
{{ obj.example|indent(8) }}
{% endif %}
sphinx-autoapi-1.8.4/autoapi/templates/dotnet/base_list.rst 0000664 0000000 0000000 00000002226 14106520141 0024125 0 ustar 00root root 0000000 0000000 {% block title %}
{{ obj.name }} {{ obj.type.title() }}
{{ "=" * (obj.name|length + obj.type|length + 1) }}
{% endblock %}
{% block toc %}
{% if obj.children %}
.. toctree::
:hidden:
:maxdepth: 2
{% for item in obj.children|sort %}
{% if item.type != 'namespace' %}
{{ item.include_path }}
{% endif %}
{% endfor %}
{% endif %}
{% if obj.references %}
.. toctree::
:hidden:
:maxdepth: 2
{% for item in obj.references|sort %}
{% if item.type != 'namespace' %}
{{ item.include_path }}
{% endif %}
{% endfor %}
{% endif %}
{% endblock %}
{% block content %}
{% macro display_type(item_type) %}
.. rubric:: {{ item_type.title() }}
{% for obj_item in obj.item_map.get(item_type, []) %}
{% macro render() %}{{ obj_item.summary }}{% endmacro %}
{{ obj_item.type }} :dn:{{ obj_item.ref_directive }}:`{{ obj_item.ref_short_name }}`
.. object: type={{ obj_item.type }} name={{ obj_item.ref_name }}
{{ render()|indent(8) }}
{% endfor %}
{% endmacro %}
.. dn:{{ obj.ref_type }}:: {{ obj.name }}
{% for item_type in obj.item_map.keys() %}
{{ display_type(item_type) }}
{% endfor %}
{% endblock %}
sphinx-autoapi-1.8.4/autoapi/templates/dotnet/class.rst 0000664 0000000 0000000 00000000046 14106520141 0023263 0 ustar 00root root 0000000 0000000 {% extends "dotnet/base_detail.rst" %} sphinx-autoapi-1.8.4/autoapi/templates/dotnet/constructor.rst 0000664 0000000 0000000 00000000045 14106520141 0024542 0 ustar 00root root 0000000 0000000 {% extends "dotnet/base_embed.rst" %} sphinx-autoapi-1.8.4/autoapi/templates/dotnet/delegate.rst 0000664 0000000 0000000 00000000046 14106520141 0023730 0 ustar 00root root 0000000 0000000 {% extends "dotnet/base_detail.rst" %} sphinx-autoapi-1.8.4/autoapi/templates/dotnet/enum.rst 0000664 0000000 0000000 00000000046 14106520141 0023122 0 ustar 00root root 0000000 0000000 {% extends "dotnet/base_detail.rst" %} sphinx-autoapi-1.8.4/autoapi/templates/dotnet/event.rst 0000664 0000000 0000000 00000000045 14106520141 0023276 0 ustar 00root root 0000000 0000000 {% extends "dotnet/base_embed.rst" %} sphinx-autoapi-1.8.4/autoapi/templates/dotnet/field.rst 0000664 0000000 0000000 00000000045 14106520141 0023240 0 ustar 00root root 0000000 0000000 {% extends "dotnet/base_embed.rst" %} sphinx-autoapi-1.8.4/autoapi/templates/dotnet/interface.rst 0000664 0000000 0000000 00000000046 14106520141 0024116 0 ustar 00root root 0000000 0000000 {% extends "dotnet/base_detail.rst" %} sphinx-autoapi-1.8.4/autoapi/templates/dotnet/method.rst 0000664 0000000 0000000 00000000045 14106520141 0023435 0 ustar 00root root 0000000 0000000 {% extends "dotnet/base_embed.rst" %} sphinx-autoapi-1.8.4/autoapi/templates/dotnet/namespace.rst 0000664 0000000 0000000 00000000044 14106520141 0024110 0 ustar 00root root 0000000 0000000 {% extends "dotnet/base_list.rst" %} sphinx-autoapi-1.8.4/autoapi/templates/dotnet/operator.rst 0000664 0000000 0000000 00000000045 14106520141 0024010 0 ustar 00root root 0000000 0000000 {% extends "dotnet/base_embed.rst" %} sphinx-autoapi-1.8.4/autoapi/templates/dotnet/property.rst 0000664 0000000 0000000 00000000045 14106520141 0024041 0 ustar 00root root 0000000 0000000 {% extends "dotnet/base_embed.rst" %} sphinx-autoapi-1.8.4/autoapi/templates/dotnet/struct.rst 0000664 0000000 0000000 00000000046 14106520141 0023502 0 ustar 00root root 0000000 0000000 {% extends "dotnet/base_detail.rst" %} sphinx-autoapi-1.8.4/autoapi/templates/go/ 0000775 0000000 0000000 00000000000 14106520141 0020534 5 ustar 00root root 0000000 0000000 sphinx-autoapi-1.8.4/autoapi/templates/go/base_member.rst 0000664 0000000 0000000 00000001662 14106520141 0023534 0 ustar 00root root 0000000 0000000 {% if obj.type == 'func' %}
{# Creating the parameters line #}
{% set ns = namespace(tmpstring='') %}
{% set argjoin = joiner(', ') %}
{% for param in obj.parameters %}
{% set ns.tmpstring = ns.tmpstring ~ argjoin() ~ param.name ~ ' ' ~ param.type %}
{% endfor %}
.. go:{{ obj.ref_type }}:: {{ obj.name }}({{ ns.tmpstring }})
{% else %}
.. go:{{ obj.ref_type }}:: {{ obj.name }}
{% endif %}
{% macro render() %}{{ obj.docstring }}{% endmacro %}
{{ render()|indent(4) }}
{# Don't define parameter description here, that can be done in the block
above #}
{% for param in obj.parameters %}
:param {{ param.name }}:
:type {{ param.name }}: {{ param.type }}
{% endfor %}
{% if obj.returns %}
:rtype: {{ obj.returns.type }}
{% endif %}
{% if obj.children %}
{% for child in obj.children|sort %}
{% macro render_child() %}{{ child.render() }}{% endmacro %}
{{ render_child()|indent(4) }}
{% endfor %}
{% endif %}
sphinx-autoapi-1.8.4/autoapi/templates/go/const.rst 0000664 0000000 0000000 00000000043 14106520141 0022411 0 ustar 00root root 0000000 0000000 {% extends "go/base_member.rst" %}
sphinx-autoapi-1.8.4/autoapi/templates/go/func.rst 0000664 0000000 0000000 00000000043 14106520141 0022216 0 ustar 00root root 0000000 0000000 {% extends "go/base_member.rst" %}
sphinx-autoapi-1.8.4/autoapi/templates/go/method.rst 0000664 0000000 0000000 00000000043 14106520141 0022543 0 ustar 00root root 0000000 0000000 {% extends "go/base_member.rst" %}
sphinx-autoapi-1.8.4/autoapi/templates/go/package.rst 0000664 0000000 0000000 00000001041 14106520141 0022655 0 ustar 00root root 0000000 0000000 .. go:package:: {{ obj.name }}
{{ obj.name }}
{{ "=" * obj.name|length }}
{% block toc %}
{% if obj.children %}
{# TODO Make this work
.. toctree::
:maxdepth: 4
{% for item in obj.children|sort %}
/autoapi/{{ item.id.split('.')|join('/') }}/index
{% endfor %}
#}
{% endif %}
{% endblock %}
{% if obj.docstring %}
{{ obj.docstring }}
{% endif %}
{% block content %}
{% for obj_item in obj.children|sort %}
{% macro render() %}{{ obj_item.render() }}{% endmacro %}
{{ render()|indent(0) }}
{% endfor %}
{% endblock %}
sphinx-autoapi-1.8.4/autoapi/templates/go/type.rst 0000664 0000000 0000000 00000000043 14106520141 0022244 0 ustar 00root root 0000000 0000000 {% extends "go/base_member.rst" %}
sphinx-autoapi-1.8.4/autoapi/templates/go/var.rst 0000664 0000000 0000000 00000000043 14106520141 0022053 0 ustar 00root root 0000000 0000000 {% extends "go/base_member.rst" %}
sphinx-autoapi-1.8.4/autoapi/templates/index.rst 0000664 0000000 0000000 00000000543 14106520141 0021772 0 ustar 00root root 0000000 0000000 API Reference
=============
This page contains auto-generated API reference documentation [#f1]_.
.. toctree::
:titlesonly:
{% for page in pages %}
{% if page.top_level_object and page.display %}
{{ page.include_path }}
{% endif %}
{% endfor %}
.. [#f1] Created with `sphinx-autoapi `_
sphinx-autoapi-1.8.4/autoapi/templates/javascript/ 0000775 0000000 0000000 00000000000 14106520141 0022275 5 ustar 00root root 0000000 0000000 sphinx-autoapi-1.8.4/autoapi/templates/javascript/class.rst 0000664 0000000 0000000 00000000565 14106520141 0024142 0 ustar 00root root 0000000 0000000 .. js:class:: {{ obj.name }}{% if obj.args %}({{ obj.args|join(',') }}){% endif %}
{% if obj.docstring %}
.. rubric:: Summary
{{ obj.docstring|indent(3) }}
{% endif %}
{% if obj.methods %}
{% for method in obj.methods %}
{% macro render() %}{{ method.render() }}{% endmacro %}
{{ render()|indent(3) }}
{%- endfor %}
{% endif %}
sphinx-autoapi-1.8.4/autoapi/templates/javascript/function.rst 0000664 0000000 0000000 00000000505 14106520141 0024654 0 ustar 00root root 0000000 0000000 {# Identention in this file is important #}
{% if is_method %}
{# Slice self off #}
.. js:method:: {{ obj.name.split('.')[-1] }}({{ args[1:]|join(',') }})
{% else %}
.. js:function:: {{ obj.name.split('.')[-1] }}({{ args|join(',') }})
{% endif %}
{% if obj.docstring %}
{{ obj.docstring|indent(3) }}
{% endif %}
sphinx-autoapi-1.8.4/autoapi/templates/javascript/member.rst 0000664 0000000 0000000 00000000167 14106520141 0024302 0 ustar 00root root 0000000 0000000 {# Identention in this file is important #}
.. js:{{ obj.type }}:: {{ obj.name }}
{{ obj.docstring|indent(3) }}
sphinx-autoapi-1.8.4/autoapi/templates/javascript/module.rst 0000664 0000000 0000000 00000001426 14106520141 0024317 0 ustar 00root root 0000000 0000000 {{ obj.name }}
{{ "-" * obj.name|length }}
{% block toc %}
{% if obj.children %}
.. toctree::
:maxdepth: 4
{% for item in obj.children|sort %}
/autoapi/{{ item.pathname }}/index
{%- endfor %}
{% endif %}
{% endblock %}
{% if obj.docstring %}
.. rubric:: Summary
{{ obj.docstring }}
{% endif %}
.. js:module:: {{ obj.name }}
{% block content %}
{%- macro display_type(item_type) %}
{{ item_type.title() }}
{{ "*" * item_type|length }}
{%- for obj_item in obj.item_map.get(item_type, []) %}
{% macro render() %}{{ obj_item.render() }}{% endmacro %}
{{ render()|indent(4) }}
{%- endfor %}
{%- endmacro %}
{%- for item_type in obj.item_map.keys() %}
{% if item_type.lower() != 'module' %}
{{ display_type(item_type) }}
{% endif %}
{%- endfor %}
{% endblock %}
sphinx-autoapi-1.8.4/autoapi/templates/python/ 0000775 0000000 0000000 00000000000 14106520141 0021450 5 ustar 00root root 0000000 0000000 sphinx-autoapi-1.8.4/autoapi/templates/python/attribute.rst 0000664 0000000 0000000 00000000040 14106520141 0024177 0 ustar 00root root 0000000 0000000 {% extends "python/data.rst" %}
sphinx-autoapi-1.8.4/autoapi/templates/python/class.rst 0000664 0000000 0000000 00000003504 14106520141 0023311 0 ustar 00root root 0000000 0000000 {% if obj.display %}
.. py:{{ obj.type }}:: {{ obj.short_name }}{% if obj.args %}({{ obj.args }}){% endif %}
{% for (args, return_annotation) in obj.overloads %}
{{ " " * (obj.type | length) }} {{ obj.short_name }}{% if args %}({{ args }}){% endif %}
{% endfor %}
{% if obj.bases %}
{% if "show-inheritance" in autoapi_options %}
Bases: {% for base in obj.bases %}{{ base|link_objs }}{% if not loop.last %}, {% endif %}{% endfor %}
{% endif %}
{% if "show-inheritance-diagram" in autoapi_options and obj.bases != ["object"] %}
.. autoapi-inheritance-diagram:: {{ obj.obj["full_name"] }}
:parts: 1
{% if "private-members" in autoapi_options %}
:private-bases:
{% endif %}
{% endif %}
{% endif %}
{% if obj.docstring %}
{{ obj.docstring|indent(3) }}
{% endif %}
{% if "inherited-members" in autoapi_options %}
{% set visible_classes = obj.classes|selectattr("display")|list %}
{% else %}
{% set visible_classes = obj.classes|rejectattr("inherited")|selectattr("display")|list %}
{% endif %}
{% for klass in visible_classes %}
{{ klass.render()|indent(3) }}
{% endfor %}
{% if "inherited-members" in autoapi_options %}
{% set visible_attributes = obj.attributes|selectattr("display")|list %}
{% else %}
{% set visible_attributes = obj.attributes|rejectattr("inherited")|selectattr("display")|list %}
{% endif %}
{% for attribute in visible_attributes %}
{{ attribute.render()|indent(3) }}
{% endfor %}
{% if "inherited-members" in autoapi_options %}
{% set visible_methods = obj.methods|selectattr("display")|list %}
{% else %}
{% set visible_methods = obj.methods|rejectattr("inherited")|selectattr("display")|list %}
{% endif %}
{% for method in visible_methods %}
{{ method.render()|indent(3) }}
{% endfor %}
{% endif %}
sphinx-autoapi-1.8.4/autoapi/templates/python/data.rst 0000664 0000000 0000000 00000001356 14106520141 0023120 0 ustar 00root root 0000000 0000000 {% if obj.display %}
.. py:{{ obj.type }}:: {{ obj.name }}
{%+ if obj.value is not none or obj.annotation is not none -%}
:annotation:
{%- if obj.annotation %} :{{ obj.annotation }}
{%- endif %}
{%- if obj.value is not none %} = {%
if obj.value is string and obj.value.splitlines()|count > 1 -%}
Multiline-String
.. raw:: html
Show Value
.. code-block:: text
:linenos:
{{ obj.value|indent(width=8) }}
.. raw:: html
{%- else -%}
{{ obj.value|string|truncate(100) }}
{%- endif %}
{%- endif %}
{% endif %}
{{ obj.docstring|indent(3) }}
{% endif %}
sphinx-autoapi-1.8.4/autoapi/templates/python/exception.rst 0000664 0000000 0000000 00000000041 14106520141 0024173 0 ustar 00root root 0000000 0000000 {% extends "python/class.rst" %}
sphinx-autoapi-1.8.4/autoapi/templates/python/function.rst 0000664 0000000 0000000 00000001103 14106520141 0024022 0 ustar 00root root 0000000 0000000 {% if obj.display %}
.. py:function:: {{ obj.short_name }}({{ obj.args }}){% if obj.return_annotation is not none %} -> {{ obj.return_annotation }}{% endif %}
{% for (args, return_annotation) in obj.overloads %}
{{ obj.short_name }}({{ args }}){% if return_annotation is not none %} -> {{ return_annotation }}{% endif %}
{% endfor %}
{% if sphinx_version >= (2, 1) %}
{% for property in obj.properties %}
:{{ property }}:
{% endfor %}
{% endif %}
{% if obj.docstring %}
{{ obj.docstring|indent(3) }}
{% else %}
{% endif %}
{% endif %}
sphinx-autoapi-1.8.4/autoapi/templates/python/method.rst 0000664 0000000 0000000 00000001503 14106520141 0023461 0 ustar 00root root 0000000 0000000 {%- if obj.display %}
{% if sphinx_version >= (2, 1) %}
.. py:method:: {{ obj.short_name }}({{ obj.args }}){% if obj.return_annotation is not none %} -> {{ obj.return_annotation }}{% endif %}
{% for (args, return_annotation) in obj.overloads %}
{{ obj.short_name }}({{ args }}){% if return_annotation is not none %} -> {{ return_annotation }}{% endif %}
{% endfor %}
{% if obj.properties %}
{% for property in obj.properties %}
:{{ property }}:
{% endfor %}
{% else %}
{% endif %}
{% else %}
.. py:{{ obj.method_type }}:: {{ obj.short_name }}({{ obj.args }})
{% for (args, return_annotation) in obj.overloads %}
{{ " " * (obj.method_type | length) }} {{ obj.short_name }}({{ args }})
{% endfor %}
{% endif %}
{% if obj.docstring %}
{{ obj.docstring|indent(3) }}
{% endif %}
{% endif %}
sphinx-autoapi-1.8.4/autoapi/templates/python/module.rst 0000664 0000000 0000000 00000004570 14106520141 0023475 0 ustar 00root root 0000000 0000000 {% if not obj.display %}
:orphan:
{% endif %}
:py:mod:`{{ obj.name }}`
=========={{ "=" * obj.name|length }}
.. py:module:: {{ obj.name }}
{% if obj.docstring %}
.. autoapi-nested-parse::
{{ obj.docstring|indent(3) }}
{% endif %}
{% block subpackages %}
{% set visible_subpackages = obj.subpackages|selectattr("display")|list %}
{% if visible_subpackages %}
Subpackages
-----------
.. toctree::
:titlesonly:
:maxdepth: 3
{% for subpackage in visible_subpackages %}
{{ subpackage.short_name }}/index.rst
{% endfor %}
{% endif %}
{% endblock %}
{% block submodules %}
{% set visible_submodules = obj.submodules|selectattr("display")|list %}
{% if visible_submodules %}
Submodules
----------
.. toctree::
:titlesonly:
:maxdepth: 1
{% for submodule in visible_submodules %}
{{ submodule.short_name }}/index.rst
{% endfor %}
{% endif %}
{% endblock %}
{% block content %}
{% if obj.all is not none %}
{% set visible_children = obj.children|selectattr("short_name", "in", obj.all)|list %}
{% elif obj.type is equalto("package") %}
{% set visible_children = obj.children|selectattr("display")|list %}
{% else %}
{% set visible_children = obj.children|selectattr("display")|rejectattr("imported")|list %}
{% endif %}
{% if visible_children %}
{{ obj.type|title }} Contents
{{ "-" * obj.type|length }}---------
{% set visible_classes = visible_children|selectattr("type", "equalto", "class")|list %}
{% set visible_functions = visible_children|selectattr("type", "equalto", "function")|list %}
{% set visible_attributes = visible_children|selectattr("type", "equalto", "data")|list %}
{% if "show-module-summary" in autoapi_options and (visible_classes or visible_functions) %}
{% block classes scoped %}
{% if visible_classes %}
Classes
~~~~~~~
.. autoapisummary::
{% for klass in visible_classes %}
{{ klass.id }}
{% endfor %}
{% endif %}
{% endblock %}
{% block functions scoped %}
{% if visible_functions %}
Functions
~~~~~~~~~
.. autoapisummary::
{% for function in visible_functions %}
{{ function.id }}
{% endfor %}
{% endif %}
{% endblock %}
{% block attributes scoped %}
{% if visible_attributes %}
Attributes
~~~~~~~~~~
.. autoapisummary::
{% for attribute in visible_attributes %}
{{ attribute.id }}
{% endfor %}
{% endif %}
{% endblock %}
{% endif %}
{% for obj_item in visible_children %}
{{ obj_item.render()|indent(0) }}
{% endfor %}
{% endif %}
{% endblock %}
sphinx-autoapi-1.8.4/autoapi/templates/python/package.rst 0000664 0000000 0000000 00000000042 14106520141 0023571 0 ustar 00root root 0000000 0000000 {% extends "python/module.rst" %}
sphinx-autoapi-1.8.4/autoapi/toctree.py 0000664 0000000 0000000 00000013626 14106520141 0020160 0 ustar 00root root 0000000 0000000 """
A small Sphinx extension that adds Domain objects (eg. Python Classes & Methods) to the TOC Tree.
It dynamically adds them to the already rendered ``app.env.tocs`` dict on the Sphinx environment.
Traditionally this only contains Section's,
we then nest our Domain references inside the already existing Sections.
"""
from docutils import nodes
from sphinx import addnodes
import sphinx.util.logging
LOGGER = sphinx.util.logging.getLogger(__name__)
def _build_toc_node(docname, anchor="anchor", text="test text", bullet=False):
"""
Create the node structure that Sphinx expects for TOC Tree entries.
The ``bullet`` argument wraps it in a ``nodes.bullet_list``,
which is how you nest TOC Tree entries.
"""
reference = nodes.reference(
"",
"",
internal=True,
refuri=docname,
anchorname="#" + anchor,
*[nodes.Text(text, text)]
)
para = addnodes.compact_paragraph("", "", reference)
ret_list = nodes.list_item("", para)
return nodes.bullet_list("", ret_list) if bullet else ret_list
def _traverse_parent(node, objtypes):
"""
Traverse up the node's parents until you hit the ``objtypes`` referenced.
Can either be a single type,
or a tuple of types.
"""
curr_node = node.parent
while curr_node is not None:
if isinstance(curr_node, objtypes):
return curr_node
curr_node = curr_node.parent
return None
def _find_toc_node(toc, ref_id, objtype):
"""
Find the actual TOC node for a ref_id.
Depends on the object type:
* Section - First section (refuri) or 2nd+ level section (anchorname)
* Desc - Just use the anchor name
"""
for check_node in toc.traverse(nodes.reference):
if objtype == nodes.section and (
check_node.attributes["refuri"] == ref_id
or check_node.attributes["anchorname"] == "#" + ref_id
):
return check_node
if (
objtype == addnodes.desc
and check_node.attributes["anchorname"] == "#" + ref_id
):
return check_node
return None
def _get_toc_reference(node, toc, docname):
"""
Logic that understands maps a specific node to it's part of the toctree.
It takes a specific incoming ``node``,
and returns the actual TOC Tree node that is said reference.
"""
if isinstance(node, nodes.section) and isinstance(node.parent, nodes.document):
# Top Level Section header
ref_id = docname
toc_reference = _find_toc_node(toc, ref_id, nodes.section)
elif isinstance(node, nodes.section):
# Nested Section header
ref_id = node.attributes["ids"][0]
toc_reference = _find_toc_node(toc, ref_id, nodes.section)
else:
# Desc node
try:
ref_id = node.children[0].attributes["ids"][0]
toc_reference = _find_toc_node(toc, ref_id, addnodes.desc)
except (KeyError, IndexError):
LOGGER.warning(
"Invalid desc node",
exc_info=True,
type="autoapi",
subtype="toc_reference",
)
toc_reference = None
return toc_reference
def add_domain_to_toctree(app, doctree, docname):
"""
Add domain objects to the toctree dynamically.
This should be attached to the ``doctree-resolved`` event.
This works by:
* Finding each domain node (addnodes.desc)
* Figuring out it's parent that will be in the toctree
(nodes.section, or a previously added addnodes.desc)
* Finding that parent in the TOC Tree based on it's ID
* Taking that element in the TOC Tree,
and finding it's parent that is a TOC Listing (nodes.bullet_list)
* Adding the new TOC element for our specific node as a child of that nodes.bullet_list
* This checks that bullet_list's last child,
and checks that it is also a nodes.bullet_list,
effectively nesting it under that element
"""
toc = app.env.tocs[docname]
for desc_node in doctree.traverse(addnodes.desc):
try:
ref_id = desc_node.children[0].attributes["ids"][0]
except (KeyError, IndexError):
# autodoc-style directives already add nodes to the toc.
continue
try:
# Python domain object
ref_text = desc_node[0].attributes["fullname"].split(".")[-1].split("(")[0]
except (KeyError, IndexError):
# TODO[eric]: Support other Domains and ways of accessing this data
# Use `astext` for other types of domain objects
ref_text = desc_node[0].astext().split(".")[-1].split("(")[0]
# This is the actual object that will exist in the TOC Tree
# Sections by default, and other Desc nodes that we've previously placed.
parent_node = _traverse_parent(
node=desc_node, objtypes=(addnodes.desc, nodes.section)
)
if parent_node:
toc_reference = _get_toc_reference(parent_node, toc, docname)
if toc_reference:
# Get the last child of our parent's bullet list, this is where "we" live.
toc_insertion_point = _traverse_parent(
toc_reference, nodes.bullet_list
)[-1]
# Ensure we're added another bullet list so that we nest inside the parent,
# not next to it
if len(toc_insertion_point) > 1 and isinstance(
toc_insertion_point[1], nodes.bullet_list
):
to_add = _build_toc_node(docname, anchor=ref_id, text=ref_text)
toc_insertion_point = toc_insertion_point[1]
else:
to_add = _build_toc_node(
docname,
anchor=ref_id,
text=ref_text,
bullet=True,
)
toc_insertion_point.append(to_add)
sphinx-autoapi-1.8.4/docs/ 0000775 0000000 0000000 00000000000 14106520141 0015417 5 ustar 00root root 0000000 0000000 sphinx-autoapi-1.8.4/docs/conf.py 0000664 0000000 0000000 00000024074 14106520141 0016725 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
#
# Sphinx AutoAPI documentation build configuration file, created by
# sphinx-quickstart on Wed Apr 22 15:38:18 2015.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = ['autoapi.extension', 'sphinx.ext.intersphinx']
autoapi_type = 'python'
autoapi_dirs = ['../autoapi']
autoapi_generate_api_docs = False
intersphinx_mapping = {
'jinja': ('https://jinja.palletsprojects.com/en/3.0.x/', None),
'sphinx': ('https://www.sphinx-doc.org/en/master/', None),
'python': ('https://docs.python.org/3/', None),
}
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'Sphinx AutoAPI'
copyright = u'2015, Read the Docs, Inc'
author = u'Read the Docs, Inc'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
import autoapi
# The short X.Y version.
version = ".".join(str(x) for x in autoapi.__version_info__[:2])
# The full version, including alpha/beta/rc tags.
release = autoapi.__version__
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all
# documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
#keep_warnings = False
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'sphinx_rtd_theme'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# " v documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
#html_extra_path = []
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Language to be used for generating the HTML full-text search index.
# Sphinx supports the following languages:
# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'
#html_search_language = 'en'
# A dictionary with options for the search language support, empty by default.
# Now only 'ja' uses this config value
#html_search_options = {'type': 'default'}
# The name of a javascript file (relative to the configuration directory) that
# implements a search results scorer. If empty, the default will be used.
#html_search_scorer = 'scorer.js'
# Output file base name for HTML help builder.
htmlhelp_basename = 'SphinxAutoAPIdoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
# Latex figure (float) alignment
#'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'SphinxAutoAPI.tex', u'Sphinx AutoAPI Documentation',
u'Read the Docs, Inc', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'sphinxautoapi', u'Sphinx AutoAPI Documentation',
[author], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'SphinxAutoAPI', u'Sphinx AutoAPI Documentation',
author, 'SphinxAutoAPI', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False
import re
from sphinx import addnodes
event_sig_re = re.compile(r'([a-zA-Z-]+)\s*\((.*)\)')
def parse_event(env, sig, signode):
m = event_sig_re.match(sig)
if not m:
signode += addnodes.desc_name(sig, sig)
return sig
name, args = m.groups()
signode += addnodes.desc_name(name, name)
plist = addnodes.desc_parameterlist()
for arg in args.split(','):
arg = arg.strip()
plist += addnodes.desc_parameter(arg, arg)
signode += plist
return name
def setup(app):
from sphinx.util.docfields import TypedField
app.add_object_type('confval', 'confval',
objname='configuration value',
indextemplate='pair: %s; configuration value')
fdesc = TypedField('parameter', label='Parameters',
names=['param'], typenames=['type'], can_collapse=True)
app.add_object_type('event', 'event', 'pair: %s; event', parse_event,
doc_field_types=[fdesc])
sphinx-autoapi-1.8.4/docs/how_to.rst 0000664 0000000 0000000 00000011131 14106520141 0017445 0 ustar 00root root 0000000 0000000 How-to Guides
=============
.. _customise-templates:
How to Customise Layout Through Templates
-----------------------------------------
You can customise the look of the documentation that AutoAPI generates
by changing the Jinja2 templates that it uses.
The default templates live in the ``autoapi/templates`` directory of the AutoAPI package.
Simply copy whichever templates you want to customise to a local directory
and edit them.
To get AutoAPI to use these templates,
point the :confval:`autoapi_template_dir` configuration option to your directory.
It can be absolute, or relative to the root of the documentation source directory
(ie the directory passed to ``sphinx-build``).
.. code-block:: python
autoapi_template_dir = '_autoapi_templates'
Your template directory must to follow the same layout as the default templates.
For example, to override the Python class and module templates:
.. code-block:: none
_autoapi_templates
└── python
├── class.rst
└── module.rst
How to Customise the Index Page
-------------------------------
The index page that AutoAPI creates is generated using a template.
So customising the index page follows the same steps as customising a template.
Simply edit the ``autoapi/templates/index.rst`` template
with the same steps as :ref:`customising a template `.
How to Remove the Index Page
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
To remove the index page altogether,
turn off the :confval:`autoapi_add_toctree_entry` configuration option::
autoapi_add_toctree_entry = False
You will then need to include the generated documentation in the toctree yourself.
For example if you were generating documentation for a package called "example",
you would add the following toctree entry::
.. toctree::
autoapi/example/index
Note that ``autoapi/`` is the default location of documentation,
as configured by :confval:`autoapi_root`.
If you change :confval:`autoapi_root`,
then the entry that you need to add would change also.
How to Configure Where Documentation Appears in the TOC Tree
------------------------------------------------------------
The :confval:`autoapi_root` configuration option defines where generated documentation is output.
To change where documentation is output,
simply change this option to another directory relative to the documentation source directory:
.. code-block:: python
autoapi_root = 'technical/api'
How to Transition to Autodoc-Style Documentation
----------------------------------------------------
Once you have written some documentation with the :ref:`autodoc-directives`,
turning the automatic documentation generation off is as easy as
disabling the :confval:`autoapi_generate_api_docs` configuration option::
autoapi_generate_api_docs = False
How to Transition to Manual Documentation
-----------------------------------------
To start writing API documentation yourself,
you can get AutoAPI to keep its generated files around as a base to start from
using the :confval:`autoapi_keep_files` option::
autoapi_keep_files = True
Once you have built your documentation with this option turned on,
you can disable AutoAPI altogether from your project.
How to Include Type Annotations as Types in Rendered Docstrings
---------------------------------------------------------------
.. warning::
This feature is experimental and may change or be removed in future versions.
Since v3.0, :mod:`sphinx` has included an :mod:`sphinx.ext.autodoc.typehints`
extension that is capable of rendering type annotations as
parameter types and return types.
For example the following function:
.. code-block::
def _func(a: int, b: Optional[str]) -> bool
"""My function.
:param a: The first arg.
:param b: The second arg.
:returns: Something.
"""
would be rendered as:
.. py:function:: _func(a, b)
:noindex:
:param int a: The first arg.
:param b: The second arg.
:type b: Optional[str]
:returns: Something.
:rtype: bool
AutoAPI is capable of the same thing.
To enable this behaviour, load the :mod:`sphinx.ext.autodoc.typehints`
(or :mod:`sphinx.ext.autodoc`) extension in Sphinx's ``conf.py`` file
and set :confval:`autodoc_typehints` to ``description`` as normal::
extensions = ['sphinx.ext.autodoc', 'autoapi.extension']
autodoc_typehints = 'description'
.. note::
Unless :confval:`autodoc_typehints` is set to ``none``,
the type annotations of overloads will always be output in the signature
and never merged into the description
because it is impossible to represent all overloads as a list of parameters.
sphinx-autoapi-1.8.4/docs/index.rst 0000664 0000000 0000000 00000000176 14106520141 0017264 0 ustar 00root root 0000000 0000000 Sphinx AutoAPI
==============
.. toctree::
:maxdepth: 2
:glob:
tutorials
how_to
reference/*
maintenance/*
sphinx-autoapi-1.8.4/docs/maintenance/ 0000775 0000000 0000000 00000000000 14106520141 0017701 5 ustar 00root root 0000000 0000000 sphinx-autoapi-1.8.4/docs/maintenance/design.rst 0000664 0000000 0000000 00000014441 14106520141 0021710 0 ustar 00root root 0000000 0000000 Design Reference
================
Python
------
When choosing what to document,
AutoAPI aims to document anything that is publicly accessible through the actual package
when loaded in Python.
For example if a function is imported from a submodule into a package,
that function is documented in both the submodule and the package.
There are some exceptions to this rule:
* Anything that is imported into a module is not documented.
Usually a module is where implementations exist.
Therefore an import of something is usually for the usage of the implementation,
and not as something to be accessed publicly.
* When the module or package defines an ``__all__``,
only the members named in ``__all__`` are documented.
* When a configuration option indicates that private
or special members should also be documented.
Furthermore, AutoAPI follows the same docstring inheritance rules as :func:`inspect.getdoc`,
with some exceptions:
* The docstrings of the following methods are not inherited because they are usually redundant:
* :meth:`object.__init__`
* :meth:`object.__new__`
* :meth:`type.__init__`
* :meth:`type.__new__`
.NET
----
This document talks about the design of a .NET Sphinx integration.
This will include a mechanism for generating Javadoc style API references automatically.
We will describe decisions that lead to specific implementation details.
Goals
-----
The main goal of this project is to be able to generate a MSDN or Javadoc style API reference from a .Net project in Sphinx.
Primary Goals
~~~~~~~~~~~~~
* Build MSDN/Javadoc style HTML output for arbitrary .Net code.
* Have specific pages for each Package, Class, and all class-level structures.
- `/api/System/`
- `/api/System/String/`
- `/api/System/String/Constructors/`
Secondary Goals
~~~~~~~~~~~~~~~
* Allow for definition of .Net classes inside of normal Sphinx prose docs (classic Sphinx style definition).
* Allow generation of Javadoc style docs from other languages.
Requirements
~~~~~~~~~~~~
Introduction
------------
We are working with Sphinx,
which has an existing way of doing this.
Generally, you define a `Domain` which describes the various language structure,
a *Class* or *Method*, for example.
Then the user will write RST that uses these definitions,
and Sphinx will create output from that markup.
.. code-block:: rst
.. py:function:: spam(eggs)
Spam the foo.
The author of the doucmentation will have now told Sphinx that the *spam* function exists in the Python project that is being documented.
Autogenerated Output
~~~~~~~~~~~~~~~~~~~~
Sphinx then built a series of tools to make the generation of this markup easier and more automatic:
* `Autodoc `_
* `Autosummary `_
Autodoc is a Python-only solution that imports the author's code into memory, and then allows the author to more automatically document full objects. For example, you can document a whole class on a page.
.. code-block:: py
.. autoclass:: Noodle
This will generate output that looks like:
.. class:: Noodle
Noodle's docstring.
There are also options for it to include a full listing of the classes attributes, methods, and other things, automatically.
.. warning:: Remember, this depends on ``Noodle`` being importable by the Python interpreter running Sphinx.
Proposed Architecture
---------------------
The proposed architecture for this project is as follows:
* A program that will generate a YAML (or JSON) file from a .Net project, representing it's full API information.
* Read the YAML and generate an appropriate tree structure that will the outputted HTML will look like (YAMLTree)
- If time allows, we will allow a merging of these objects with multiple YAML files to allow for prose content to be injected into the output
* Take the YAML structure and generate in-memory rst that corresponds to the Sphinx dotnet Domain objects
* dotnet Domain will output HTML based on the doctree generated from the in-memory RST
In diagram form::
Code -> YAML -> YAMLTree -> RST (Dotnet Domain) -> Sphinx -> HTML
YAMLTree
~~~~~~~~
One of the main problems is how to actually structure the outputted HTML pages.
The YAML file will likely be ordered,
but we need to have a place to define the page structure in the HTML.
This can be done before or after the loading of the content into RST.
We decided to do it before loading into RST because that matches standard Sphinx convention.
Generally the markup being fed in as RST is considered to be in a file that maps to it's output loation.
If we tried to maniuplate this structure after loading into the Domain,
that could lead to unexpected consequences like wrong indexes and missing references.
File Structure vs. Hierarchy
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Specific ID's should have one specific detail representation.
This means that every YAML docid object should only have one place that it is rendered with a ``.. dn:`` canonical identifier.
All other places it is referenced should be in either:
* A reference
* A toctree (listing)
Sphinx Implementation
~~~~~~~~~~~~~~~~~~~~~
The user will run a normal `make html` as part of the experience.
The generation and loading will be done as an extension that can be configured.
There will be Sphinx configuration for how things get built:
.. code-block:: rst
autoapi_root = 'api' # Where HTML is generated
autoapi_dirs = ['yaml'] # Directory of YAML sources
We will then loop over all YAML files in the ``autoapi_dir`` and parse them.
They will then be output into ``autoapi_root`` inside the documentation.
Examples
--------
A nice example of Sphinx Python output similar to what we want:
* http://dta.googlecode.com/git/doc/_build/html/index.html
* Src: https://raw.githubusercontent.com/sfcta/dta/master/doc/index.rst
An example domain for Spec:
* https://subversion.xray.aps.anl.gov/bcdaext/specdomain/trunk/src/specdomain/sphinxcontrib/specdomain.py
Other Ideas
-----------
.. warning:: Things in this section might not get implemented.
The .Net domain will not be able to depend on importing code from the users code base. We might be able to implement similar authoring tools with the YAML file. We might be able to output the YAML subtree of an object with autodoc style tools:
.. code-block:: rst
.. autodnclass:: System.String
:members:
sphinx-autoapi-1.8.4/docs/maintenance/release-process.rst 0000664 0000000 0000000 00000001410 14106520141 0023523 0 ustar 00root root 0000000 0000000 Release Process
===============
This page documents the steps to be taken to release a new version of Sphinx AutoAPI.
Pre-Checks
----------
1. Check that the dependencies of the package are correct.
2. Clean the ``.tox`` directory and run the tests.
3. Commit and push any changes needed to make the tests pass.
4. Check that the tests passed on github.
Preparation
-----------
1. Update the version numbers in ``autoapi/__init__.py``.
2. Add any missing changelog entries.
3. Put the version number and release date into the changelog.
4. Commit and push the changes.
5. Check that the tests passed on github.
Release
-------
.. code-block:: bash
git clean -fdx
python setup.py sdist bdist_wheel
twine upload dist/*
git tag vX.X.X
git push --tags
sphinx-autoapi-1.8.4/docs/reference/ 0000775 0000000 0000000 00000000000 14106520141 0017355 5 ustar 00root root 0000000 0000000 sphinx-autoapi-1.8.4/docs/reference/config.rst 0000664 0000000 0000000 00000023543 14106520141 0021363 0 ustar 00root root 0000000 0000000 Configuration Options
=====================
.. confval:: autoapi_dirs
**Required**
Paths (relative or absolute) to the source code that you wish to generate your API documentation from.
The paths are searched recursively for files matching :confval:`autoapi_file_patterns`.
Relative paths should be relative to the source directory of your documentation.
For Python, if a package directory is specified,
the package directory itself will be included in the relative path of the children.
If an ordinary directory is specified,
that directory will not be included in the relative path.
.. confval:: autoapi_type
Default: ``python``
Set the type of files you are documenting.
This depends on the programming language that you are using:
========== ================
Language ``autoapi_type``
========== ================
Python ``'python'``
Go ``'go'``
Javascript ``'javascript'``
.NET ``'dotnet'``
========== ================
.. confval:: autoapi_template_dir
Default: ``''``
A directory that has user-defined templates to override our default templates.
The path can either be absolute,
or relative to the source directory of your documentation files.
An path relative to where `sphinx-build` is run
is allowed for backwards compatibility only
and will be removed in a future version.
You can view the default templates in the
`autoapi/templates `_
directory of the package.
.. confval:: autoapi_file_patterns
Default: Varies by Language
A list containing the file patterns to look for when generating documentation.
Patterns should be listed in order of preference.
For example,
if ``autoapi_file_patterns`` is set to the default value
and a `.py` file and a `.pyi` file are found,
then the `.py` will be read.
The defaults by language are:
========== ============================================
Language ``autoapi_file_patterns``
========== ============================================
Python ``['*.py', '*.pyi']``
Go ``['*.go']``
Javascript ``['*.js']``
.NET ``['project.json', '*.csproj', '*.vbproj']``
========== ============================================
.. confval:: autoapi_generate_api_docs
Default: ``True``
Whether to generate API documentation.
If this is ``False``, documentation should be generated though the
:doc:`directives`.
Customisation Options
---------------------
.. confval:: autoapi_options
Default: [
``'members'``,
``'undoc-members'``,
``'private-members'``,
``'show-inheritance'``,
``'show-module-summary'``,
``'special-members'``,
``'imported-members'``,
]
Options for display of the generated documentation.
* ``members``: Display children of an object
* ``inherited-members``: Display children of an object
that have been inherited from a base class.
* ``undoc-members``: Display objects that have no docstring
* ``private-members``: Display private objects (eg. ``_foo`` in Python)
* ``special-members``: Display special objects (eg. ``__foo__`` in Python)
* ``show-inheritance``: Display a list of base classes below the class signature.
* ``show-inheritance-diagram``: Display an inheritance diagram in
generated class documentation.
It makes use of the :mod:`sphinx.ext.inheritance_diagram` extension,
and requires `Graphviz `_ to be installed.
* ``show-module-summary``: Whether to include autosummary directives
in generated module documentation.
* ``imported-members``: Display objects imported from the same
top level package or module.
The default module template does not include imported objects,
even with this option enabled.
The default package template does.
.. confval:: autoapi_ignore
Default: Varies By Language
A list of patterns to ignore when finding files.
The defaults by language are:
========== ============================================
Language ``autoapi_file_patterns``
========== ============================================
Python ``['*migrations*']``
Go ``[]``
Javascript ``[]``
.NET ``['*toc.yml', '*index.yml']``
========== ============================================
.. confval:: autoapi_root
Default: ``autoapi``
Path to output the generated AutoAPI files into,
including the generated index page.
This path must be relative to the source directory of your documentation files.
This can be used to place the generated documentation
anywhere in your documentation hierarchy.
.. confval:: autoapi_add_toctree_entry
Default: ``True``
Whether to insert the generated documentation into the TOC tree.
If this is ``False``, the default AutoAPI index page is not generated
and you will need to include the generated documentation
in a TOC tree entry yourself.
.. confval:: autoapi_python_class_content
Default: ``class``
Which docstring to insert into the content of a class.
* ``class``: Use only the class docstring.
* ``both``: Use the concatentation of the class docstring and the
``__init__`` docstring.
* ``init``: Use only the ``__init__`` docstring.
If the class does not have an ``__init__`` or the ``__init__``
docstring is empty and the class defines a ``__new__`` with a docstring,
the ``__new__`` docstring is used instead of the ``__init__`` docstring.
.. confval:: autoapi_member_order
Default: ``bysource``
The order to document members. This option can have the following values:
* ``alphabetical``: Order members by their name, case sensitively.
* ``bysource``: Order members by the order that they were defined in the source code.
* ``groupwise``: Order members by their type then alphabetically,
ordering the types as follows:
* Submodules and subpackages
* Attributes
* Exceptions
* Classes
* Functions
* Methods
.. confval:: autoapi_python_use_implicit_namespaces
Default: ``False``
This changes the package detection behaviour to be compatible with :pep:`420`,
but directories in :confval:`autoapi_dirs`
are no longer searched recursively for packages.
Instead, when this is ``True``,
:confval:`autoapi_dirs` should point directly to
the directories of implicit namespaces
and the directories of packages.
If searching is still required,
this should be done manually in the ``conf.py``.
.. confval:: autoapi_prepare_jinja_env
Default: ``None``
A callback that is called shortly after the Jinja environment is created.
It passed the Jinja environment for editing before template rendering begins.
The callback should have the following signature:
.. py:function:: prepare_jinja_env(jinja_env: jinja2.Environment) -> None
:noindex:
Events
~~~~~~
The following events allow you to control the behaviour of AutoAPI.
.. event:: autoapi-skip-member (app, what, name, obj, skip, options)
(Python only)
Emitted when a template has to decide whether a member should be included
in the documentation.
Usually the member is skipped if a handler returns ``True``,
and included otherwise.
Handlers should return ``None`` to fall back to the default skipping
behaviour of AutoAPI or another attached handler.
.. code-block:: python
:caption: Example conf.py
def skip_util_classes(app, what, name, obj, skip, options):
if what == "class" and "util" in name:
skip = True
return skip
def setup(sphinx):
sphinx.connect("autoapi-skip-member", skip_util_classes)
:param app: The Sphinx application object.
:param what: The type of the object which the docstring belongs to.
This can be one of:
``"attribute"``, ``"class"``, ``"data"``, ``"exception"``,
``"function"``, ``"method"``, ``"module"``, ``"package"``.
:type what: str
:param name: The fully qualified name of the object.
:type name: str
:param obj: The object itself.
:type obj: PythonPythonMapper
:param skip: Whether AutoAPI will skip this member if the handler
does not override the decision.
:type skip: bool
:param options: The options given to the directive.
Advanced Options
-----------------
.. confval:: autoapi_keep_files
Default: ``False``
Keep the AutoAPI generated files on the filesystem after the run.
Useful for debugging or transitioning to manual documentation.
Keeping files will also allow AutoAPI to use incremental builds.
Providing none of the source files have changed,
AutoAPI will skip parsing the source code and regenerating the API documentation.
Suppressing Warnings
---------------------
.. confval:: suppress_warnings
This is a sphinx builtin option that enables the granular filtering of AutoAPI
generated warnings.
Items in the ``suppress_warnings`` list are of the format ``"type.subtype"`` where
``".subtype"`` can be left out to cover all subtypes. To suppress all AutoAPI
warnings add the type ``"autoapi"`` to the list:
.. code-block:: python
suppress_warnings = ["autoapi"]
If narrower suppression is wanted, the available subtypes for AutoAPI are:
* python_import_resolution
Used if resolving references to objects in an imported module failed. Potential reasons
include cyclical imports and missing (parent) modules.
* not_readable
Emitted if processing (opening, parsing, ...) an input file failed.
* toc_reference
Used if a reference to an entry in a table of content cannot be resolved.
So if all AutoAPI warnings concerning unreadable sources and failing Python imports should be
filtered, but all other warnings should not, the option would be
.. code-block:: python
suppress_warnings = ["autoapi.python_import_resolution", "autoapi.not_readable"]
sphinx-autoapi-1.8.4/docs/reference/directives.rst 0000664 0000000 0000000 00000004003 14106520141 0022245 0 ustar 00root root 0000000 0000000 Directives
==========
.. _autodoc-directives:
Autodoc-Style Directives
------------------------
You can opt to write API documentation yourself using autodoc style directives.
These directives work similarly to autodoc,
but docstrings are retrieved through static analysis instead of through imports.
.. seealso::
When transitioning to autodoc-style documentation,
you may want to turn the :confval:`autoapi_generate_api_docs`
option off so that automatic API documentation is no longer generated.
To use these directives you will need to enable the autodoc extension
in your Sphinx project's ``conf.py``:
.. code:: python
extensions = ['sphinx.ext.autodoc', 'autoapi.extension']
For Python, all directives have an autodoc equivalent
and accept the same options.
The following directives are available:
.. rst:directive:: autoapimodule
autoapiclass
autoapiexception
Equivalent to :rst:dir:`automodule`, :rst:dir:`autoclass`,
and :rst:dir:`autoexception` respectively.
:confval:`autodoc_inherit_docstrings` does not currently work.
.. rst:directive:: autoapifunction
autoapidata
autoapimethod
autoapiattribute
Equivalent to :rst:dir:`autofunction`, :rst:dir:`autodata`,
:rst:dir:`automethod`, and :rst:dir:`autoattribute` respectively.
Inheritance Diagrams
--------------------
.. rst:directive:: autoapi-inheritance-diagram
This directive uses the :mod:`sphinx.ext.inheritance_diagram` extension
to create inheritance diagrams for classes.
For example:
.. autoapi-inheritance-diagram:: autoapi.mappers.python.objects.PythonModule autoapi.mappers.python.objects.PythonPackage
:parts: 1
:mod:`sphinx.ext.inheritance_diagram` makes use of the
:mod:`sphinx.ext.graphviz` extension,
and therefore it requires `Graphviz `_ to be installed.
The directive can be configured using the same options as
:mod:`sphinx.ext.inheritance_diagram`.
sphinx-autoapi-1.8.4/docs/reference/templates.rst 0000664 0000000 0000000 00000005654 14106520141 0022117 0 ustar 00root root 0000000 0000000 Templates
=========
A lot of the power from AutoAPI comes from templates.
We are basically building a mapping from code to docs,
and templates let you highly customise the display of said docs.
Structure
---------
Every type of data structure has its own template.
It uses the form :samp:`{language}/{type}.rst` to find the template to render.
The full search path is:
* :samp:`{language}/{type}.rst`
So for a .NET Class, this would resolve to:
* :samp:`dotnet/class.rst`
We provide :samp:`base/base.rst` as an incredibly basic output of every object::
.. {language}:{type}:: {name}
Custom Filters, Tests, and Globals
----------------------------------
The :confval:`autoapi_prepare_jinja_env` configuration option allows you
to pass a callback that can edit the :class:`jinja2.Environment` object
before rendering begins.
This callback, among other things, can be used to add custom filters,
tests, and/or globals to the Jinja environment. For example:
.. code-block:: python
def autoapi_prepare_jinja_env(jinja_env):
jinja_env.filters["my_custom_filter"] = lambda value: value.upper()
Context
-------
Every template is given a set context that can be accessed in the templates.
This contains:
* ``autoapi_options``: The value of the :confval:`autoapi_options`
configuration option.
* ``include_summaries``: The value of the :confval:`autoapi_include_summaries`
configuration option.
* ``obj``: A Python object derived from :class:`PythonMapperBase`.
* ``sphinx_version``: The contents of :attr:`sphinx.version_info`.
The object in ``obj`` has a number of standard attributes
that you can reliably access per language.
.. warning::
These classes should not be constructed manually.
They can be reliably accessed through templates only.
Python
~~~~~~
.. autoapiclass:: autoapi.mappers.python.objects.PythonPythonMapper
:members:
.. autoapiclass:: autoapi.mappers.python.objects.PythonFunction
:members:
:show-inheritance:
.. autoapiclass:: autoapi.mappers.python.objects.PythonMethod
:members:
:show-inheritance:
.. autoapiclass:: autoapi.mappers.python.objects.PythonData
:members:
:show-inheritance:
.. autoapiclass:: autoapi.mappers.python.objects.PythonAttribute
:members:
:show-inheritance:
.. autoapiclass:: autoapi.mappers.python.objects.TopLevelPythonPythonMapper
:members:
:show-inheritance:
.. autoapiclass:: autoapi.mappers.python.objects.PythonModule
:members:
:show-inheritance:
.. autoapiclass:: autoapi.mappers.python.objects.PythonPackage
:members:
:show-inheritance:
.. autoapiclass:: autoapi.mappers.python.objects.PythonClass
:members:
:show-inheritance:
.. autoapiclass:: autoapi.mappers.python.objects.PythonException
:members:
:show-inheritance:
Go
~~~
.. autoapiclass:: autoapi.mappers.go.GoPythonMapper
:members:
Javascript
~~~~~~~~~~
.. autoapiclass:: autoapi.mappers.javascript.JavaScriptPythonMapper
:members:
.NET
~~~~
.. autoapiclass:: autoapi.mappers.dotnet.DotNetPythonMapper
:members:
sphinx-autoapi-1.8.4/docs/tutorials.rst 0000664 0000000 0000000 00000016313 14106520141 0020203 0 ustar 00root root 0000000 0000000 Tutorials
=========
Setting up Automatic API Documentation Generation
-------------------------------------------------
This tutorial will assume that you already have a basic Sphinx project set up.
If you are not sure how to do this,
you can follow the :doc:`sphinx:usage/quickstart` guide in the Sphinx documentation.
The recommended way of installing AutoAPI is through a `virtualenv `_.
Once you have a virtualenv set up, you can install AutoAPI with the command:
========== ======================================
Language Command
========== ======================================
Python ``pip install sphinx-autoapi``
Go ``pip install sphinx-autoapi[go]``
Javascript ``pip install sphinx-autoapi``
.NET ``pip install sphinx-autoapi[dotnet]``
========== ======================================
Depending on which language you are trying to document,
each language has a different set of steps for finishing the setup of AutoAPI:
.. contents::
:local:
:backlinks: none
Python
^^^^^^
To enable the extension,
we need to add it to the list of extensions in Sphinx's ``conf.py`` file::
extensions = ['autoapi.extension']
For Python, there is only one required configuration option that we need to set.
:confval:`autoapi_dirs` tells AutoAPI which directories contain
the source code to document.
These can either be absolute, or relative to the source directory of
your documentation files.
For example, say we have a package and we have used ``sphinx-quickstart``
to create a Sphinx project in a ``docs/`` folder.
The directory structure might look like this:
.. code-block:: none
mypackage/
├── docs
│ ├── _build
│ ├── conf.py
│ ├── index.rst
│ ├── make.bat
│ ├── Makefile
│ ├── _static
│ └── _templates
├── mypackage
│ ├── _client.py
│ ├── __init__.py
│ └── _server.py
└── README.md
``sphinx-quickstart`` sets up the ``sphinx-build`` to run from
inside the ``docs/`` directory, and the source code is one level up.
So the value of our :confval:`autoapi_dirs` option would be::
autoapi_dirs = ['../mypackage']
If you are documenting many packages,
you can point AutoAPI to the directory that contains those packages.
For example if our source code was inside a ``src/`` directory:
.. code-block:: none
mypackage/
├── docs
│ ├── _build
│ ├── conf.py
│ ├── index.rst
│ ├── make.bat
│ ├── Makefile
│ ├── _static
│ └── _templates
├── README.md
└── src
└── mypackage
├── _client.py
├── __init__.py
└── _server.py
We can configure :confval:`autoapi_dirs` to be::
autoapi_dirs = ['../src']
Now that everything is configured,
AutoAPI will generate documentation when you run Sphinx!
.. code-block:: bash
cd docs/
sphinx-build -b html . _build
Go
^^^
Support for Go requires you to have the go environment installed
(https://golang.org/dl/), as well as our godocjson tool::
go get github.com/readthedocs/godocjson
and the Go domain extension for Sphinx::
pip install sphinxcontrib-golangdomain
To enable the AutoAPI extension,
we need to add it to the list of extensions in Sphinx's ``conf.py`` file
with the Go domain extension::
extensions = [
'sphinxcontrib.golangdomain',
'autoapi.extension',
]
For Go, there are two required configuration options that we need to set.
:confval:`autoapi_type` tells AutoAPI what type of language we are documenting.
For Go, this is::
autoapi_type = 'go'
The second configuration option is :confval:`autoapi_dirs`,
which tells AutoAPI which directories contain the source code to document.
These can either be absolute, or relative to the source directory of
your documentation files.
So if your documentation was inside a ``docs/`` directory
and your source code is in an ``example`` directory one level up,
you would configure :confval:`autoapi_dirs` to be::
autoapi_dirs = ['../example']
Now that everything is configured,
AutoAPI will generate documentation when you run Sphinx!
.. code-block:: bash
cd docs/
sphinx-build -b html . _build
Javascript
^^^^^^^^^^
Support for Javascript requires you to have jsdoc (http://usejsdoc.org/) installed::
npm install jsdoc -g
To enable the AutoAPI extension,
we need to add it to the list of extensions in Sphinx's ``conf.py`` file::
extensions = ['autoapi.extension']
For Javascript, there are two required configuration options that we need to set.
:confval:`autoapi_type` tells AutoAPI what type of language we are documenting.
For Javascript, this is::
autoapi_type = 'javascript'
The second configuration option is :confval:`autoapi_dirs`,
which tells AutoAPI which directories contain the source code to document.
These can either be absolute, or relative to the source directory of
your documentation files.
So if your documentation was inside a ``docs/`` directory
and your source code is in an ``example`` directory one level up,
you would configure :confval:`autoapi_dirs` to be::
autoapi_dirs = ['../example']
Now that everything is configured,
AutoAPI will generate documentation when you run Sphinx!
.. code-block:: bash
cd docs/
sphinx-build -b html . _build
.NET
^^^^
Support for .NET requires you to have the docfx (https://dotnet.github.io/docfx/) tool installed,
as well as the .NET domain extension for Sphinx::
pip install sphinxcontrib-dotnetdomain
Firstly, we need to configure docfx to output to a directory known to AutoAPI.
By default, ``docfx`` will output metadata files into the ``_api`` path.
You can configure which path to output files into by setting the path in your
`docfx configuration file `_
in your project repository.
For example, if your documentation source files are located inside a ``docs/`` directory:
.. code:: json
{
"metadata": [{
"dest": "docs/_api"
}]
}
To enable the AutoAPI extension,
we need to add it to the list of extensions in Sphinx's ``conf.py`` file
with the .NET domain extension::
extensions = [
'sphinxcontrib.dotnetdomain',
'autoapi.extension',
]
For .NET, there are two required configuration options that we need to set.
:confval:`autoapi_type` tells AutoAPI what type of language we are documenting.
For .NET, this is::
autoapi_type = 'dotnet'
The second configuration option is :confval:`autoapi_dirs`,
which tells AutoAPI which directories contain the source code to document.
These can either be absolute, or relative to the source directory of
your documentation files.
So if your documentation was inside a ``docs/`` directory
and your source code is in an ``example`` directory one level up,
you would configure :confval:`autoapi_dirs` to be::
autoapi_dirs = ['../example']
Now that everything is configured,
AutoAPI will generate documentation when you run Sphinx!
.. code-block:: bash
cd docs/
sphinx-build -b html . _build
sphinx-autoapi-1.8.4/pylintrc 0000664 0000000 0000000 00000000625 14106520141 0016261 0 ustar 00root root 0000000 0000000 [MASTER]
load-plugins=
[MESSAGES CONTROL]
disable=bad-continuation,
duplicate-code,
fixme,
import-error,
missing-class-docstring,
missing-function-docstring,
missing-module-docstring,
too-few-public-methods,
too-many-locals,
too-many-instance-attributes,
useless-object-inheritance
enable=c-extension-no-member
[BASIC]
good-names=i,j,id,_
sphinx-autoapi-1.8.4/pyproject.toml 0000664 0000000 0000000 00000000142 14106520141 0017400 0 ustar 00root root 0000000 0000000 [build-system]
requires = ["setuptools>=46.4.0", "wheel"]
build-backend = "setuptools.build_meta"
sphinx-autoapi-1.8.4/setup.cfg 0000664 0000000 0000000 00000002535 14106520141 0016315 0 ustar 00root root 0000000 0000000 [metadata]
name = sphinx-autoapi
version = attr: autoapi.__version__
author = Eric Holscher
author_email = eric@ericholscher.com
maintainer = Ashley Whetter
maintainer_email = ashley@awhetter.co.uk
description = Sphinx API documentation generator
long_description = file: README.rst
long_description_content_type = text/x-rst
url = http://github.com/readthedocs/sphinx-autoapi
license = MIT
license_files =
LICENSE.rst
classifiers =
Development Status :: 4 - Beta
Environment :: Plugins
Framework :: Sphinx :: Extension
Intended Audience :: Developers
License :: OSI Approved :: MIT License
Natural Language :: English
Programming Language :: Python
Programming Language :: Python :: 3
Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
project_urls =
Documentation = https://sphinx-autoapi.readthedocs.io/en/latest/
[options]
packages = find:
include_package_data = True
python_requires = >=3.6
install_requires =
astroid>=2.7
Jinja2
PyYAML
sphinx>=3.0
unidecode
[options.extras_require]
docs =
sphinx
sphinx_rtd_theme
go =
sphinxcontrib-golangdomain
dotnet =
sphinxcontrib-dotnetdomain
[options.packages.find]
include =
autoapi
autoapi.*
[bdist_wheel]
universal = 1
sphinx-autoapi-1.8.4/setup.py 0000664 0000000 0000000 00000000045 14106520141 0016200 0 ustar 00root root 0000000 0000000 from setuptools import setup
setup()
sphinx-autoapi-1.8.4/tests/ 0000775 0000000 0000000 00000000000 14106520141 0015631 5 ustar 00root root 0000000 0000000 sphinx-autoapi-1.8.4/tests/dotnetexample/ 0000775 0000000 0000000 00000000000 14106520141 0020502 5 ustar 00root root 0000000 0000000 sphinx-autoapi-1.8.4/tests/dotnetexample/Makefile 0000664 0000000 0000000 00000016525 14106520141 0022153 0 ustar 00root root 0000000 0000000 # Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
# User-friendly check for sphinx-build
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
endif
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext
help:
@echo "Please use \`make ' where is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " applehelp to make an Apple Help Book"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " xml to make Docutils-native XML files"
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
@echo " coverage to run coverage check of the documentation (if enabled)"
clean:
rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/SphinxAutoAPI.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/SphinxAutoAPI.qhc"
applehelp:
$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
@echo
@echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
@echo "N.B. You won't be able to view it unless you put it in" \
"~/Library/Documentation/Help or install it in your application" \
"bundle."
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/SphinxAutoAPI"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/SphinxAutoAPI"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
latexpdfja:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through platex and dvipdfmx..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
coverage:
$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
@echo "Testing of coverage in the sources finished, look at the " \
"results in $(BUILDDIR)/coverage/python.txt."
xml:
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
@echo
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
pseudoxml:
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
@echo
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
livehtml:
sphinx-autobuild -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
sphinx-autoapi-1.8.4/tests/dotnetexample/README.md 0000664 0000000 0000000 00000000506 14106520141 0021762 0 ustar 00root root 0000000 0000000 ## .NET example
This assumes that you have a ``docfx`` executable on your `PATH`.
It also depends on the sphinxcontrib-dotnet domain: https://github.com/readthedocs/sphinxcontrib-dotnetdomain
Currently this is setup to build the Indentity repo from ASP.Net
You should simply be able to run ``make html`` in this directory.
sphinx-autoapi-1.8.4/tests/dotnetexample/conf.py 0000664 0000000 0000000 00000001524 14106520141 0022003 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
templates_path = ["_templates"]
source_suffix = ".rst"
master_doc = "index"
project = u"dotnetexample"
copyright = u"2015, readthedocs"
author = u"readthedocs"
version = "0.1"
release = "0.1"
language = None
exclude_patterns = ["_build"]
pygments_style = "sphinx"
todo_include_todos = False
html_theme = "sphinx_rtd_theme"
htmlhelp_basename = "dotnetexampledoc"
extensions = ["autoapi.extension", "sphinxcontrib.dotnetdomain"]
autoapi_type = "dotnet"
# Turn this on for debugging
# autoapi_keep_files = True
autoapi_dirs = ["example/Identity/src/"]
import os
SITE_ROOT = os.path.dirname(os.path.realpath(__file__))
DIR = os.path.join(SITE_ROOT, autoapi_dirs[0])
if not os.path.exists(DIR):
os.system(
"git clone https://github.com/aspnet/Identity %s"
% os.path.join(SITE_ROOT, "example/Identity")
)
sphinx-autoapi-1.8.4/tests/dotnetexample/example/ 0000775 0000000 0000000 00000000000 14106520141 0022135 5 ustar 00root root 0000000 0000000 sphinx-autoapi-1.8.4/tests/dotnetexample/example/clone.sh 0000775 0000000 0000000 00000000055 14106520141 0023574 0 ustar 00root root 0000000 0000000 git clone https://github.com/aspnet/Identity
sphinx-autoapi-1.8.4/tests/dotnetexample/index.rst 0000664 0000000 0000000 00000000163 14106520141 0022343 0 ustar 00root root 0000000 0000000 Welcome to .Net example's documentation!
========================================
.. toctree::
autoapi/index
sphinx-autoapi-1.8.4/tests/fixtures/ 0000775 0000000 0000000 00000000000 14106520141 0017502 5 ustar 00root root 0000000 0000000 sphinx-autoapi-1.8.4/tests/fixtures/dotnet.json 0000664 0000000 0000000 00000072412 14106520141 0021700 0 ustar 00root root 0000000 0000000 {
"items": [
{
"uid": "Microsoft.AspNet.Identity.IUserStore`1",
"parent": "Microsoft.AspNet.Identity",
"syntax": {
"content": "public interface IUserStore : IDisposable where TUser : class",
"typeParameters": [
{
"id": "TUser",
"description": "The type encapsulating a user."
}
],
"content.vb": "Public Interface IUserStore(Of TUser As Class) Inherits IDisposable"
},
"children": [
"Microsoft.AspNet.Identity.IUserStore`1.CreateAsync(`0,CancellationToken)",
"Microsoft.AspNet.Identity.IUserStore`1.DeleteAsync(`0,CancellationToken)",
"Microsoft.AspNet.Identity.IUserStore`1.FindByIdAsync(System.String,CancellationToken)",
"Microsoft.AspNet.Identity.IUserStore`1.FindByNameAsync(System.String,CancellationToken)",
"Microsoft.AspNet.Identity.IUserStore`1.GetNormalizedUserNameAsync(`0,CancellationToken)",
"Microsoft.AspNet.Identity.IUserStore`1.GetUserIdAsync(`0,CancellationToken)",
"Microsoft.AspNet.Identity.IUserStore`1.GetUserNameAsync(`0,CancellationToken)",
"Microsoft.AspNet.Identity.IUserStore`1.SetNormalizedUserNameAsync(`0,System.String,CancellationToken)",
"Microsoft.AspNet.Identity.IUserStore`1.SetUserNameAsync(`0,System.String,CancellationToken)",
"Microsoft.AspNet.Identity.IUserStore`1.UpdateAsync(`0,CancellationToken)"
],
"fullName.vb": "Microsoft.AspNet.Identity.IUserStore(Of TUser)",
"name.vb": "IUserStore(Of TUser)",
"langs": [
"csharp",
"vb"
],
"fullName": "Microsoft.AspNet.Identity.IUserStore",
"id": "IUserStore`1",
"name": "IUserStore",
"assemblies": [
"Microsoft.AspNet.Identity"
],
"namespace": "Microsoft.AspNet.Identity",
"summary": "Provides an abstraction for a store which manages user accounts.",
"source": {
"path": "aspnet/identity/src/Microsoft.AspNet.Identity/IUserStore.cs",
"startLine": 13,
"remote": {
"repo": "https://github.com/aspnet/apidocs",
"path": "aspnet/identity/src/Microsoft.AspNet.Identity/IUserStore.cs",
"branch": "master"
}
},
"href": "Microsoft.AspNet.Identity.IUserStore`1.yml",
"type": "Interface",
"example": []
},
{
"name": "GetUserIdAsync(TUser, CancellationToken)",
"parent": "Microsoft.AspNet.Identity.IUserStore`1",
"href": "Microsoft.AspNet.Identity.IUserStore`1.yml",
"assemblies": [
"Microsoft.AspNet.Identity"
],
"namespace": "Microsoft.AspNet.Identity",
"summary": "Gets the user identifier for the specified .",
"source": {
"path": "aspnet/identity/src/Microsoft.AspNet.Identity/IUserStore.cs",
"startLine": 21,
"remote": {
"repo": "https://github.com/aspnet/apidocs",
"path": "aspnet/identity/src/Microsoft.AspNet.Identity/IUserStore.cs",
"branch": "master"
}
},
"fullName.vb": "Microsoft.AspNet.Identity.IUserStore(Of TUser).GetUserIdAsync(TUser, CancellationToken)",
"id": "GetUserIdAsync(`0,CancellationToken)",
"langs": [
"csharp",
"vb"
],
"fullName": "Microsoft.AspNet.Identity.IUserStore.GetUserIdAsync(TUser, CancellationToken)",
"syntax": {
"content": "Task GetUserIdAsync(TUser user, CancellationToken cancellationToken)",
"return": {
"type": "Task{System.String}",
"description": "The that represents the asynchronous operation, containing the identifier for the specified ."
},
"content.vb": "Function GetUserIdAsync(user As TUser, cancellationToken As CancellationToken) As Task(Of String)",
"parameters": [
{
"type": "{TUser}",
"id": "user",
"description": "The user whose identifier should be retrieved."
},
{
"type": "CancellationToken",
"id": "cancellationToken",
"description": "The used to propagate notifications that the operation should be canceled."
}
]
},
"type": "Method",
"example": [],
"uid": "Microsoft.AspNet.Identity.IUserStore`1.GetUserIdAsync(`0,CancellationToken)"
},
{
"name": "GetUserNameAsync(TUser, CancellationToken)",
"parent": "Microsoft.AspNet.Identity.IUserStore`1",
"href": "Microsoft.AspNet.Identity.IUserStore`1.yml",
"assemblies": [
"Microsoft.AspNet.Identity"
],
"namespace": "Microsoft.AspNet.Identity",
"summary": "Gets the user name for the specified .",
"source": {
"path": "aspnet/identity/src/Microsoft.AspNet.Identity/IUserStore.cs",
"startLine": 29,
"remote": {
"repo": "https://github.com/aspnet/apidocs",
"path": "aspnet/identity/src/Microsoft.AspNet.Identity/IUserStore.cs",
"branch": "master"
}
},
"fullName.vb": "Microsoft.AspNet.Identity.IUserStore(Of TUser).GetUserNameAsync(TUser, CancellationToken)",
"id": "GetUserNameAsync(`0,CancellationToken)",
"langs": [
"csharp",
"vb"
],
"fullName": "Microsoft.AspNet.Identity.IUserStore.GetUserNameAsync(TUser, CancellationToken)",
"syntax": {
"content": "Task GetUserNameAsync(TUser user, CancellationToken cancellationToken)",
"return": {
"type": "Task{System.String}",
"description": "The that represents the asynchronous operation, containing the name for the specified ."
},
"content.vb": "Function GetUserNameAsync(user As TUser, cancellationToken As CancellationToken) As Task(Of String)",
"parameters": [
{
"type": "{TUser}",
"id": "user",
"description": "The user whose name should be retrieved."
},
{
"type": "CancellationToken",
"id": "cancellationToken",
"description": "The used to propagate notifications that the operation should be canceled."
}
]
},
"type": "Method",
"example": [],
"uid": "Microsoft.AspNet.Identity.IUserStore`1.GetUserNameAsync(`0,CancellationToken)"
},
{
"name": "SetUserNameAsync(TUser, String, CancellationToken)",
"parent": "Microsoft.AspNet.Identity.IUserStore`1",
"href": "Microsoft.AspNet.Identity.IUserStore`1.yml",
"assemblies": [
"Microsoft.AspNet.Identity"
],
"namespace": "Microsoft.AspNet.Identity",
"summary": "Sets the given for the specified .",
"source": {
"path": "aspnet/identity/src/Microsoft.AspNet.Identity/IUserStore.cs",
"startLine": 38,
"remote": {
"repo": "https://github.com/aspnet/apidocs",
"path": "aspnet/identity/src/Microsoft.AspNet.Identity/IUserStore.cs",
"branch": "master"
}
},
"fullName.vb": "Microsoft.AspNet.Identity.IUserStore(Of TUser).SetUserNameAsync(TUser, System.String, CancellationToken)",
"id": "SetUserNameAsync(`0,System.String,CancellationToken)",
"langs": [
"csharp",
"vb"
],
"fullName": "Microsoft.AspNet.Identity.IUserStore.SetUserNameAsync(TUser, System.String, CancellationToken)",
"syntax": {
"content": "Task SetUserNameAsync(TUser user, string userName, CancellationToken cancellationToken)",
"return": {
"type": "Task",
"description": "The that represents the asynchronous operation."
},
"content.vb": "Function SetUserNameAsync(user As TUser, userName As String, cancellationToken As CancellationToken) As Task",
"parameters": [
{
"type": "{TUser}",
"id": "user",
"description": "The user whose name should be set."
},
{
"type": "System.String",
"id": "userName",
"description": "The user name to set."
},
{
"type": "CancellationToken",
"id": "cancellationToken",
"description": "The used to propagate notifications that the operation should be canceled."
}
]
},
"type": "Method",
"example": [],
"uid": "Microsoft.AspNet.Identity.IUserStore`1.SetUserNameAsync(`0,System.String,CancellationToken)"
},
{
"name": "GetNormalizedUserNameAsync(TUser, CancellationToken)",
"parent": "Microsoft.AspNet.Identity.IUserStore`1",
"href": "Microsoft.AspNet.Identity.IUserStore`1.yml",
"assemblies": [
"Microsoft.AspNet.Identity"
],
"namespace": "Microsoft.AspNet.Identity",
"summary": "Gets the normalized user name for the specified .",
"source": {
"path": "aspnet/identity/src/Microsoft.AspNet.Identity/IUserStore.cs",
"startLine": 46,
"remote": {
"repo": "https://github.com/aspnet/apidocs",
"path": "aspnet/identity/src/Microsoft.AspNet.Identity/IUserStore.cs",
"branch": "master"
}
},
"fullName.vb": "Microsoft.AspNet.Identity.IUserStore(Of TUser).GetNormalizedUserNameAsync(TUser, CancellationToken)",
"id": "GetNormalizedUserNameAsync(`0,CancellationToken)",
"langs": [
"csharp",
"vb"
],
"fullName": "Microsoft.AspNet.Identity.IUserStore.GetNormalizedUserNameAsync(TUser, CancellationToken)",
"syntax": {
"content": "Task GetNormalizedUserNameAsync(TUser user, CancellationToken cancellationToken)",
"return": {
"type": "Task{System.String}",
"description": "The that represents the asynchronous operation, containing the normalized user name for the specified ."
},
"content.vb": "Function GetNormalizedUserNameAsync(user As TUser, cancellationToken As CancellationToken) As Task(Of String)",
"parameters": [
{
"type": "{TUser}",
"id": "user",
"description": "The user whose normalized name should be retrieved."
},
{
"type": "CancellationToken",
"id": "cancellationToken",
"description": "The used to propagate notifications that the operation should be canceled."
}
]
},
"type": "Method",
"example": [],
"uid": "Microsoft.AspNet.Identity.IUserStore`1.GetNormalizedUserNameAsync(`0,CancellationToken)"
},
{
"name": "SetNormalizedUserNameAsync(TUser, String, CancellationToken)",
"parent": "Microsoft.AspNet.Identity.IUserStore`1",
"href": "Microsoft.AspNet.Identity.IUserStore`1.yml",
"assemblies": [
"Microsoft.AspNet.Identity"
],
"namespace": "Microsoft.AspNet.Identity",
"summary": "Sets the given normalized name for the specified .",
"source": {
"path": "aspnet/identity/src/Microsoft.AspNet.Identity/IUserStore.cs",
"startLine": 55,
"remote": {
"repo": "https://github.com/aspnet/apidocs",
"path": "aspnet/identity/src/Microsoft.AspNet.Identity/IUserStore.cs",
"branch": "master"
}
},
"fullName.vb": "Microsoft.AspNet.Identity.IUserStore(Of TUser).SetNormalizedUserNameAsync(TUser, System.String, CancellationToken)",
"id": "SetNormalizedUserNameAsync(`0,System.String,CancellationToken)",
"langs": [
"csharp",
"vb"
],
"fullName": "Microsoft.AspNet.Identity.IUserStore.SetNormalizedUserNameAsync(TUser, System.String, CancellationToken)",
"syntax": {
"content": "Task SetNormalizedUserNameAsync(TUser user, string normalizedName, CancellationToken cancellationToken)",
"return": {
"type": "Task",
"description": "The that represents the asynchronous operation."
},
"content.vb": "Function SetNormalizedUserNameAsync(user As TUser, normalizedName As String, cancellationToken As CancellationToken) As Task",
"parameters": [
{
"type": "{TUser}",
"id": "user",
"description": "The user whose name should be set."
},
{
"type": "System.String",
"id": "normalizedName",
"description": "The normalized name to set."
},
{
"type": "CancellationToken",
"id": "cancellationToken",
"description": "The used to propagate notifications that the operation should be canceled."
}
]
},
"type": "Method",
"example": [],
"uid": "Microsoft.AspNet.Identity.IUserStore`1.SetNormalizedUserNameAsync(`0,System.String,CancellationToken)"
},
{
"name": "CreateAsync(TUser, CancellationToken)",
"parent": "Microsoft.AspNet.Identity.IUserStore`1",
"href": "Microsoft.AspNet.Identity.IUserStore`1.yml",
"assemblies": [
"Microsoft.AspNet.Identity"
],
"namespace": "Microsoft.AspNet.Identity",
"summary": "Creates the specified in the user store.",
"source": {
"path": "aspnet/identity/src/Microsoft.AspNet.Identity/IUserStore.cs",
"startLine": 63,
"remote": {
"repo": "https://github.com/aspnet/apidocs",
"path": "aspnet/identity/src/Microsoft.AspNet.Identity/IUserStore.cs",
"branch": "master"
}
},
"fullName.vb": "Microsoft.AspNet.Identity.IUserStore(Of TUser).CreateAsync(TUser, CancellationToken)",
"id": "CreateAsync(`0,CancellationToken)",
"langs": [
"csharp",
"vb"
],
"fullName": "Microsoft.AspNet.Identity.IUserStore.CreateAsync(TUser, CancellationToken)",
"syntax": {
"content": "Task CreateAsync(TUser user, CancellationToken cancellationToken)",
"return": {
"type": "Task{Microsoft.AspNet.Identity.IdentityResult}",
"description": "The that represents the asynchronous operation, containing the of the creation operation."
},
"content.vb": "Function CreateAsync(user As TUser, cancellationToken As CancellationToken) As Task(Of IdentityResult)",
"parameters": [
{
"type": "{TUser}",
"id": "user",
"description": "The user to create."
},
{
"type": "CancellationToken",
"id": "cancellationToken",
"description": "The used to propagate notifications that the operation should be canceled."
}
]
},
"type": "Method",
"example": [],
"uid": "Microsoft.AspNet.Identity.IUserStore`1.CreateAsync(`0,CancellationToken)"
},
{
"name": "UpdateAsync(TUser, CancellationToken)",
"parent": "Microsoft.AspNet.Identity.IUserStore`1",
"href": "Microsoft.AspNet.Identity.IUserStore`1.yml",
"assemblies": [
"Microsoft.AspNet.Identity"
],
"namespace": "Microsoft.AspNet.Identity",
"summary": "Updates the specified in the user store.",
"source": {
"path": "aspnet/identity/src/Microsoft.AspNet.Identity/IUserStore.cs",
"startLine": 71,
"remote": {
"repo": "https://github.com/aspnet/apidocs",
"path": "aspnet/identity/src/Microsoft.AspNet.Identity/IUserStore.cs",
"branch": "master"
}
},
"fullName.vb": "Microsoft.AspNet.Identity.IUserStore(Of TUser).UpdateAsync(TUser, CancellationToken)",
"id": "UpdateAsync(`0,CancellationToken)",
"langs": [
"csharp",
"vb"
],
"fullName": "Microsoft.AspNet.Identity.IUserStore.UpdateAsync(TUser, CancellationToken)",
"syntax": {
"content": "Task UpdateAsync(TUser user, CancellationToken cancellationToken)",
"return": {
"type": "Task{Microsoft.AspNet.Identity.IdentityResult}",
"description": "The that represents the asynchronous operation, containing the of the update operation."
},
"content.vb": "Function UpdateAsync(user As TUser, cancellationToken As CancellationToken) As Task(Of IdentityResult)",
"parameters": [
{
"type": "{TUser}",
"id": "user",
"description": "The user to update."
},
{
"type": "CancellationToken",
"id": "cancellationToken",
"description": "The used to propagate notifications that the operation should be canceled."
}
]
},
"type": "Method",
"example": [],
"uid": "Microsoft.AspNet.Identity.IUserStore`1.UpdateAsync(`0,CancellationToken)"
},
{
"name": "DeleteAsync(TUser, CancellationToken)",
"parent": "Microsoft.AspNet.Identity.IUserStore`1",
"href": "Microsoft.AspNet.Identity.IUserStore`1.yml",
"assemblies": [
"Microsoft.AspNet.Identity"
],
"namespace": "Microsoft.AspNet.Identity",
"summary": "Deletes the specified from the user store.",
"source": {
"path": "aspnet/identity/src/Microsoft.AspNet.Identity/IUserStore.cs",
"startLine": 79,
"remote": {
"repo": "https://github.com/aspnet/apidocs",
"path": "aspnet/identity/src/Microsoft.AspNet.Identity/IUserStore.cs",
"branch": "master"
}
},
"fullName.vb": "Microsoft.AspNet.Identity.IUserStore(Of TUser).DeleteAsync(TUser, CancellationToken)",
"id": "DeleteAsync(`0,CancellationToken)",
"langs": [
"csharp",
"vb"
],
"fullName": "Microsoft.AspNet.Identity.IUserStore.DeleteAsync(TUser, CancellationToken)",
"syntax": {
"content": "Task DeleteAsync(TUser user, CancellationToken cancellationToken)",
"return": {
"type": "Task{Microsoft.AspNet.Identity.IdentityResult}",
"description": "The that represents the asynchronous operation, containing the of the update operation."
},
"content.vb": "Function DeleteAsync(user As TUser, cancellationToken As CancellationToken) As Task(Of IdentityResult)",
"parameters": [
{
"type": "{TUser}",
"id": "user",
"description": "The user to delete."
},
{
"type": "CancellationToken",
"id": "cancellationToken",
"description": "The used to propagate notifications that the operation should be canceled."
}
]
},
"type": "Method",
"example": [],
"uid": "Microsoft.AspNet.Identity.IUserStore`1.DeleteAsync(`0,CancellationToken)"
},
{
"name": "FindByIdAsync(String, CancellationToken)",
"parent": "Microsoft.AspNet.Identity.IUserStore`1",
"href": "Microsoft.AspNet.Identity.IUserStore`1.yml",
"assemblies": [
"Microsoft.AspNet.Identity"
],
"namespace": "Microsoft.AspNet.Identity",
"summary": "Finds and returns a user, if any, who has the specified .",
"source": {
"path": "aspnet/identity/src/Microsoft.AspNet.Identity/IUserStore.cs",
"startLine": 89,
"remote": {
"repo": "https://github.com/aspnet/apidocs",
"path": "aspnet/identity/src/Microsoft.AspNet.Identity/IUserStore.cs",
"branch": "master"
}
},
"fullName.vb": "Microsoft.AspNet.Identity.IUserStore(Of TUser).FindByIdAsync(System.String, CancellationToken)",
"id": "FindByIdAsync(System.String,CancellationToken)",
"langs": [
"csharp",
"vb"
],
"fullName": "Microsoft.AspNet.Identity.IUserStore.FindByIdAsync(System.String, CancellationToken)",
"syntax": {
"content": "Task FindByIdAsync(string userId, CancellationToken cancellationToken)",
"return": {
"type": "Task{{TUser}}",
"description": "The that represents the asynchronous operation, containing the user matching the specified if it exists."
},
"content.vb": "Function FindByIdAsync(userId As String, cancellationToken As CancellationToken) As Task(Of TUser)",
"parameters": [
{
"type": "System.String",
"id": "userId",
"description": "The user ID to search for."
},
{
"type": "CancellationToken",
"id": "cancellationToken",
"description": "The used to propagate notifications that the operation should be canceled."
}
]
},
"type": "Method",
"example": [],
"uid": "Microsoft.AspNet.Identity.IUserStore`1.FindByIdAsync(System.String,CancellationToken)"
},
{
"name": "FindByNameAsync(String, CancellationToken)",
"parent": "Microsoft.AspNet.Identity.IUserStore`1",
"href": "Microsoft.AspNet.Identity.IUserStore`1.yml",
"assemblies": [
"Microsoft.AspNet.Identity"
],
"namespace": "Microsoft.AspNet.Identity",
"summary": "Finds and returns a user, if any, who has the specified normalized user name.",
"source": {
"path": "aspnet/identity/src/Microsoft.AspNet.Identity/IUserStore.cs",
"startLine": 99,
"remote": {
"repo": "https://github.com/aspnet/apidocs",
"path": "aspnet/identity/src/Microsoft.AspNet.Identity/IUserStore.cs",
"branch": "master"
}
},
"fullName.vb": "Microsoft.AspNet.Identity.IUserStore(Of TUser).FindByNameAsync(System.String, CancellationToken)",
"id": "FindByNameAsync(System.String,CancellationToken)",
"langs": [
"csharp",
"vb"
],
"fullName": "Microsoft.AspNet.Identity.IUserStore.FindByNameAsync(System.String, CancellationToken)",
"syntax": {
"content": "Task FindByNameAsync(string normalizedUserName, CancellationToken cancellationToken)",
"return": {
"type": "Task{{TUser}}",
"description": "The that represents the asynchronous operation, containing the user matching the specified if it exists."
},
"content.vb": "Function FindByNameAsync(normalizedUserName As String, cancellationToken As CancellationToken) As Task(Of TUser)",
"parameters": [
{
"type": "System.String",
"id": "normalizedUserName",
"description": "The normalized user name to search for."
},
{
"type": "CancellationToken",
"id": "cancellationToken",
"description": "The used to propagate notifications that the operation should be canceled."
}
]
},
"type": "Method",
"example": [],
"uid": "Microsoft.AspNet.Identity.IUserStore`1.FindByNameAsync(System.String,CancellationToken)"
}
],
"references": [
{
"fullName": "Microsoft.AspNet.Identity",
"isExternal": false,
"uid": "Microsoft.AspNet.Identity",
"name": "Microsoft.AspNet.Identity"
},
{
"fullName": "TUser",
"isExternal": false,
"uid": "{TUser}",
"name": "TUser"
},
{
"fullName": "CancellationToken",
"isExternal": true,
"name": "CancellationToken",
"parent": null,
"uid": "CancellationToken"
},
{
"definition": "Task`1",
"uid": "Task{System.String}",
"parent": null,
"spec.vb": [
{
"fullName": "Task",
"uid": "Task`1",
"name": "Task",
"isExternal": true
},
{
"fullName": "(Of ",
"name": "(Of "
},
{
"fullName": "System.String",
"uid": "System.String",
"name": "String",
"isExternal": true
},
{
"fullName": ")",
"name": ")"
}
],
"fullName.vb": "Task(Of System.String)",
"name.vb": "Task(Of String)",
"fullName": "Task",
"spec.csharp": [
{
"fullName": "Task",
"uid": "Task`1",
"name": "Task",
"isExternal": true
},
{
"fullName": "<",
"name": "<"
},
{
"fullName": "System.String",
"uid": "System.String",
"name": "String",
"isExternal": true
},
{
"fullName": ">",
"name": ">"
}
],
"name": "Task"
},
{
"fullName": null,
"isExternal": false,
"uid": null,
"name": null
},
{
"name": "Task<>",
"parent": null,
"spec.vb": [
{
"fullName": "Task",
"uid": "Task`1",
"name": "Task",
"isExternal": true
},
{
"fullName": "(Of ",
"name": "(Of "
},
{
"fullName": null,
"name": null
},
{
"fullName": ")",
"name": ")"
}
],
"fullName.vb": "Task(Of )",
"name.vb": "Task(Of )",
"uid": "Task`1",
"fullName": "Task<>",
"spec.csharp": [
{
"fullName": "Task",
"uid": "Task`1",
"name": "Task",
"isExternal": true
},
{
"fullName": "<",
"name": "<"
},
{
"fullName": null,
"name": null
},
{
"fullName": ">",
"name": ">"
}
],
"isExternal": true
},
{
"fullName": "System.String",
"isExternal": true,
"name": "String",
"parent": "System",
"uid": "System.String"
},
{
"fullName": "Task",
"isExternal": true,
"name": "Task",
"parent": null,
"uid": "Task"
},
{
"fullName": "System",
"isExternal": false,
"uid": "System",
"name": "System"
},
{
"definition": "Task`1",
"uid": "Task{Microsoft.AspNet.Identity.IdentityResult}",
"parent": null,
"href": "Microsoft.AspNet.Identity.IdentityResult.yml",
"spec.vb": [
{
"fullName": "Task",
"uid": "Task`1",
"name": "Task",
"isExternal": true
},
{
"fullName": "(Of ",
"name": "(Of "
},
{
"fullName": "Microsoft.AspNet.Identity.IdentityResult",
"href": "Microsoft.AspNet.Identity.IdentityResult.yml",
"uid": "Microsoft.AspNet.Identity.IdentityResult",
"name": "IdentityResult"
},
{
"fullName": ")",
"name": ")"
}
],
"fullName.vb": "Task(Of Microsoft.AspNet.Identity.IdentityResult)",
"name.vb": "Task(Of IdentityResult)",
"fullName": "Task",
"spec.csharp": [
{
"fullName": "Task",
"uid": "Task`1",
"name": "Task",
"isExternal": true
},
{
"fullName": "<",
"name": "<"
},
{
"fullName": "Microsoft.AspNet.Identity.IdentityResult",
"href": "Microsoft.AspNet.Identity.IdentityResult.yml",
"uid": "Microsoft.AspNet.Identity.IdentityResult",
"name": "IdentityResult"
},
{
"fullName": ">",
"name": ">"
}
],
"name": "Task"
},
{
"definition": "Task`1",
"uid": "Task{{TUser}}",
"parent": null,
"spec.vb": [
{
"fullName": "Task",
"uid": "Task`1",
"name": "Task",
"isExternal": true
},
{
"fullName": "(Of ",
"name": "(Of "
},
{
"fullName": "TUser",
"name": "TUser"
},
{
"fullName": ")",
"name": ")"
}
],
"fullName.vb": "Task(Of TUser)",
"name.vb": "Task(Of TUser)",
"fullName": "Task",
"spec.csharp": [
{
"fullName": "Task",
"uid": "Task`1",
"name": "Task",
"isExternal": true
},
{
"fullName": "<",
"name": "<"
},
{
"fullName": "TUser",
"name": "TUser"
},
{
"fullName": ">",
"name": ">"
}
],
"name": "Task"
}
]
} sphinx-autoapi-1.8.4/tests/fixtures/go.json 0000664 0000000 0000000 00000005400 14106520141 0021001 0 ustar 00root root 0000000 0000000 {
"funcs": [
{
"name": "CopyFuncs",
"doc": "CopyFuncs produces a json-annotated array of Func objects from an array of GoDoc Func objects.\n",
"packageName": "main",
"packageImportPath": "example",
"recv": "",
"orig": ""
},
{
"name": "CopyValues",
"doc": "CopyValues produces a json-annotated array of Value objects from an array of GoDoc Value objects.\n",
"packageName": "main",
"packageImportPath": "example",
"recv": "",
"orig": ""
}
],
"name": "main",
"vars": [],
"doc": "",
"notes": {},
"bugs": null,
"filenames": [
"example/godocjson.go"
],
"importPath": "example",
"consts": [],
"imports": [
"encoding/json",
"fmt",
"go/doc",
"go/parser",
"go/token",
"os"
],
"type": "package",
"types": [
{
"funcs": [],
"name": "Func",
"vars": [],
"doc": "Func represents a function declaration.\n",
"packageName": "main",
"packageImportPath": "example",
"consts": [],
"methods": []
},
{
"funcs": [],
"name": "Note",
"vars": [],
"doc": "Note represents a note comment.\n",
"packageName": "main",
"packageImportPath": "example",
"consts": [],
"methods": []
},
{
"funcs": [
{
"name": "CopyPackage",
"doc": "CopyPackage produces a json-annotated Package object from a GoDoc Package object.\n",
"packageName": "main",
"packageImportPath": "example",
"recv": "",
"orig": ""
}
],
"name": "Package",
"vars": [],
"doc": "Package represents a package declaration.\n",
"packageName": "main",
"packageImportPath": "example",
"consts": [],
"methods": []
},
{
"funcs": [],
"name": "Type",
"vars": [],
"doc": "Type represents a type declaration.\n",
"packageName": "main",
"packageImportPath": "example",
"consts": [],
"methods": []
},
{
"funcs": [],
"name": "Value",
"vars": [],
"doc": "Value represents a value declaration.\n",
"packageName": "main",
"packageImportPath": "example",
"consts": [],
"methods": []
}
]
} sphinx-autoapi-1.8.4/tests/fixtures/javascript.json 0000664 0000000 0000000 00000022454 14106520141 0022552 0 ustar 00root root 0000000 0000000 [
{
"comment": "/**\n * Creates an instance of Circle.\n *\n * @constructor\n * @this {Circle}\n * @param {number} r The desired radius of the circle.\n */",
"kind": "class",
"description": "Creates an instance of Circle.",
"this": "{Circle}",
"see": [],
"meta": {
"path": "/Users/eric/projects/sphinx-autoapi/tests/jsexample/example",
"range": [
134,
251
],
"code": {
"node": "