From 0a5b84b8be4b5032a2e1e2d3a03bbe84c89fe8df Mon Sep 17 00:00:00 2001 From: Ashley Whetter Date: Mon, 31 Aug 2020 21:17:57 -0700 Subject: [PATCH] autoapi_file_patterns is in order of preference Closes #243 --- autoapi/mappers/base.py | 15 ++++++++++- autoapi/mappers/python/parser.py | 3 ++- docs/reference/config.rst | 6 +++++ tests/python/pyiexample/conf.py | 2 +- tests/python/pyiexample/example/example.py | 2 ++ tests/python/pyiexample2/conf.py | 20 +++++++++++++++ tests/python/pyiexample2/example/example.py | 8 ++++++ tests/python/pyiexample2/example/example.pyi | 2 ++ tests/python/pyiexample2/index.rst | 27 ++++++++++++++++++++ tests/python/test_pyintegration.py | 19 ++++++++++++++ 10 files changed, 101 insertions(+), 3 deletions(-) create mode 100644 tests/python/pyiexample/example/example.py create mode 100644 tests/python/pyiexample2/conf.py create mode 100644 tests/python/pyiexample2/example/example.py create mode 100644 tests/python/pyiexample2/example/example.pyi create mode 100644 tests/python/pyiexample2/index.rst diff --git a/autoapi/mappers/base.py b/autoapi/mappers/base.py index fa90733..94b10af 100644 --- a/autoapi/mappers/base.py +++ b/autoapi/mappers/base.py @@ -219,12 +219,24 @@ class SphinxMapperBase(object): # 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): - for pattern in patterns: + 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( @@ -244,6 +256,7 @@ class SphinxMapperBase(object): filename = os.path.join(root, filename) yield filename + seen.add(norm_name) def read_file(self, path, **kwargs): """Read file input into memory diff --git a/autoapi/mappers/python/parser.py b/autoapi/mappers/python/parser.py index a747121..9ad8a2c 100644 --- a/autoapi/mappers/python/parser.py +++ b/autoapi/mappers/python/parser.py @@ -4,6 +4,7 @@ import os import sys import astroid +import astroid.builder from . import astroid_utils @@ -39,7 +40,7 @@ class Parser(object): module_parts.appendleft(module_part) module_name = ".".join(module_parts) - node = astroid.MANAGER.ast_from_file(file_path, module_name, source=True) + node = astroid.builder.AstroidBuilder().file_build(file_path, module_name) return self.parse(node) def parse_file(self, file_path): diff --git a/docs/reference/config.rst b/docs/reference/config.rst index 476dfab..106124d 100644 --- a/docs/reference/config.rst +++ b/docs/reference/config.rst @@ -52,6 +52,12 @@ Configuration Options 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: ========== ============================================ diff --git a/tests/python/pyiexample/conf.py b/tests/python/pyiexample/conf.py index a3292c7..2382363 100644 --- a/tests/python/pyiexample/conf.py +++ b/tests/python/pyiexample/conf.py @@ -18,4 +18,4 @@ htmlhelp_basename = "pyexampledoc" extensions = ["sphinx.ext.autodoc", "autoapi.extension"] autoapi_type = "python" autoapi_dirs = ["example"] -autoapi_file_pattern = "*.py" +autoapi_file_patterns = ["*.pyi", "*.py"] diff --git a/tests/python/pyiexample/example/example.py b/tests/python/pyiexample/example/example.py new file mode 100644 index 0000000..9590479 --- /dev/null +++ b/tests/python/pyiexample/example/example.py @@ -0,0 +1,2 @@ +class DoNotFindThis(object): + """pyi files should be preferred.""" diff --git a/tests/python/pyiexample2/conf.py b/tests/python/pyiexample2/conf.py new file mode 100644 index 0000000..46a98a9 --- /dev/null +++ b/tests/python/pyiexample2/conf.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- + +templates_path = ["_templates"] +source_suffix = ".rst" +master_doc = "index" +project = u"pyexample" +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 = "alabaster" +html_static_path = ["_static"] +htmlhelp_basename = "pyexampledoc" +extensions = ["sphinx.ext.autodoc", "autoapi.extension"] +autoapi_type = "python" +autoapi_dirs = ["example"] diff --git a/tests/python/pyiexample2/example/example.py b/tests/python/pyiexample2/example/example.py new file mode 100644 index 0000000..11a61dd --- /dev/null +++ b/tests/python/pyiexample2/example/example.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- +"""Example module + +This is a description +""" + +class Foo(object): + pass diff --git a/tests/python/pyiexample2/example/example.pyi b/tests/python/pyiexample2/example/example.pyi new file mode 100644 index 0000000..1ce84b9 --- /dev/null +++ b/tests/python/pyiexample2/example/example.pyi @@ -0,0 +1,2 @@ +class DoNotFindThis(object): + """py files should be preferred.""" diff --git a/tests/python/pyiexample2/index.rst b/tests/python/pyiexample2/index.rst new file mode 100644 index 0000000..01e8e25 --- /dev/null +++ b/tests/python/pyiexample2/index.rst @@ -0,0 +1,27 @@ +.. pyexample documentation master file, created by + sphinx-quickstart on Fri May 29 13:34:37 2015. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to pyexample's documentation! +===================================== + +.. toctree:: + + autoapi/index + manualapi + +Contents: + +.. toctree:: + :maxdepth: 2 + + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/tests/python/test_pyintegration.py b/tests/python/test_pyintegration.py index 25a34b0..c28adb3 100644 --- a/tests/python/test_pyintegration.py +++ b/tests/python/test_pyintegration.py @@ -127,6 +127,9 @@ class TestSimpleStubModule(object): with io.open(example_path, encoding="utf8") as example_handle: example_file = example_handle.read() + # Are pyi files preferred + assert "DoNotFindThis" not in example_file + assert "class example.Foo" in example_file assert "class Meta" in example_file assert "Another class var docstring" in example_file @@ -139,6 +142,22 @@ class TestSimpleStubModule(object): assert "Set an attribute" in example_file +class TestSimpleStubModuleNotPreferred(object): + @pytest.fixture(autouse=True, scope="class") + def built(self, builder): + builder("pyiexample2") + + def test_integration(self): + example_path = "_build/text/autoapi/example/index.txt" + with io.open(example_path, encoding="utf8") as example_handle: + example_file = example_handle.read() + + # Are py files preferred + assert "DoNotFindThis" not in example_file + + assert "Foo" in example_file + + @pytest.mark.skipif( sys.version_info < (3, 6), reason="Annotations are invalid in Python <3.5" )