From b93f53c7e4c84922a77f63cc0e1dca0a60a72201 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sat, 4 May 2019 01:16:07 +0900 Subject: [PATCH] apidoc: Use a template for generating package file --- sphinx/ext/apidoc.py | 79 +++++-------- sphinx/templates/apidoc/package.rst | 52 +++++++++ sphinx/templates/apidoc/toc.rst | 1 - tests/test_ext_apidoc.py | 166 ++++++++++++++++++++++++++++ 4 files changed, 244 insertions(+), 54 deletions(-) create mode 100644 sphinx/templates/apidoc/package.rst diff --git a/sphinx/ext/apidoc.py b/sphinx/ext/apidoc.py index 8c8101307..af77133b2 100644 --- a/sphinx/ext/apidoc.py +++ b/sphinx/ext/apidoc.py @@ -114,62 +114,35 @@ def create_module_file(package, basename, opts): def create_package_file(root, master_package, subroot, py_files, opts, subs, is_namespace, excludes=[]): # NOQA # type: (str, str, str, List[str], Any, List[str], bool, List[str]) -> None """Build the text of the file and write the file.""" - text = format_heading(1, ('%s package' if not is_namespace else "%s namespace") - % makename(master_package, subroot)) - - if opts.modulefirst and not is_namespace: - text += format_directive(subroot, master_package) - text += '\n' - - # build a list of directories that are szvpackages (contain an INITPY file) - # and also checks the INITPY file is not empty, or there are other python - # source files in that folder. - # (depending on settings - but shall_skip() takes care of that) - subs = [sub for sub in subs if not - shall_skip(path.join(root, sub, INITPY), opts, excludes)] - # if there are some package directories, add a TOC for theses subpackages - if subs: - text += format_heading(2, 'Subpackages') - text += '.. toctree::\n\n' - for sub in subs: - text += ' %s.%s\n' % (makename(master_package, subroot), sub) - text += '\n' - - submods = [path.splitext(sub)[0] for sub in py_files - if not shall_skip(path.join(root, sub), opts, excludes) and - sub != INITPY] - if submods: - text += format_heading(2, 'Submodules') - if opts.separatemodules: - text += '.. toctree::\n\n' - for submod in submods: - modfile = makename(master_package, makename(subroot, submod)) - text += ' %s\n' % modfile - - # generate separate file for this module - if not opts.noheadings: - filetext = format_heading(1, '%s module' % modfile) - else: - filetext = '' - filetext += format_directive(makename(subroot, submod), - master_package) - write_file(modfile, filetext, opts) - else: - for submod in submods: - modfile = makename(master_package, makename(subroot, submod)) - if not opts.noheadings: - text += format_heading(2, '%s module' % modfile) - text += format_directive(makename(subroot, submod), - master_package) - text += '\n' - text += '\n' - - if not opts.modulefirst and not is_namespace: - text += format_heading(2, 'Module contents') - text += format_directive(subroot, master_package) + # build a list of sub packages (directories containing an INITPY file) + subpackages = [sub for sub in subs if not + shall_skip(path.join(root, sub, INITPY), opts, excludes)] + subpackages = [makename(makename(master_package, subroot), pkgname) + for pkgname in subpackages] + # build a list of sub modules + submodules = [path.splitext(sub)[0] for sub in py_files + if not shall_skip(path.join(root, sub), opts, excludes) and + sub != INITPY] + submodules = [makename(master_package, makename(subroot, modname)) + for modname in submodules] + context = { + 'pkgname': makename(master_package, subroot), + 'subpackages': subpackages, + 'submodules': submodules, + 'is_namespace': is_namespace, + 'modulefirst': opts.modulefirst, + 'separatemodules': opts.separatemodules, + 'automodule_options': OPTIONS, + 'show_headings': not opts.noheadings, + } + text = ReSTRenderer(template_dir).render('package.rst', context) write_file(makename(master_package, subroot), text, opts) + if submodules and opts.separatemodules: + for submodule in submodules: + create_module_file(None, submodule, opts) + def create_modules_toc_file(modules, opts, name='modules'): # type: (List[str], Any, str) -> None diff --git a/sphinx/templates/apidoc/package.rst b/sphinx/templates/apidoc/package.rst new file mode 100644 index 000000000..0026af34c --- /dev/null +++ b/sphinx/templates/apidoc/package.rst @@ -0,0 +1,52 @@ +{%- macro automodule(modname, options) -%} +.. automodule:: {{ modname }} +{%- for option in options %} + :{{ option }}: +{%- endfor %} +{%- endmacro %} + +{%- macro toctree(docnames) -%} +.. toctree:: +{% for docname in docnames %} + {{ docname }} +{%- endfor %} +{%- endmacro %} + +{%- if is_namespace %} +{{- [pkgname, "namespace"] | join(" ") | e | heading }} +{% else %} +{{- [pkgname, "package"] | join(" ") | e | heading }} +{% endif %} + +{%- if modulefirst and not is_namespace %} +{{ automodule(pkgname, automodule_options) }} +{% endif %} + +{%- if subpackages %} +Subpackages +----------- + +{{ toctree(subpackages) }} +{% endif %} + +{%- if submodules %} +Submodules +---------- +{% if separatemodules %} +{{ toctree(submodules) }} +{%- else %} +{%- for submodule in submodules %} +{% if show_headings %} +{{- [submodule, "module"] | join(" ") | e | heading(2) }} +{% endif %} +{{ automodule(submodule, automodule_options) }} +{%- endfor %} +{% endif %} +{% endif %} + +{%- if not modulefirst and not is_namespace %} +Module contents +--------------- + +{{ automodule(pkgname, automodule_options) }} +{% endif %} diff --git a/sphinx/templates/apidoc/toc.rst b/sphinx/templates/apidoc/toc.rst index 291a19402..f0877eeb2 100644 --- a/sphinx/templates/apidoc/toc.rst +++ b/sphinx/templates/apidoc/toc.rst @@ -2,7 +2,6 @@ .. toctree:: :maxdepth: {{ maxdepth }} - {% for docname in docnames %} {{ docname }} {%- endfor %} diff --git a/tests/test_ext_apidoc.py b/tests/test_ext_apidoc.py index 6b04ac3e7..9fefb4ce9 100644 --- a/tests/test_ext_apidoc.py +++ b/tests/test_ext_apidoc.py @@ -446,3 +446,169 @@ def test_module_file_noheadings(tempdir): " :members:\n" " :undoc-members:\n" " :show-inheritance:\n") + + +def test_package_file(tempdir): + outdir = path(tempdir) + (outdir / 'testpkg').makedirs() + (outdir / 'testpkg' / '__init__.py').write_text('') + (outdir / 'testpkg' / 'example.py').write_text('') + (outdir / 'testpkg' / 'subpkg').makedirs() + (outdir / 'testpkg' / 'subpkg' / '__init__.py').write_text('') + apidoc_main(['-o', tempdir, tempdir / 'testpkg']) + assert (outdir / 'testpkg.rst').exists() + assert (outdir / 'testpkg.subpkg.rst').exists() + + content = (outdir / 'testpkg.rst').text() + assert content == ("testpkg package\n" + "===============\n" + "\n" + "Subpackages\n" + "-----------\n" + "\n" + ".. toctree::\n" + "\n" + " testpkg.subpkg\n" + "\n" + "Submodules\n" + "----------\n" + "\n" + "testpkg.example module\n" + "----------------------\n" + "\n" + ".. automodule:: testpkg.example\n" + " :members:\n" + " :undoc-members:\n" + " :show-inheritance:\n" + "\n" + "\n" + "Module contents\n" + "---------------\n" + "\n" + ".. automodule:: testpkg\n" + " :members:\n" + " :undoc-members:\n" + " :show-inheritance:\n") + + content = (outdir / 'testpkg.subpkg.rst').text() + assert content == ("testpkg.subpkg package\n" + "======================\n" + "\n" + "Module contents\n" + "---------------\n" + "\n" + ".. automodule:: testpkg.subpkg\n" + " :members:\n" + " :undoc-members:\n" + " :show-inheritance:\n") + + +def test_package_file_separate(tempdir): + outdir = path(tempdir) + (outdir / 'testpkg').makedirs() + (outdir / 'testpkg' / '__init__.py').write_text('') + (outdir / 'testpkg' / 'example.py').write_text('') + apidoc_main(['--separate', '-o', tempdir, tempdir / 'testpkg']) + assert (outdir / 'testpkg.rst').exists() + assert (outdir / 'testpkg.example.rst').exists() + + content = (outdir / 'testpkg.rst').text() + assert content == ("testpkg package\n" + "===============\n" + "\n" + "Submodules\n" + "----------\n" + "\n" + ".. toctree::\n" + "\n" + " testpkg.example\n" + "\n" + "Module contents\n" + "---------------\n" + "\n" + ".. automodule:: testpkg\n" + " :members:\n" + " :undoc-members:\n" + " :show-inheritance:\n") + + content = (outdir / 'testpkg.example.rst').text() + assert content == ("testpkg.example module\n" + "======================\n" + "\n" + ".. automodule:: testpkg.example\n" + " :members:\n" + " :undoc-members:\n" + " :show-inheritance:\n") + + +def test_package_file_module_first(tempdir): + outdir = path(tempdir) + (outdir / 'testpkg').makedirs() + (outdir / 'testpkg' / '__init__.py').write_text('') + (outdir / 'testpkg' / 'example.py').write_text('') + apidoc_main(['--module-first', '-o', tempdir, tempdir]) + + content = (outdir / 'testpkg.rst').text() + assert content == ("testpkg package\n" + "===============\n" + "\n" + ".. automodule:: testpkg\n" + " :members:\n" + " :undoc-members:\n" + " :show-inheritance:\n" + "\n" + "Submodules\n" + "----------\n" + "\n" + "testpkg.example module\n" + "----------------------\n" + "\n" + ".. automodule:: testpkg.example\n" + " :members:\n" + " :undoc-members:\n" + " :show-inheritance:\n" + "\n") + + +def test_package_file_without_submodules(tempdir): + outdir = path(tempdir) + (outdir / 'testpkg').makedirs() + (outdir / 'testpkg' / '__init__.py').write_text('') + apidoc_main(['-o', tempdir, tempdir / 'testpkg']) + assert (outdir / 'testpkg.rst').exists() + + content = (outdir / 'testpkg.rst').text() + assert content == ("testpkg package\n" + "===============\n" + "\n" + "Module contents\n" + "---------------\n" + "\n" + ".. automodule:: testpkg\n" + " :members:\n" + " :undoc-members:\n" + " :show-inheritance:\n") + + +def test_namespace_package_file(tempdir): + outdir = path(tempdir) + (outdir / 'testpkg').makedirs() + (outdir / 'testpkg' / 'example.py').write_text('') + apidoc_main(['--implicit-namespace', '-o', tempdir, tempdir / 'testpkg']) + assert (outdir / 'testpkg.rst').exists() + + content = (outdir / 'testpkg.rst').text() + assert content == ("testpkg namespace\n" + "=================\n" + "\n" + "Submodules\n" + "----------\n" + "\n" + "testpkg.example module\n" + "----------------------\n" + "\n" + ".. automodule:: testpkg.example\n" + " :members:\n" + " :undoc-members:\n" + " :show-inheritance:\n" + "\n")