diff --git a/setup.cfg b/setup.cfg index 0dfbcc6..4886f2c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -32,7 +32,7 @@ test = [options.package_data] sphinx_automodapi = templates/*/*.rst -sphinx_automodapi.tests = cases/*/*.*, cases/*/*/*.*, cases/*/*/*/*.*, cases/*/*/*/*/*.* +sphinx_automodapi.tests = cases/*/*.*, cases/*/*/*.*, cases/*/*/*/*.*, cases/*/*/*/*/*.*, duplicated_warning/docs/* [tool:pytest] minversion = 4.6 diff --git a/sphinx_automodapi/automodapi.py b/sphinx_automodapi/automodapi.py index f993cf5..a6cd719 100644 --- a/sphinx_automodapi/automodapi.py +++ b/sphinx_automodapi/automodapi.py @@ -63,6 +63,10 @@ documentation. The option ``:inherited-members:`` or ``:no-inherited-members:`` allows the user to overrride the global setting. + * ``:noindex:`` + Propagates the ``noindex`` flag to autodoc. Use it to avoid duplicate + objects warnings. + This extension also adds four sphinx configuration options: @@ -239,6 +243,7 @@ def automodapi_replace(sourcestr, app, dotoctree=True, docname=None, hds = '-^' allowedpkgnms = [] allowothers = False + noindex = False # look for actual options unknownops = [] @@ -266,6 +271,8 @@ def automodapi_replace(sourcestr, app, dotoctree=True, docname=None, inherited_members = False elif opname == 'include-all-objects': allowothers = True + elif opname == 'noindex': + noindex = True else: unknownops.append(opname) @@ -321,6 +328,8 @@ def automodapi_replace(sourcestr, app, dotoctree=True, docname=None, clsfuncoptions = [] if toctreestr: clsfuncoptions.append(toctreestr) + if noindex: + clsfuncoptions.append(':noindex:') if toskip: clsfuncoptions.append(':skip: ' + ','.join(toskip)) if allowedpkgnms: diff --git a/sphinx_automodapi/automodsumm.py b/sphinx_automodapi/automodsumm.py index dd2dfc2..10a71f6 100644 --- a/sphinx_automodapi/automodsumm.py +++ b/sphinx_automodapi/automodsumm.py @@ -124,6 +124,7 @@ class Automodsumm(Autosummary): option_spec['allowed-package-names'] = _str_list_converter option_spec['inherited-members'] = flag option_spec['no-inherited-members'] = flag + option_spec['noindex'] = flag def run(self): env = self.state.document.settings.env @@ -457,7 +458,7 @@ def generate_automodsumm_docs(lines, srcfn, app=None, suffix='.rst', new_files = [] # write - for name, path, template_name, inherited_mem in sorted(items): + for name, path, template_name, inherited_mem, noindex in sorted(items): if path is None: # The corresponding autosummary:: directive did not have @@ -601,6 +602,7 @@ def get_members_class(obj, typ, include_public=[], else: mod_name, obj_name = '.'.join(parts[:-1]), parts[-1] + ns['noindex'] = noindex ns['fullname'] = name ns['module'] = mod_name ns['objname'] = obj_name diff --git a/sphinx_automodapi/templates/autosummary_core/class.rst b/sphinx_automodapi/templates/autosummary_core/class.rst index 85105fa..198d04b 100644 --- a/sphinx_automodapi/templates/autosummary_core/class.rst +++ b/sphinx_automodapi/templates/autosummary_core/class.rst @@ -9,6 +9,9 @@ .. autoclass:: {{ objname }} :show-inheritance: + {% if noindex -%} + :noindex: + {%- endif %} {% if '__init__' in methods %} {% set caught_result = methods.remove('__init__') %} diff --git a/sphinx_automodapi/tests/duplicated_warning/__init__.py b/sphinx_automodapi/tests/duplicated_warning/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/sphinx_automodapi/tests/duplicated_warning/docs/conf.py b/sphinx_automodapi/tests/duplicated_warning/docs/conf.py new file mode 100644 index 0000000..b3a40ef --- /dev/null +++ b/sphinx_automodapi/tests/duplicated_warning/docs/conf.py @@ -0,0 +1,11 @@ +project = 'duplicated' +copyright = '2022, Maximilian Linhoff' +author = 'Maximilian Linhoff' +release = '0.1' + + +extensions = [ + "sphinx_automodapi.automodapi", +] + +html_theme = 'alabaster' diff --git a/sphinx_automodapi/tests/duplicated_warning/docs/foo.rst b/sphinx_automodapi/tests/duplicated_warning/docs/foo.rst new file mode 100644 index 0000000..15c9792 --- /dev/null +++ b/sphinx_automodapi/tests/duplicated_warning/docs/foo.rst @@ -0,0 +1,9 @@ +Foo Submodule +============= + + +API Reference +------------- + +.. automodapi:: sphinx_automodapi.tests.duplicated_warning.duplicated.foo + :noindex: diff --git a/sphinx_automodapi/tests/duplicated_warning/docs/index.rst b/sphinx_automodapi/tests/duplicated_warning/docs/index.rst new file mode 100644 index 0000000..55140c9 --- /dev/null +++ b/sphinx_automodapi/tests/duplicated_warning/docs/index.rst @@ -0,0 +1,19 @@ +.. duplicated documentation master file, created by + sphinx-quickstart on Tue Mar 29 17:11:23 2022. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to duplicated's documentation! +====================================== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + foo + + +API Reference +------------- + +.. automodapi:: sphinx_automodapi.tests.duplicated_warning.duplicated diff --git a/sphinx_automodapi/tests/duplicated_warning/duplicated/__init__.py b/sphinx_automodapi/tests/duplicated_warning/duplicated/__init__.py new file mode 100644 index 0000000..41d8653 --- /dev/null +++ b/sphinx_automodapi/tests/duplicated_warning/duplicated/__init__.py @@ -0,0 +1,6 @@ +from .foo import Foo + + +__all__ = [ + 'Foo', +] diff --git a/sphinx_automodapi/tests/duplicated_warning/duplicated/foo/__init__.py b/sphinx_automodapi/tests/duplicated_warning/duplicated/foo/__init__.py new file mode 100644 index 0000000..a15a7ef --- /dev/null +++ b/sphinx_automodapi/tests/duplicated_warning/duplicated/foo/__init__.py @@ -0,0 +1,5 @@ +from .foo import Foo + +__all__ = [ + "Foo", +] diff --git a/sphinx_automodapi/tests/duplicated_warning/duplicated/foo/foo.py b/sphinx_automodapi/tests/duplicated_warning/duplicated/foo/foo.py new file mode 100644 index 0000000..c706ea3 --- /dev/null +++ b/sphinx_automodapi/tests/duplicated_warning/duplicated/foo/foo.py @@ -0,0 +1,17 @@ +__all__ = [ + 'Foo', + 'Bar', + 'baz', +] + + +class Foo: + '''Awesome Foo class''' + + +class Bar: + '''Awesome Bar class''' + + +def baz(): + '''Awesome baz function''' diff --git a/sphinx_automodapi/tests/example_module/abstract_classes.py b/sphinx_automodapi/tests/example_module/abstract_classes.py index a5893c3..af1102d 100644 --- a/sphinx_automodapi/tests/example_module/abstract_classes.py +++ b/sphinx_automodapi/tests/example_module/abstract_classes.py @@ -1,10 +1,4 @@ -try: - # Python 3 - from collections.abc import Sequence -except ImportError: - # Python 2 (this import also works in Python <= 3.7, but will be removed in - # Python 3.8) - from collections import Sequence +from collections.abc import Sequence __all__ = ['SequenceSubclass'] diff --git a/sphinx_automodapi/tests/test_cases.py b/sphinx_automodapi/tests/test_cases.py index 351e388..63b0171 100644 --- a/sphinx_automodapi/tests/test_cases.py +++ b/sphinx_automodapi/tests/test_cases.py @@ -115,3 +115,28 @@ def test_run_full_case(tmpdir, case_dir, parallel): with open(path_reference, encoding='utf8') as f: reference = f.read() assert actual.strip() == reference.strip() + + +def test_duplicated_warning(tmpdir): + input_dir = os.path.join(os.path.dirname(__file__), 'duplicated_warning', 'docs') + docs_dir = tmpdir.mkdir('docs').strpath + + start_dir = os.path.abspath('.') + src_dir = '.' + + for root, dirnames, filenames in os.walk(input_dir): + for filename in filenames: + root_dir = os.path.join(docs_dir, os.path.relpath(root, input_dir)) + ensuredir(root_dir) + input_file = os.path.join(root, filename) + shutil.copy(input_file, root_dir) + + argv = ['-W', '-b', 'html', src_dir, '_build/html'] + + try: + os.chdir(docs_dir) + status = build_main(argv=argv) + finally: + os.chdir(start_dir) + + assert status == 0 diff --git a/sphinx_automodapi/utils.py b/sphinx_automodapi/utils.py index f0b1fff..2cab3ad 100644 --- a/sphinx_automodapi/utils.py +++ b/sphinx_automodapi/utils.py @@ -108,7 +108,7 @@ def find_mod_objs(modname, onlylocals=False): def find_autosummary_in_lines_for_automodsumm(lines, module=None, filename=None): """Find out what items appear in autosummary:: directives in the given lines. - Returns a list of (name, toctree, template, inherited_members) + Returns a list of (name, toctree, template, inherited_members, noindex) where *name* is a name of an object and *toctree* the :toctree: path of the corresponding autosummary directive (relative to the root of the file name), @@ -133,12 +133,14 @@ def find_autosummary_in_lines_for_automodsumm(lines, module=None, filename=None) template_arg_re = re.compile(r'^\s+:template:\s*(.*?)\s*$') inherited_members_arg_re = re.compile(r'^\s+:inherited-members:\s*$') no_inherited_members_arg_re = re.compile(r'^\s+:no-inherited-members:\s*$') + noindex_arg_re = re.compile(r'^\s+:noindex:\s*$') documented = [] toctree = None template = None inherited_members = None + noindex = None current_module = module in_autosummary = False base_indent = "" @@ -168,6 +170,11 @@ def find_autosummary_in_lines_for_automodsumm(lines, module=None, filename=None) inherited_members = False continue + m = noindex_arg_re.match(line) + if m: + noindex = True + continue + if line.strip().startswith(':'): warn(line) continue # skip options @@ -181,7 +188,7 @@ def find_autosummary_in_lines_for_automodsumm(lines, module=None, filename=None) not name.startswith(current_module + '.'): name = "%s.%s" % (current_module, name) documented.append((name, toctree, template, - inherited_members)) + inherited_members, noindex)) continue if not line.strip() or line.startswith(base_indent + " "):