xref: /petsc/src/binding/petsc4py/docs/source/conf.py (revision 2c804a55bf7293d13d730bf664b1d16fb852206e)
155a74a43SLisandro Dalcin# Configuration file for the Sphinx documentation builder.
25808f684SSatish Balay#
355a74a43SLisandro Dalcin# For the full list of built-in configuration values, see the documentation:
455a74a43SLisandro Dalcin# https://www.sphinx-doc.org/en/master/usage/configuration.html
555a74a43SLisandro Dalcin
655a74a43SLisandro Dalcin# -- Path setup --------------------------------------------------------------
75808f684SSatish Balay
85808f684SSatish Balay# If extensions (or modules to document with autodoc) are in another directory,
95808f684SSatish Balay# add these directories to sys.path here. If the directory is relative to the
105808f684SSatish Balay# documentation root, use os.path.abspath to make it absolute, like shown here.
115808f684SSatish Balay
12d919c72dSLisandro Dalcinimport re
1355a74a43SLisandro Dalcinimport os
1455a74a43SLisandro Dalcinimport shutil
1555a74a43SLisandro Dalcinimport sys
16*2c804a55SBarry Smithimport subprocess
1755a74a43SLisandro Dalcinimport typing
1855a74a43SLisandro Dalcinimport datetime
1955a74a43SLisandro Dalcinimport importlib
2055a74a43SLisandro Dalcinimport sphobjinv
2155a74a43SLisandro Dalcinimport functools
2255a74a43SLisandro Dalcinimport pylit
2355a74a43SLisandro Dalcinfrom sphinx.ext.napoleon.docstring import NumpyDocstring
2455a74a43SLisandro Dalcin
2555a74a43SLisandro Dalcinsys.path.insert(0, os.path.abspath('.'))
2655a74a43SLisandro Dalcin_today = datetime.datetime.now()
2755a74a43SLisandro Dalcin
286f336411SStefano Zampini# FIXME: allow building from build?
2955a74a43SLisandro Dalcin
3055a74a43SLisandro Dalcin# -- Project information -----------------------------------------------------
3155a74a43SLisandro Dalcin# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
3255a74a43SLisandro Dalcin
3355a74a43SLisandro Dalcinpackage = 'petsc4py'
3455a74a43SLisandro Dalcin
35d919c72dSLisandro Dalcindocdir = os.path.abspath(os.path.dirname(__file__))
36d919c72dSLisandro Dalcintopdir = os.path.abspath(os.path.join(docdir, *[os.path.pardir] * 2))
3755a74a43SLisandro Dalcin
386f336411SStefano Zampini
3955a74a43SLisandro Dalcindef pkg_version():
40d919c72dSLisandro Dalcin    with open(os.path.join(topdir, 'src', package, '__init__.py')) as f:
415808f684SSatish Balay        m = re.search(r"__version__\s*=\s*'(.*)'", f.read())
425808f684SSatish Balay        return m.groups()[0]
435808f684SSatish Balay
445808f684SSatish Balay
45d919c72dSLisandro Dalcindef get_doc_branch():
46d919c72dSLisandro Dalcin    release = 1
47d919c72dSLisandro Dalcin    if topdir.endswith(os.path.join(os.path.sep, 'src', 'binding', package)):
48d919c72dSLisandro Dalcin        rootdir = os.path.abspath(os.path.join(topdir, *[os.path.pardir] * 3))
49d919c72dSLisandro Dalcin        rootname = package.replace('4py', '')
50d919c72dSLisandro Dalcin        version_h = os.path.join(rootdir, 'include', f'{rootname}version.h')
51d919c72dSLisandro Dalcin        if os.path.exists(version_h) and os.path.isfile(version_h):
52d919c72dSLisandro Dalcin            release_macro = f'{rootname.upper()}_VERSION_RELEASE'
536f336411SStefano Zampini            version_re = re.compile(rf'#define\s+{release_macro}\s+([-]*\d+)')
54d919c72dSLisandro Dalcin            with open(version_h, 'r') as f:
55d919c72dSLisandro Dalcin                release = int(version_re.search(f.read()).groups()[0])
56d919c72dSLisandro Dalcin    return 'release' if release else 'main'
57d919c72dSLisandro Dalcin
58d919c72dSLisandro Dalcin
596f336411SStefano Zampini__project__ = 'PETSc for Python'
606f336411SStefano Zampini__author__ = 'Lisandro Dalcin'
616f336411SStefano Zampini__copyright__ = f'{_today.year}, {__author__}'
625808f684SSatish Balay
6355a74a43SLisandro Dalcinrelease = pkg_version()
6455a74a43SLisandro Dalcinversion = release.rsplit('.', 1)[0]
655808f684SSatish Balay
665808f684SSatish Balay
6755a74a43SLisandro Dalcin# -- General configuration ---------------------------------------------------
6855a74a43SLisandro Dalcin# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
695808f684SSatish Balay
7055a74a43SLisandro Dalcinextensions = [
7155a74a43SLisandro Dalcin    'sphinx.ext.autodoc',
7255a74a43SLisandro Dalcin    'sphinx.ext.autosummary',
7355a74a43SLisandro Dalcin    'sphinx.ext.intersphinx',
7455a74a43SLisandro Dalcin    'sphinx.ext.napoleon',
75b3f8c7a1SStefano Zampini    'sphinx.ext.extlinks',
7655a74a43SLisandro Dalcin]
775808f684SSatish Balay
7855a74a43SLisandro Dalcintemplates_path = ['_templates']
795808f684SSatish Balayexclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
805808f684SSatish Balay
8155a74a43SLisandro Dalcindefault_role = 'any'
8255a74a43SLisandro Dalcin
8355a74a43SLisandro Dalcinpygments_style = 'tango'
8455a74a43SLisandro Dalcin
8555a74a43SLisandro Dalcinnitpicky = True
8655a74a43SLisandro Dalcinnitpick_ignore = [
8755a74a43SLisandro Dalcin    ('envvar', 'NUMPY_INCLUDE'),
8855a74a43SLisandro Dalcin    ('py:class', 'ndarray'),  # FIXME
8955a74a43SLisandro Dalcin    ('py:class', 'typing_extensions.Self'),
9055a74a43SLisandro Dalcin]
9155a74a43SLisandro Dalcinnitpick_ignore_regex = [
9255a74a43SLisandro Dalcin    (r'c:.*', r'MPI_.*'),
9355a74a43SLisandro Dalcin    (r'c:.*', r'Petsc.*'),
9455a74a43SLisandro Dalcin    (r'envvar', r'(LD_LIBRARY_)?PATH'),
9555a74a43SLisandro Dalcin    (r'envvar', r'(MPICH|OMPI|MPIEXEC)_.*'),
9655a74a43SLisandro Dalcin]
9755a74a43SLisandro Dalcin
9855a74a43SLisandro Dalcintoc_object_entries = False
9955a74a43SLisandro Dalcintoc_object_entries_show_parents = 'hide'
10055a74a43SLisandro Dalcin# python_use_unqualified_type_names = True
10155a74a43SLisandro Dalcin
10255a74a43SLisandro Dalcinautodoc_class_signature = 'separated'
10355a74a43SLisandro Dalcinautodoc_typehints = 'description'
10455a74a43SLisandro Dalcinautodoc_typehints_format = 'short'
10555a74a43SLisandro Dalcinautodoc_mock_imports = []
10655a74a43SLisandro Dalcinautodoc_type_aliases = {}
10755a74a43SLisandro Dalcin
10855a74a43SLisandro Dalcinautosummary_context = {
10955a74a43SLisandro Dalcin    'synopsis': {},
11055a74a43SLisandro Dalcin    'autotype': {},
11155a74a43SLisandro Dalcin}
1125808f684SSatish Balay
1131d9f564dSStefano Zampini# Links depends on the actual branch -> release or main
1141d9f564dSStefano Zampiniwww = f'https://gitlab.com/petsc/petsc/-/tree/{get_doc_branch()}'
1156f336411SStefano Zampiniextlinks = {'sources': (f'{www}/src/binding/petsc4py/src/%s', '%s')}
1165808f684SSatish Balay
117d919c72dSLisandro Dalcinnapoleon_preprocess_types = True
118d919c72dSLisandro Dalcin
119d919c72dSLisandro Dalcintry:
120d919c72dSLisandro Dalcin    import sphinx_rtd_theme
1216f336411SStefano Zampini
122d919c72dSLisandro Dalcin    if 'sphinx_rtd_theme' not in extensions:
123d919c72dSLisandro Dalcin        extensions.append('sphinx_rtd_theme')
124d919c72dSLisandro Dalcinexcept ImportError:
125d919c72dSLisandro Dalcin    sphinx_rtd_theme = None
126d919c72dSLisandro Dalcin
127d919c72dSLisandro Dalcinintersphinx_mapping = {
128d919c72dSLisandro Dalcin    'python': ('https://docs.python.org/3/', None),
129d919c72dSLisandro Dalcin    'numpy': ('https://numpy.org/doc/stable/', None),
130d919c72dSLisandro Dalcin    'numpydoc': ('https://numpydoc.readthedocs.io/en/latest/', None),
131d919c72dSLisandro Dalcin    'mpi4py': ('https://mpi4py.readthedocs.io/en/stable/', None),
132d919c72dSLisandro Dalcin    'pyopencl': ('https://documen.tician.de/pyopencl/', None),
133d919c72dSLisandro Dalcin    'dlpack': ('https://dmlc.github.io/dlpack/latest/', None),
134d919c72dSLisandro Dalcin    'petsc': ('https://petsc.org/release/', None),
135d919c72dSLisandro Dalcin}
136d919c72dSLisandro Dalcin
1376f336411SStefano Zampini
13855a74a43SLisandro Dalcindef _mangle_petsc_intersphinx():
13955a74a43SLisandro Dalcin    """Preprocess the keys in PETSc's intersphinx inventory.
14055a74a43SLisandro Dalcin
14155a74a43SLisandro Dalcin    PETSc have intersphinx keys of the form:
14255a74a43SLisandro Dalcin
14355a74a43SLisandro Dalcin        manualpages/Vec/VecShift
14455a74a43SLisandro Dalcin
14555a74a43SLisandro Dalcin    instead of:
14655a74a43SLisandro Dalcin
14755a74a43SLisandro Dalcin        petsc.VecShift
14855a74a43SLisandro Dalcin
14955a74a43SLisandro Dalcin    This function downloads their object inventory and strips the leading path
15055a74a43SLisandro Dalcin    elements so that references to PETSc names actually resolve."""
151e3ec4a52SBarry Smith
152d919c72dSLisandro Dalcin    website = intersphinx_mapping['petsc'][0].partition('/release/')[0]
153d919c72dSLisandro Dalcin    branch = get_doc_branch()
1546f336411SStefano Zampini    doc_url = f'{website}/{branch}/'
1556f336411SStefano Zampini    if 'LOC' in os.environ and os.path.isfile(
1566f336411SStefano Zampini        os.path.join(os.environ['LOC'], 'objects.inv')
1576f336411SStefano Zampini    ):
1586f336411SStefano Zampini        inventory_url = 'file://' + os.path.join(os.environ['LOC'], 'objects.inv')
1590c386d85SStefano Zampini    else:
1606f336411SStefano Zampini        inventory_url = f'{doc_url}objects.inv'
1616f336411SStefano Zampini    print('Using PETSC inventory from ' + inventory_url)
1620c386d85SStefano Zampini    inventory = sphobjinv.Inventory(url=inventory_url)
163e3ec4a52SBarry Smith    print(inventory)
164d919c72dSLisandro Dalcin
165d919c72dSLisandro Dalcin    for obj in inventory.objects:
1666f336411SStefano Zampini        if obj.name.startswith('manualpages'):
1676f336411SStefano Zampini            obj.name = 'petsc.' + '/'.join(obj.name.split('/')[2:])
1686f336411SStefano Zampini            obj.role = 'class'
1696f336411SStefano Zampini            obj.domain = 'py'
17055a74a43SLisandro Dalcin
1716f336411SStefano Zampini    new_inventory_filename = 'petsc_objects.inv'
172d919c72dSLisandro Dalcin    sphobjinv.writebytes(
1736f336411SStefano Zampini        new_inventory_filename, sphobjinv.compress(inventory.data_file(contract=True))
174d919c72dSLisandro Dalcin    )
1750c386d85SStefano Zampini    intersphinx_mapping['petsc'] = (doc_url, new_inventory_filename)
17655a74a43SLisandro Dalcin
17755a74a43SLisandro Dalcin
17855a74a43SLisandro Dalcin_mangle_petsc_intersphinx()
17955a74a43SLisandro Dalcin
18055a74a43SLisandro Dalcin
18155a74a43SLisandro Dalcindef _setup_mpi4py_typing():
18255a74a43SLisandro Dalcin    pkg = type(sys)('mpi4py')
18355a74a43SLisandro Dalcin    mod = type(sys)('mpi4py.MPI')
18455a74a43SLisandro Dalcin    mod.__package__ = pkg.__name__
18555a74a43SLisandro Dalcin    sys.modules[pkg.__name__] = pkg
18655a74a43SLisandro Dalcin    sys.modules[mod.__name__] = mod
18755a74a43SLisandro Dalcin    for clsname in (
18855a74a43SLisandro Dalcin        'Intracomm',
18955a74a43SLisandro Dalcin        'Datatype',
19055a74a43SLisandro Dalcin        'Op',
19155a74a43SLisandro Dalcin    ):
19255a74a43SLisandro Dalcin        cls = type(clsname, (), {})
19355a74a43SLisandro Dalcin        cls.__module__ = mod.__name__
19455a74a43SLisandro Dalcin        setattr(mod, clsname, cls)
19555a74a43SLisandro Dalcin
19655a74a43SLisandro Dalcin
19755a74a43SLisandro Dalcindef _patch_domain_python():
19855a74a43SLisandro Dalcin    from sphinx.domains.python import PythonDomain
1996f336411SStefano Zampini
20055a74a43SLisandro Dalcin    PythonDomain.object_types['data'].roles += ('class',)
20155a74a43SLisandro Dalcin
20255a74a43SLisandro Dalcin
20355a74a43SLisandro Dalcindef _setup_autodoc(app):
20455a74a43SLisandro Dalcin    from sphinx.ext import autodoc
20555a74a43SLisandro Dalcin    from sphinx.util import inspect
20655a74a43SLisandro Dalcin    from sphinx.util import typing
20755a74a43SLisandro Dalcin
20855a74a43SLisandro Dalcin    #
20955a74a43SLisandro Dalcin
21055a74a43SLisandro Dalcin    def stringify_annotation(annotation, mode='fully-qualified-except-typing'):
21155a74a43SLisandro Dalcin        qualname = getattr(annotation, '__qualname__', '')
21255a74a43SLisandro Dalcin        module = getattr(annotation, '__module__', '')
21355a74a43SLisandro Dalcin        args = getattr(annotation, '__args__', None)
21455a74a43SLisandro Dalcin        if module == 'builtins' and qualname and args is not None:
21555a74a43SLisandro Dalcin            args = ', '.join(stringify_annotation(a, mode) for a in args)
21655a74a43SLisandro Dalcin            return f'{qualname}[{args}]'
21755a74a43SLisandro Dalcin        return stringify_annotation_orig(annotation, mode)
21855a74a43SLisandro Dalcin
21955a74a43SLisandro Dalcin    try:
22055a74a43SLisandro Dalcin        stringify_annotation_orig = typing.stringify_annotation
22155a74a43SLisandro Dalcin        inspect.stringify_annotation = stringify_annotation
22255a74a43SLisandro Dalcin        typing.stringify_annotation = stringify_annotation
22355a74a43SLisandro Dalcin        autodoc.stringify_annotation = stringify_annotation
22455a74a43SLisandro Dalcin        autodoc.typehints.stringify_annotation = stringify_annotation
22555a74a43SLisandro Dalcin    except AttributeError:
22655a74a43SLisandro Dalcin        stringify_annotation_orig = typing.stringify
22755a74a43SLisandro Dalcin        inspect.stringify_annotation = stringify_annotation
22855a74a43SLisandro Dalcin        typing.stringify = stringify_annotation
22955a74a43SLisandro Dalcin        autodoc.stringify_typehint = stringify_annotation
23055a74a43SLisandro Dalcin
23155a74a43SLisandro Dalcin    #
23255a74a43SLisandro Dalcin
23355a74a43SLisandro Dalcin    class ClassDocumenterMixin:
23455a74a43SLisandro Dalcin        def __init__(self, *args, **kwargs):
23555a74a43SLisandro Dalcin            super().__init__(*args, **kwargs)
23655a74a43SLisandro Dalcin            if self.config.autodoc_class_signature == 'separated':
23755a74a43SLisandro Dalcin                members = self.options.members
23855a74a43SLisandro Dalcin                special_members = self.options.special_members
23955a74a43SLisandro Dalcin                if special_members is not None:
24055a74a43SLisandro Dalcin                    for name in ('__new__', '__init__'):
24155a74a43SLisandro Dalcin                        if name in members:
24255a74a43SLisandro Dalcin                            members.remove(name)
24355a74a43SLisandro Dalcin                        if name in special_members:
24455a74a43SLisandro Dalcin                            special_members.remove(name)
24555a74a43SLisandro Dalcin
24655a74a43SLisandro Dalcin    class ClassDocumenter(
24755a74a43SLisandro Dalcin        ClassDocumenterMixin,
24855a74a43SLisandro Dalcin        autodoc.ClassDocumenter,
24955a74a43SLisandro Dalcin    ):
25055a74a43SLisandro Dalcin        pass
25155a74a43SLisandro Dalcin
25255a74a43SLisandro Dalcin    class ExceptionDocumenter(
25355a74a43SLisandro Dalcin        ClassDocumenterMixin,
25455a74a43SLisandro Dalcin        autodoc.ExceptionDocumenter,
25555a74a43SLisandro Dalcin    ):
25655a74a43SLisandro Dalcin        pass
25755a74a43SLisandro Dalcin
25855a74a43SLisandro Dalcin    app.add_autodocumenter(ClassDocumenter, override=True)
25955a74a43SLisandro Dalcin    app.add_autodocumenter(ExceptionDocumenter, override=True)
26055a74a43SLisandro Dalcin
26155a74a43SLisandro Dalcin
26255a74a43SLisandro Dalcindef _monkey_patch_returns():
26355a74a43SLisandro Dalcin    """Rewrite the role of names in "Returns" sections.
26455a74a43SLisandro Dalcin
26555a74a43SLisandro Dalcin    This is needed because Napoleon uses ``:class:`` for the return types
26655a74a43SLisandro Dalcin    and this does not work with type aliases like ``ArrayScalar``. To resolve
26755a74a43SLisandro Dalcin    this we swap ``:class:`` for ``:any:``.
26855a74a43SLisandro Dalcin
26955a74a43SLisandro Dalcin    """
2706f336411SStefano Zampini    _parse_returns_section = NumpyDocstring._parse_returns_section
27155a74a43SLisandro Dalcin
27255a74a43SLisandro Dalcin    @functools.wraps(NumpyDocstring._parse_returns_section)
27355a74a43SLisandro Dalcin    def wrapper(*args, **kwargs):
27455a74a43SLisandro Dalcin        out = _parse_returns_section(*args, **kwargs)
2756f336411SStefano Zampini        return [line.replace(':class:', ':any:') for line in out]
27655a74a43SLisandro Dalcin
27755a74a43SLisandro Dalcin    NumpyDocstring._parse_returns_section = wrapper
27855a74a43SLisandro Dalcin
27955a74a43SLisandro Dalcin
28055a74a43SLisandro Dalcindef _monkey_patch_see_also():
28155a74a43SLisandro Dalcin    """Rewrite the role of names in "see also" sections.
28255a74a43SLisandro Dalcin
28355a74a43SLisandro Dalcin    Napoleon uses :obj: for all names found in "see also" sections but we
28455a74a43SLisandro Dalcin    need :all: so that references to labels work."""
28555a74a43SLisandro Dalcin
2866f336411SStefano Zampini    _parse_numpydoc_see_also_section = NumpyDocstring._parse_numpydoc_see_also_section
28755a74a43SLisandro Dalcin
28855a74a43SLisandro Dalcin    @functools.wraps(NumpyDocstring._parse_numpydoc_see_also_section)
28955a74a43SLisandro Dalcin    def wrapper(*args, **kwargs):
29055a74a43SLisandro Dalcin        out = _parse_numpydoc_see_also_section(*args, **kwargs)
2916f336411SStefano Zampini        return [line.replace(':obj:', ':any:') for line in out]
29255a74a43SLisandro Dalcin
29355a74a43SLisandro Dalcin    NumpyDocstring._parse_numpydoc_see_also_section = wrapper
29455a74a43SLisandro Dalcin
29555a74a43SLisandro Dalcin
29655a74a43SLisandro Dalcindef _apply_monkey_patches():
29755a74a43SLisandro Dalcin    """Modify Napoleon types after parsing to make references work."""
29855a74a43SLisandro Dalcin    _monkey_patch_returns()
29955a74a43SLisandro Dalcin    _monkey_patch_see_also()
30055a74a43SLisandro Dalcin
30155a74a43SLisandro Dalcin
30255a74a43SLisandro Dalcin_apply_monkey_patches()
30355a74a43SLisandro Dalcin
30455a74a43SLisandro Dalcin
30555a74a43SLisandro Dalcindef _process_demos(*demos):
30655a74a43SLisandro Dalcin    # Convert demo .py files to rst. Also copy the .py file so it can be
30755a74a43SLisandro Dalcin    # linked from the demo rst file.
30855a74a43SLisandro Dalcin    try:
3096f336411SStefano Zampini        os.mkdir('demo')
31055a74a43SLisandro Dalcin    except FileExistsError:
31155a74a43SLisandro Dalcin        pass
31255a74a43SLisandro Dalcin    for demo in demos:
3136f336411SStefano Zampini        demo_dir = os.path.join('demo', os.path.dirname(demo))
3146f336411SStefano Zampini        demo_src = os.path.join(os.pardir, os.pardir, 'demo', demo)
31555a74a43SLisandro Dalcin        try:
31655a74a43SLisandro Dalcin            os.mkdir(demo_dir)
31755a74a43SLisandro Dalcin        except FileExistsError:
31855a74a43SLisandro Dalcin            pass
3196f336411SStefano Zampini        with open(demo_src, 'r') as infile:
3206f336411SStefano Zampini            with open(
3216f336411SStefano Zampini                os.path.join(os.path.join('demo', os.path.splitext(demo)[0] + '.rst')),
3226f336411SStefano Zampini                'w',
32355a74a43SLisandro Dalcin            ) as outfile:
32455a74a43SLisandro Dalcin                converter = pylit.Code2Text(infile)
32555a74a43SLisandro Dalcin                outfile.write(str(converter))
32655a74a43SLisandro Dalcin        demo_copy_name = os.path.join(demo_dir, os.path.basename(demo))
32755a74a43SLisandro Dalcin        shutil.copyfile(demo_src, demo_copy_name)
32855a74a43SLisandro Dalcin        html_static_path.append(demo_copy_name)
3296f336411SStefano Zampini    with open(os.path.join('demo', 'demo.rst'), 'w') as demofile:
33055a74a43SLisandro Dalcin        demofile.write("""
33155a74a43SLisandro Dalcinpetsc4py demos
33255a74a43SLisandro Dalcin==============
33355a74a43SLisandro Dalcin
33455a74a43SLisandro Dalcin.. toctree::
33555a74a43SLisandro Dalcin
33655a74a43SLisandro Dalcin""")
33755a74a43SLisandro Dalcin        for demo in demos:
3386f336411SStefano Zampini            demofile.write('    ' + os.path.splitext(demo)[0] + '\n')
3396f336411SStefano Zampini        demofile.write('\n')
3406f336411SStefano Zampini
34155a74a43SLisandro Dalcin
34255a74a43SLisandro Dalcinhtml_static_path = []
3436f336411SStefano Zampini_process_demos('poisson2d/poisson2d.py')
34455a74a43SLisandro Dalcin
34555a74a43SLisandro Dalcin
34655a74a43SLisandro Dalcindef setup(app):
34755a74a43SLisandro Dalcin    _setup_mpi4py_typing()
34855a74a43SLisandro Dalcin    _patch_domain_python()
34955a74a43SLisandro Dalcin    _monkey_patch_returns()
35055a74a43SLisandro Dalcin    _monkey_patch_see_also()
35155a74a43SLisandro Dalcin    _setup_autodoc(app)
35255a74a43SLisandro Dalcin
35355a74a43SLisandro Dalcin    try:
35455a74a43SLisandro Dalcin        from petsc4py import PETSc
35555a74a43SLisandro Dalcin    except ImportError:
35655a74a43SLisandro Dalcin        autodoc_mock_imports.append('PETSc')
35755a74a43SLisandro Dalcin        return
35855a74a43SLisandro Dalcin    del PETSc.DA  # FIXME
35955a74a43SLisandro Dalcin
36055a74a43SLisandro Dalcin    sys_dwb = sys.dont_write_bytecode
36155a74a43SLisandro Dalcin    sys.dont_write_bytecode = True
36255a74a43SLisandro Dalcin    import apidoc
3636f336411SStefano Zampini
36455a74a43SLisandro Dalcin    sys.dont_write_bytecode = sys_dwb
36555a74a43SLisandro Dalcin
36655a74a43SLisandro Dalcin    name = PETSc.__name__
36755a74a43SLisandro Dalcin    here = os.path.abspath(os.path.dirname(__file__))
36855a74a43SLisandro Dalcin    outdir = os.path.join(here, apidoc.OUTDIR)
36955a74a43SLisandro Dalcin    source = os.path.join(outdir, f'{name}.py')
37055a74a43SLisandro Dalcin    getmtime = os.path.getmtime
37155a74a43SLisandro Dalcin    generate = (
37255a74a43SLisandro Dalcin        not os.path.exists(source)
37355a74a43SLisandro Dalcin        or getmtime(source) < getmtime(PETSc.__file__)
37455a74a43SLisandro Dalcin        or getmtime(source) < getmtime(apidoc.__file__)
37555a74a43SLisandro Dalcin    )
37655a74a43SLisandro Dalcin    if generate:
37755a74a43SLisandro Dalcin        apidoc.generate(source)
37855a74a43SLisandro Dalcin    module = apidoc.load_module(source)
37955a74a43SLisandro Dalcin    apidoc.replace_module(module)
38055a74a43SLisandro Dalcin
38155a74a43SLisandro Dalcin    modules = [
38255a74a43SLisandro Dalcin        'petsc4py',
38355a74a43SLisandro Dalcin    ]
38455a74a43SLisandro Dalcin    typing_overload = typing.overload
38555a74a43SLisandro Dalcin    typing.overload = lambda arg: arg
38655a74a43SLisandro Dalcin    for name in modules:
38755a74a43SLisandro Dalcin        mod = importlib.import_module(name)
38855a74a43SLisandro Dalcin        ann = apidoc.load_module(f'{mod.__file__}i', name)
38955a74a43SLisandro Dalcin        apidoc.annotate(mod, ann)
39055a74a43SLisandro Dalcin    typing.overload = typing_overload
39155a74a43SLisandro Dalcin
39255a74a43SLisandro Dalcin    from petsc4py import typing as tp
3936f336411SStefano Zampini
39455a74a43SLisandro Dalcin    for attr in tp.__all__:
39555a74a43SLisandro Dalcin        autodoc_type_aliases[attr] = f'~petsc4py.typing.{attr}'
39655a74a43SLisandro Dalcin
3976f336411SStefano Zampini
39855a74a43SLisandro Dalcin# -- Options for HTML output -------------------------------------------------
39955a74a43SLisandro Dalcin# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
4005808f684SSatish Balay
4015808f684SSatish Balay# The theme to use for HTML and HTML Help pages.  See the documentation for
4025808f684SSatish Balay# a list of builtin themes.
40355a74a43SLisandro Dalcinhtml_theme = 'pydata_sphinx_theme'
4045808f684SSatish Balay
405*2c804a55SBarry Smithhtml_theme_options = {
406*2c804a55SBarry Smith    'navigation_with_keys': True,
407*2c804a55SBarry Smith    "footer_end": ["theme-version", "last-updated"],
408*2c804a55SBarry Smith}
409*2c804a55SBarry Smithgit_describe_version = subprocess.check_output(['git', 'describe', '--always']).strip().decode('utf-8') # noqa: S603, S607
410*2c804a55SBarry Smithhtml_last_updated_fmt = r'%Y-%m-%dT%H:%M:%S%z (' + git_describe_version + ')'
411bc1908f0SBarry Smith
4125808f684SSatish Balay# -- Options for HTMLHelp output ------------------------------------------
4135808f684SSatish Balay
4145808f684SSatish Balay# Output file base name for HTML help builder.
41555a74a43SLisandro Dalcinhtmlhelp_basename = f'{package}-man'
4165808f684SSatish Balay
4175808f684SSatish Balay
4185808f684SSatish Balay# -- Options for LaTeX output ---------------------------------------------
4195808f684SSatish Balay
4205808f684SSatish Balay# (source start file, target name, title,
4215808f684SSatish Balay#  author, documentclass [howto, manual, or own class]).
4225808f684SSatish Balaylatex_documents = [
4236f336411SStefano Zampini    ('index', f'{package}.tex', __project__, __author__, 'howto'),
4245808f684SSatish Balay]
4255808f684SSatish Balay
42655a74a43SLisandro Dalcinlatex_elements = {
42755a74a43SLisandro Dalcin    'papersize': 'a4',
42855a74a43SLisandro Dalcin}
42955a74a43SLisandro Dalcin
4305808f684SSatish Balay
4315808f684SSatish Balay# -- Options for manual page output ---------------------------------------
4325808f684SSatish Balay
4335808f684SSatish Balay# (source start file, name, description, authors, manual section).
4346f336411SStefano Zampiniman_pages = [('index', package, __project__, [__author__], 3)]
4355808f684SSatish Balay
4365808f684SSatish Balay
4375808f684SSatish Balay# -- Options for Texinfo output -------------------------------------------
4385808f684SSatish Balay
4395808f684SSatish Balay# (source start file, target name, title, author,
4405808f684SSatish Balay#  dir menu entry, description, category)
4415808f684SSatish Balaytexinfo_documents = [
4426f336411SStefano Zampini    (
4436f336411SStefano Zampini        'index',
4446f336411SStefano Zampini        package,
4456f336411SStefano Zampini        __project__,
4466f336411SStefano Zampini        __author__,
4476f336411SStefano Zampini        package,
4486f336411SStefano Zampini        f'{__project__}.',
4496f336411SStefano Zampini        'Miscellaneous',
4506f336411SStefano Zampini    ),
4515808f684SSatish Balay]
4525808f684SSatish Balay
45355a74a43SLisandro Dalcin
4545808f684SSatish Balay# -- Options for Epub output ----------------------------------------------
4555808f684SSatish Balay
45655a74a43SLisandro Dalcin# Output file base name for ePub builder.
45755a74a43SLisandro Dalcinepub_basename = package
458