From ff8d35d5a1b2a74b42ddf8f42797ffe1a5eb132a Mon Sep 17 00:00:00 2001 From: Erik Sundell Date: Sun, 11 Dec 2022 00:17:51 +0100 Subject: [PATCH 01/12] Update MANIFEST.in to reflect single file module --- MANIFEST.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MANIFEST.in b/MANIFEST.in index 9187fe8..9a338fd 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,5 +1,5 @@ include MANIFEST.in -recursive-include autodoc_traits * +include autodoc_traits.py include LICENSE include *.md From bce4a7573da2696b133ca08cceef13f7c1c64a68 Mon Sep 17 00:00:00 2001 From: Erik Sundell Date: Sun, 11 Dec 2022 00:17:26 +0100 Subject: [PATCH 02/12] Update .gitignore --- .gitignore | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 66 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 894a44c..94dbd57 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,10 @@ +# Manually added parts to .gitignore +# ---------------------------------- +# + +# Python .gitignore from https://github.com/github/gitignore/blob/HEAD/Python.gitignore +# ------------------------------------------------------------------------------------- +# # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] @@ -20,6 +27,7 @@ parts/ sdist/ var/ wheels/ +share/python-wheels/ *.egg-info/ .installed.cfg *.egg @@ -38,14 +46,17 @@ pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ +.nox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover +*.py,cover .hypothesis/ .pytest_cache/ +cover/ # Translations *.mo @@ -55,6 +66,7 @@ coverage.xml *.log local_settings.py db.sqlite3 +db.sqlite3-journal # Flask stuff: instance/ @@ -67,16 +79,49 @@ instance/ docs/_build/ # PyBuilder +.pybuilder/ target/ # Jupyter Notebook .ipynb_checkpoints -# pyenv -.python-version +# IPython +profile_default/ +ipython_config.py -# celery beat schedule file +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff celerybeat-schedule +celerybeat.pid # SageMath parsed files *.sage.py @@ -102,3 +147,21 @@ venv.bak/ # mypy .mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ From 4bfee3d0fc090dcf6b81c1d6830fa44c56f080e7 Mon Sep 17 00:00:00 2001 From: Erik Sundell Date: Sun, 11 Dec 2022 01:41:50 +0100 Subject: [PATCH 03/12] docs: fix incorrect description in README.md --- README.md | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 6123dc4..284dcff 100644 --- a/README.md +++ b/README.md @@ -5,19 +5,21 @@ [![Discourse](https://img.shields.io/badge/help_forum-discourse-blue?logo=discourse)](https://discourse.jupyter.org/c/jupyterhub) [![Gitter](https://img.shields.io/badge/social_chat-gitter-blue?logo=gitter)](https://gitter.im/jupyterhub/jupyterhub) -`autodoc-traits` is a Sphinx extension that influences -[`sphinx.ext.autodoc`][]'s provided [Sphinx directives][], specifically -[`autoclass`][] and [`autoattribute`][], to better document classes with -[Traitlets][] based configuration. - -The `autoclass` directive is updated to document class attributes inheriting -from [`traitlets.TraitType`][] by default. The `autoattribute` directive is -updated to provide a header looking like `default_url c.KubeSpawner.default_url -= Unicode('')`. - -The extension also provides the `autoconfigurable` directive mapping to the -`autoclass` directive, and the `autotrait` directive mapping to the -`autoattributes` directive. +`autodoc-traits` is a Sphinx extension that builds on [`sphinx.ext.autodoc`][] +to better document classes with [Traitlets][] based configuration. +`autodoc-traits` provides the [Sphinx directives][] `autoconfigurable` (use with +classes) and `autotrait` (use with the traitlets based configuration options). + +The `sphinx.ext.autodoc` provided directive [`automodule`][], which can overview +classes, will with `autodoc-traits` enabled use `autoconfigurable` over +[`autoclass`][] for classes has trait based configuration. Similarly, the +`sphinx.ext.autodoc` provided `autoclass` directive will use `autotrait` over +[`autoattribute`][] if configured to present the traitlets attributes normally +not presented. + +The `autoattribute` directive will provide a header looking like `trait +c.TestConfigurable.trait = Bool(False)`, and as docstring it will use the +trait's configured help text. ## How to use it @@ -42,13 +44,20 @@ The extension also provides the `autoconfigurable` directive mapping to the ] ``` -3. Make use of a `sphinx.ext.autodoc` Sphinx directive like `autoclass`, or - `automodule` that make use of `autoclass`: +3. Make use of the `sphinx.ext.autodoc` Sphinx directive like `automodule` that + document classes, the `autodoc_traits` provided `autoconfigurable` that + documents traitlets configurable classes, or the `autodoc_traits` provided + `autotrait` that documents individual traitlets configuration options: From a .rst document: ```rst - .. autoclass:: KubeSpawner + .. automodule:: test_module + :members: + + .. autoconfigurable:: test_module.TestConfigurable + + .. autotrait:: test_module.TestConfigurable.trait ``` ## Use with MyST Parser @@ -60,7 +69,7 @@ From a .md document, with `myst-parser`: ````markdown ```{eval-rst} -.. autoclass:: KubeSpawner +.. autoconfigurable:: test_module.TestConfigurable ``` ```` From be97348319b2962a08aec48e13669664b5d70459 Mon Sep 17 00:00:00 2001 From: Erik Sundell Date: Sun, 11 Dec 2022 01:46:39 +0100 Subject: [PATCH 04/12] maint: add tests --- .github/workflows/test.yaml | 61 ++++++++++ pyproject.toml | 8 ++ tests/README.md | 30 +++++ tests/conftest.py | 80 ++++++++++++ tests/docs/source/autoclass/members.rst | 11 ++ tests/docs/source/autoclass/undoc_members.rst | 11 ++ .../autoconfigurable/exclude_members.rst | 14 +++ .../autoconfigurable/inherited_members.rst | 15 +++ .../docs/source/autoconfigurable/members.rst | 11 ++ .../source/autoconfigurable/no_members.rst | 10 ++ .../non_configurable_raises_error.rst | 11 ++ .../autoconfigurable/specified_members.rst | 15 +++ tests/docs/source/automodule/members.rst | 9 ++ tests/docs/source/autotrait/help.rst | 7 ++ tests/docs/source/autotrait/noconfig.rst | 8 ++ tests/docs/source/autotrait/nohelp.rst | 8 ++ .../autotrait/non_trait_raises_error.rst | 11 ++ tests/docs/source/conf.py | 14 +++ tests/docs/source/index.rst | 9 ++ tests/docs/test_module.py | 83 +++++++++++++ tests/test_autodoc_traits.py | 115 ++++++++++++++++++ tests/test_fixtures.py | 30 +++++ 22 files changed, 571 insertions(+) create mode 100644 .github/workflows/test.yaml create mode 100644 tests/README.md create mode 100644 tests/conftest.py create mode 100644 tests/docs/source/autoclass/members.rst create mode 100644 tests/docs/source/autoclass/undoc_members.rst create mode 100644 tests/docs/source/autoconfigurable/exclude_members.rst create mode 100644 tests/docs/source/autoconfigurable/inherited_members.rst create mode 100644 tests/docs/source/autoconfigurable/members.rst create mode 100644 tests/docs/source/autoconfigurable/no_members.rst create mode 100644 tests/docs/source/autoconfigurable/non_configurable_raises_error.rst create mode 100644 tests/docs/source/autoconfigurable/specified_members.rst create mode 100644 tests/docs/source/automodule/members.rst create mode 100644 tests/docs/source/autotrait/help.rst create mode 100644 tests/docs/source/autotrait/noconfig.rst create mode 100644 tests/docs/source/autotrait/nohelp.rst create mode 100644 tests/docs/source/autotrait/non_trait_raises_error.rst create mode 100644 tests/docs/source/conf.py create mode 100644 tests/docs/source/index.rst create mode 100644 tests/docs/test_module.py create mode 100644 tests/test_autodoc_traits.py create mode 100644 tests/test_fixtures.py diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 0000000..ac660d7 --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,61 @@ +# This is a GitHub workflow defining a set of jobs with a set of steps. +# ref: https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions +# +name: Test + +on: + pull_request: + paths-ignore: + - "**.md" + - ".github/workflows/*" + - "!.github/workflows/test.yaml" + push: + paths-ignore: + - "**.md" + - ".github/workflows/*" + - "!.github/workflows/test.yaml" + branches-ignore: + - "dependabot/**" + - "pre-commit-ci-update-config" + tags: + - "**" + workflow_dispatch: + +jobs: + pytest: + runs-on: ubuntu-22.04 + + strategy: + fail-fast: false + matrix: + include: + # NOTE: jinja2<3.1 is added as a workaround to ensure we can test + # against sphinx 2 and 3 that otherwise breaks, see + # https://github.com/sphinx-doc/sphinx/issues/10291#issuecomment-1079709635. + # + - python-version: "3.8" + sphinx-version: "2.*" + traitlets-version: "4.*" + pip-install-addition: "'jinja2<3.1'" + - python-version: "3.9" + sphinx-version: "3.*" + traitlets-version: "4.*" + pip-install-addition: "'jinja2<3.1'" + - python-version: "3.10" + sphinx-version: "4.*" + traitlets-version: "5.*" + pip-install-addition: "" + - python-version: "3.11" + sphinx-version: "5.*" + traitlets-version: "5.*" + pip-install-addition: "" + + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: "${{ matrix.python-version }}" + + - run: pip install ".[test]" "sphinx==${{ matrix.sphinx-version }}" "traitlets==${{ matrix.traitlets-version }}" ${{ matrix.pip-install-addition }} + + - run: pytest diff --git a/pyproject.toml b/pyproject.toml index afbf576..10d021b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -81,6 +81,14 @@ target_version = [ ] +# pytest is used for running Python based tests +# +# ref: https://docs.pytest.org/en/stable/ +# +[tool.pytest.ini_options] +addopts = "--verbose --color=yes --durations=10 --ignore=tests/docs/test_module.py" + + # tbump is used to simplify and standardize the release process when updating # the version, making a git commit and tag, and pushing changes. # diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 0000000..322cda6 --- /dev/null +++ b/tests/README.md @@ -0,0 +1,30 @@ +# About the test suite + +We use `pytest` to run `sphinx-build` against the Sphinx project in the `docs/` +folder. Besides concluding that the build succeeds without warnings, we look for +strings in the .html files to estimate if it has rendered as it should or not. + +The test .rst documents include some descriptions about whats tested. + +## Inspecting the test documentation + +`sphinx-autobuild` is convenient to use when looking to inspect or expand the +content in the docs/ folder, which rendered is whats inspected by the test +suite. + +```shell +pip install sphinx-autobuild + +cd docs +# --watch: we watch python files influencing the built documentation +# --pre-build: we rebuild from scratch as changes to the python files +# can influence all built html +sphinx-autobuild \ + --open-browser \ + --watch="test_module.py" \ + --watch="../../autodoc_traits.py" \ + --pre-build="rm -rf build" \ + --ignore + source \ + build +``` diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..875f81d --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,80 @@ +import glob +import os +import shutil +import sys +import tempfile +from functools import partial + +import pytest + +if sys.version_info >= (3, 8): + copy_tree = partial(shutil.copytree, dirs_exist_ok=True) +else: + # use deprecated distutils on Python < 3.8 + # when shutil.copytree added dirs_exist_ok support + from distutils.dir_util import copy_tree + + +@pytest.fixture +def temp_docs_dir(): + """ + This fixture provides a temporary directory with files copied from the + tests/docs directory. + """ + with tempfile.TemporaryDirectory() as temp_dir: + tests_dir = os.path.abspath(os.path.dirname(__file__)) + test_docs_dir = os.path.join(tests_dir, "docs") + + # populate content + copy_tree(test_docs_dir, temp_dir) + + yield temp_dir + + +@pytest.fixture +def get_glob_filtered_temp_docs_dir(temp_docs_dir): + """ + This fixture provides function that returns a path to a temp docs directory + based on tests/docs, but filtered to only retain .rst files globbed by + provide glob_patterns relative to the source/ directory. + + Note that to test specific documents, including those that are expected to + raise errors, we could use the Sphinx configuration "include_patterns". + Sadly its only available in Sphinx 5.1+ so it would constrain us to test + against Sphinx 5.1+. Due to that, we rely on this fixture instead. + """ + + def _filter_source_dir_func(glob_patterns): + old_cwd = os.getcwd() + try: + os.chdir(os.path.join(temp_docs_dir, "source")) + source_rst_files = set(glob.glob("**/*.rst", recursive=True)) + files_to_retain = set() + for p in glob_patterns: + files_to_retain = files_to_retain.union( + set(glob.glob(p, recursive=True)) + ) + + if not source_rst_files.intersection(files_to_retain): + print("glob_patterns", glob_patterns) + print("source_rst_files", source_rst_files) + print("files_to_retain", files_to_retain) + raise ValueError( + "provided glob_patterns found no .rst in the source folder to retain!" + ) + + for f in source_rst_files.difference(files_to_retain): + os.remove(f) + + print() + print( + f"Fixture get_glob_filtered_temp_docs_dir provided the directory {temp_docs_dir}:" + ) + for f in glob.glob("**/*.rst", recursive=True): + print(f"- {f}") + print() + finally: + os.chdir(old_cwd) + return temp_docs_dir + + yield _filter_source_dir_func diff --git a/tests/docs/source/autoclass/members.rst b/tests/docs/source/autoclass/members.rst new file mode 100644 index 0000000..6ccb1c3 --- /dev/null +++ b/tests/docs/source/autoclass/members.rst @@ -0,0 +1,11 @@ +autoclass - members +=================== + +The ``members`` option without specified members should present all class +members. + +In this test expect no trait members to show up. + +.. autoclass:: test_module.TestConfigurable + :noindex: + :members: diff --git a/tests/docs/source/autoclass/undoc_members.rst b/tests/docs/source/autoclass/undoc_members.rst new file mode 100644 index 0000000..f9b34b2 --- /dev/null +++ b/tests/docs/source/autoclass/undoc_members.rst @@ -0,0 +1,11 @@ +autoclass - undoc-members +========================= + +The ``members`` and ``undoc-members`` option combined should present all class +members, including the traits. And with autodoc_traits installed, the attributes +should be presented with their help strings as docstrings. + +.. autoclass:: test_module.TestConfigurable + :noindex: + :members: + :undoc-members: diff --git a/tests/docs/source/autoconfigurable/exclude_members.rst b/tests/docs/source/autoconfigurable/exclude_members.rst new file mode 100644 index 0000000..7a2a36b --- /dev/null +++ b/tests/docs/source/autoconfigurable/exclude_members.rst @@ -0,0 +1,14 @@ +autoconfigurable - exclude-members +================================== + +The ``exclude-members`` option should work to exclude specific members, trait +members and and non-traits members alike. + +In this test we provide ``members`` and then exclude the members ``trait`` +and ``method`` by specifying them with ``exclude-members`` that otherwise ought +to show up, and check that they aren't showing up. + +.. autoconfigurable:: test_module.TestConfigurable + :noindex: + :members: + :exclude-members: trait,method diff --git a/tests/docs/source/autoconfigurable/inherited_members.rst b/tests/docs/source/autoconfigurable/inherited_members.rst new file mode 100644 index 0000000..ecda72b --- /dev/null +++ b/tests/docs/source/autoconfigurable/inherited_members.rst @@ -0,0 +1,15 @@ +autoconfigurable - inherited-members +==================================== + +With the ``inherited-members`` option, we expect traits from the superclass +TestConfigurable to show up as well as traits from TestConfigurableSubclass. + +.. note:: + Several members from the ``traitlets.HasTraits`` base class are excluded for + now as they cause the sphinx-build warning of ``Unexpected section title`` in + sphinx 4. + +.. autoconfigurable:: test_module.TestConfigurableSubclass + :noindex: + :inherited-members: + :exclude-members: class_config_section,observe,on_trait_change,trait_defaults,trait_events,trait_values,unobserve diff --git a/tests/docs/source/autoconfigurable/members.rst b/tests/docs/source/autoconfigurable/members.rst new file mode 100644 index 0000000..cc0cf9e --- /dev/null +++ b/tests/docs/source/autoconfigurable/members.rst @@ -0,0 +1,11 @@ +autoconfigurable - members +========================== + +The ``members`` option without specified members should present all class +members. + +In this test expect all trait members to show up. + +.. autoconfigurable:: test_module.TestConfigurable + :noindex: + :members: diff --git a/tests/docs/source/autoconfigurable/no_members.rst b/tests/docs/source/autoconfigurable/no_members.rst new file mode 100644 index 0000000..bc6da4f --- /dev/null +++ b/tests/docs/source/autoconfigurable/no_members.rst @@ -0,0 +1,10 @@ +autoconfigurable - no members +============================= + +Without the ``members`` option, one may expect no members to show up, but we +present them all still, see `Issue27`_. + +.. _Issue27: https://github.com/jupyterhub/autodoc-traits/issues/27 + +.. autoconfigurable:: test_module.TestConfigurable + :noindex: diff --git a/tests/docs/source/autoconfigurable/non_configurable_raises_error.rst b/tests/docs/source/autoconfigurable/non_configurable_raises_error.rst new file mode 100644 index 0000000..782f9aa --- /dev/null +++ b/tests/docs/source/autoconfigurable/non_configurable_raises_error.rst @@ -0,0 +1,11 @@ +autoconfigurable - non configurable class +========================================= + +Test that we error when used on non-configurable classes. + +.. note:: + This file is targeted by ``exclude_patterns`` in ``source/conf.py`` + to avoid failing unless we want to explicitly test such failure. + +.. autoconfigurable:: test_module.TestNonConfigurable + :noindex: diff --git a/tests/docs/source/autoconfigurable/specified_members.rst b/tests/docs/source/autoconfigurable/specified_members.rst new file mode 100644 index 0000000..eba421f --- /dev/null +++ b/tests/docs/source/autoconfigurable/specified_members.rst @@ -0,0 +1,15 @@ +autoconfigurable - specified members +==================================== + +The ``members`` option with specified members should only present the specified +members. + +In this test we list the member ``method`` and ``trait_nohelp``. One may expect +no members besides these to show up, but we present them and all trait members +still, see `Issue27`_. + +.. _Issue27: https://github.com/jupyterhub/autodoc-traits/issues/27 + +.. autoconfigurable:: test_module.TestConfigurable + :noindex: + :members: method,trait_nohelp diff --git a/tests/docs/source/automodule/members.rst b/tests/docs/source/automodule/members.rst new file mode 100644 index 0000000..1c7f485 --- /dev/null +++ b/tests/docs/source/automodule/members.rst @@ -0,0 +1,9 @@ +automodule - members +==================== + +Test that we can present a module with a mix of traitlets configurable member +classes and normal classes, and they all show up. + +.. automodule:: test_module + :noindex: + :members: diff --git a/tests/docs/source/autotrait/help.rst b/tests/docs/source/autotrait/help.rst new file mode 100644 index 0000000..b5e191e --- /dev/null +++ b/tests/docs/source/autotrait/help.rst @@ -0,0 +1,7 @@ +autotrait - help +================ + +Test that we present the trait's provided ``help``. + +.. autotrait:: test_module.TestConfigurable.trait + :noindex: diff --git a/tests/docs/source/autotrait/noconfig.rst b/tests/docs/source/autotrait/noconfig.rst new file mode 100644 index 0000000..f946551 --- /dev/null +++ b/tests/docs/source/autotrait/noconfig.rst @@ -0,0 +1,8 @@ +autotrait - no config +===================== + +Test that we still present a trait without ``config=True`` if directly requested +via the ``autotrait`` directive. + +.. autotrait:: test_module.TestConfigurable.trait_noconfig + :noindex: diff --git a/tests/docs/source/autotrait/nohelp.rst b/tests/docs/source/autotrait/nohelp.rst new file mode 100644 index 0000000..8cab158 --- /dev/null +++ b/tests/docs/source/autotrait/nohelp.rst @@ -0,0 +1,8 @@ +autotrait - no help +=================== + +Test that we fall back to present the trait's header even if it lacks a ``help`` +string. + +.. autotrait:: test_module.TestConfigurable.trait_nohelp + :noindex: diff --git a/tests/docs/source/autotrait/non_trait_raises_error.rst b/tests/docs/source/autotrait/non_trait_raises_error.rst new file mode 100644 index 0000000..76f4645 --- /dev/null +++ b/tests/docs/source/autotrait/non_trait_raises_error.rst @@ -0,0 +1,11 @@ +autotrait - non trait attribute +=============================== + +Test that we error when used on non-trait attributes. + +.. note:: + This file is targeted by ``exclude_patterns`` in ``source/conf.py`` + to avoid failing unless we want to explicitly test such failure. + +.. autotrait:: test_module.TestConfigurable.non_trait + :noindex: diff --git a/tests/docs/source/conf.py b/tests/docs/source/conf.py new file mode 100644 index 0000000..7a297e4 --- /dev/null +++ b/tests/docs/source/conf.py @@ -0,0 +1,14 @@ +import os +import sys + +project = "autodoc_traits tests" +extensions = ["autodoc_traits"] + +# ensure test_module.py is on path +tests_dir = os.path.join(os.path.dirname(__file__), "..") +tests_dir = os.path.abspath(tests_dir) +sys.path.insert(0, tests_dir) + +# Don't parse .rst documents expected to raise an error unless we want to test +# that specifically. +exclude_patterns = ["**/*_raises_error.rst"] diff --git a/tests/docs/source/index.rst b/tests/docs/source/index.rst new file mode 100644 index 0000000..8afbc9b --- /dev/null +++ b/tests/docs/source/index.rst @@ -0,0 +1,9 @@ +autodoc_traits tests +==================== + +.. toctree ref: https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-toctree +.. toctree:: + :maxdepth: 2 + :glob: + + */* diff --git a/tests/docs/test_module.py b/tests/docs/test_module.py new file mode 100644 index 0000000..38f5053 --- /dev/null +++ b/tests/docs/test_module.py @@ -0,0 +1,83 @@ +""" +test_module docstring + +This module provides a module and classes with and without traits to test +autodoc_traits against. It does not contain tests. +""" + +from traitlets import Bool +from traitlets.config.configurable import Configurable + + +class TestConfigurable(Configurable): + """TestConfigurable docstring""" + + non_trait = False + + @property + def non_trait_property(self): + """non_trait_property docstring""" + + trait = Bool( + help="""trait help text""", + config=True, + ) + trait_nohelp = Bool( + config=True, + ) + trait_noconfig = Bool( + help="""trait_noconfig help text""", + ) + + def method(self): + """method docstring""" + + +class TestConfigurableSubclass(TestConfigurable): + """TestConfigurableSubclass docstring""" + + subclass_non_trait = False + + @property + def subclass_non_trait_property(self): + """subclass_non_trait_property docstring""" + + subclass_trait = Bool( + config=True, + help="""subclass_trait help text""", + ) + subclass_trait_nohelp = Bool( + config=True, + ) + subclass_trait_noconfig = Bool( + help="""subclass_trait_noconfig help text""", + ) + + def subclass_method(self): + """subclass_method docstring""" + + +class TestNonConfigurable: + """TestNonConfigurable docstring""" + + non_trait = False + + @property + def non_trait_property(self): + """non_trait_property docstring""" + + def method(self): + """method docstring""" + + +class TestNonConfigurableSubclass(TestNonConfigurable): + """TestNonConfigurableSubclass docstring""" + + non_trait = False + + @property + def subclass_non_trait_property(self): + """subclass_non_trait_property docstring""" + + def subclass_method(self): + """subclass_method docstring""" diff --git a/tests/test_autodoc_traits.py b/tests/test_autodoc_traits.py new file mode 100644 index 0000000..f0bc976 --- /dev/null +++ b/tests/test_autodoc_traits.py @@ -0,0 +1,115 @@ +import os +import subprocess + +import pytest + + +def test_sphinx_build_all_docs(temp_docs_dir, monkeypatch): + """ + Tests that the docs folder builds without warnings. + """ + monkeypatch.chdir(temp_docs_dir) + + subprocess.run( + ["sphinx-build", "--color", "-W", "--keep-going", "source", "build"], + check=True, + text=True, + ) + + +@pytest.mark.parametrize( + "rst_file_to_test, strings_in_html, strings_not_in_html", + [ + ("autoclass/members.rst", [], ["c.TestConfigurable.trait"]), + ("autoclass/undoc_members.rst", ["c.TestConfigurable.trait"], []), + ( + "autoconfigurable/exclude_members.rst", + ["c.TestConfigurable.trait_nohelp"], + ["trait help text", "method docstring"], + ), + ( + "autoconfigurable/inherited_members.rst", + [ + "c.TestConfigurableSubclass.trait", + "c.TestConfigurableSubclass.subclass_trait", + "method docstring", + ], + [], + ), + ( + "autoconfigurable/members.rst", + ["trait help text", "method docstring"], + ["trait_noconfig help text"], + ), + ( + "autoconfigurable/no_members.rst", + ["trait help text"], + ["trait_noconfig help text", "method docstring"], + ), + ("autoconfigurable/non_configurable_raises_error.rst", [], []), + ( + "autoconfigurable/specified_members.rst", + ["method docstring", "c.TestConfigurable.trait_nohelp", "trait help text"], + [], + ), + ( + "automodule/members.rst", + [ + "test_module docstring", + "TestConfigurable docstring", + "TestConfigurableSubclass docstring", + "TestNonConfigurable docstring", + "TestNonConfigurableSubclass docstring", + ], + [], + ), + ("autotrait/help.rst", ["c.TestConfigurable.trait", "trait help text"], []), + ("autotrait/noconfig.rst", ["c.TestConfigurable.trait_noconfig"], []), + ("autotrait/nohelp.rst", ["c.TestConfigurable.trait_nohelp"], []), + ("autotrait/non_trait_raises_error.rst", [], []), + ], +) +def test_sphinx_build_file( + get_glob_filtered_temp_docs_dir, + monkeypatch, + rst_file_to_test, + strings_in_html, + strings_not_in_html, +): + """ + Tests that individual .rst documents in the docs folder builds without + warnings, emits .html with certain strings, and emits .html without certain + strings. + """ + temp_docs_dir = get_glob_filtered_temp_docs_dir(["index.rst", rst_file_to_test]) + monkeypatch.chdir(temp_docs_dir) + + p = subprocess.run( + [ + "sphinx-build", + "--color", + "-W", + "--keep-going", + "-D", + "exclude_patterns=", + "source", + "build", + ], + text=True, + ) + if "raises_error" in rst_file_to_test: + assert p.returncode > 0 + return + assert p.returncode == 0 + + html_file_to_inspect = os.path.join( + "build", rst_file_to_test.replace(".rst", ".html") + ) + with open(html_file_to_inspect) as f: + html = f.read() + + for s in strings_in_html: + assert s in html + + for s in strings_not_in_html: + assert s not in html diff --git a/tests/test_fixtures.py b/tests/test_fixtures.py new file mode 100644 index 0000000..daf1618 --- /dev/null +++ b/tests/test_fixtures.py @@ -0,0 +1,30 @@ +import os + + +def test_temp_docs_dir(temp_docs_dir): + """ + Verify that we get a reference to a temporary directory with source/conf.py + in it. + """ + assert os.path.isdir(os.path.join(temp_docs_dir, "source")) + assert os.path.isfile(os.path.join(temp_docs_dir, "source/conf.py")) + + +def test_get_glob_filtered_temp_docs_dir(get_glob_filtered_temp_docs_dir): + """ + Verify that we get a reference to a temporary directory with: + - source/conf.py + - index.rst files retained + - filtered .rst files removed + - non-filtered .rst files retained + """ + temp_docs_dir = get_glob_filtered_temp_docs_dir( + ["index.rst", "automodule/members.rst"] + ) + assert os.path.isdir(os.path.join(temp_docs_dir, "source")) + assert os.path.isfile(os.path.join(temp_docs_dir, "source/conf.py")) + assert os.path.isfile(os.path.join(temp_docs_dir, "source/index.rst")) + assert os.path.isfile(os.path.join(temp_docs_dir, "source/automodule/members.rst")) + assert not os.path.isfile( + os.path.join(temp_docs_dir, "source/autoclass/members.rst") + ) From 9cfdfd8afd213ef93831419e4de64a5a2906ac28 Mon Sep 17 00:00:00 2001 From: Erik Sundell Date: Sun, 11 Dec 2022 01:46:15 +0100 Subject: [PATCH 05/12] maint: make requirements sphinx>=2 traitlets>=4 explicit --- pyproject.toml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 10d021b..f778c39 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,10 +5,7 @@ [project] name = "autodoc-traits" description = "Sphinx extension to autodoc traitlets" -readme = "README.md" -requires-python = ">=3.7" -license = {file = "LICENSE"} -keywords = ["repo2docker", "jupyterhub"] +keywords = ["sphinx", "extension", "autodoc", "traitlets"] authors = [ {name = "Jupyter Development Team", email = "jupyter@googlegroups.com"}, ] @@ -17,11 +14,14 @@ classifiers = [ "Operating System :: OS Independent", "Programming Language :: Python :: 3", ] +readme = "README.md" +license = {file = "LICENSE"} +dynamic = ["version"] +requires-python = ">=3.7" dependencies = [ - "sphinx", - "traitlets", + "sphinx>=2", + "traitlets>=4", ] -dynamic = ["version"] [project.optional-dependencies] test = [ @@ -46,6 +46,7 @@ build-backend = "hatchling.build" [tool.hatch.version] path = "autodoc_traits.py" + # autoflake is used for autoformatting Python code # # ref: https://github.com/PyCQA/autoflake#readme @@ -56,6 +57,7 @@ remove-all-unused-imports = true remove-duplicate-keys = true #remove-unused-variables = true + # isort is used for autoformatting Python code # # ref: https://pycqa.github.io/isort/ From 5747e4bf06abcba24ab26b92a51ac1b06421530d Mon Sep 17 00:00:00 2001 From: Erik Sundell Date: Sun, 11 Dec 2022 01:47:19 +0100 Subject: [PATCH 06/12] maint: refresh autodoc_traits.py for long term maintenance --- autodoc_traits.py | 192 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 152 insertions(+), 40 deletions(-) diff --git a/autodoc_traits.py b/autodoc_traits.py index 7f808d4..82001f8 100644 --- a/autodoc_traits.py +++ b/autodoc_traits.py @@ -14,70 +14,182 @@ class ConfigurableDocumenter(ClassDocumenter): - """Specialized Documenter subclass for traits with config=True""" + """ + Specialized Documenter subclass for traits with config=True + + Links to relevant source code in sphinx.ext.autodoc: + - Documenter: https://github.com/sphinx-doc/sphinx/blob/v6.0.0b2/sphinx/ext/autodoc/__init__.py#L270-L299 + - ClassDocumenter: https://github.com/sphinx-doc/sphinx/blob/v6.0.0b2/sphinx/ext/autodoc/__init__.py#L1395-L1408 + """ + # objtype: The suffix to "auto" for a Sphinx directive name that will be + # created (and the default value for "directivetype"). objtype = "configurable" + + # directivetype: Clarifies that this Documenter class could be capable of + # documenting this kind of members of other parent like + # Documenter classes. directivetype = "class" + # priority: Declares this class' priority for use if multiple classes + # "can_document_member" of the "directivetype". This is only + # relevant if a parent class has a member. + # + # ConfigurableDocumenter can document traitlets configurable + # classes, so a parent like Documenter class can be the + # ModuleDocumenter. + # + priority = 100 # higher priority than ClassDocumenter's 10 + + @classmethod + def can_document_member(cls, member, membername, isattr, parent): + """ + If the member is a class with traitlets then we can document it, and we + will document it thanks to a high priority. + + This function is not considered if the ``autoconfigurable`` or + ``autoclass`` directives are called directly. can_document_member is + only used by other parent like Documenter classes having members of this + class' configured "documentertype" - such as ModuleDocumenter. + """ + return isinstance(member, MetaHasTraits) + def get_object_members(self, want_all): - """Add traits with .tag(config=True) to members list""" + """ + This get_object_members function override is a hack, manipulating + __doc__ values of trait configuration objects, but otherwise behaving + exactly like the super class get_object_members. + + It sets truthy strings to the class' traits __doc__ attributes. They + will otherwise be filtered out by the Documenter.filter_members + function, unless ``undoc-members`` option is set. + + Links to relevant source code in sphinx.ext.autodoc: + - Documenter.filter_members: https://github.com/sphinx-doc/sphinx/blob/v6.0.0b2/sphinx/ext/autodoc/__init__.py#L616-L769 + - Documenter.get_object_members: https://github.com/sphinx-doc/sphinx/blob/v6.0.0b2/sphinx/ext/autodoc/__init__.py#L607-L614 + - ClassDocumenter.get_object_members: https://github.com/sphinx-doc/sphinx/blob/v6.0.0b2/sphinx/ext/autodoc/__init__.py#L1656-L1674 + - traitlets.HasTraits.class_traits: https://github.com/ipython/traitlets/blob/v5.6.0/traitlets/traitlets.py#L1620-L1652 + """ check, members = super().get_object_members(want_all) - if not isinstance(self.object, MetaHasTraits): - return check, members - # The directive can have been passed a inherited-members option to - # influence it, and we rely on two traitlets provided functions for it. + + truthy_string = ( + "A hack is used by autodoc_traits since 1.1.0 for trait " + "configurations, updating trait configuration's __doc__ to this " + "truthy string as required to make sphinx.ext.autodoc behave as " + " wanted." + ) + for trait in self.object.class_traits(config=True).values(): + trait.__doc__ = truthy_string + + # We add all traits, also the inherited, bypassing :members: and + # :inherit-members: options. # - # class_own_traits returns the class own defined traits, while - # class_traits includes super classes' defined traits. + # FIXME: We have been adding the trait_members unconditionally, but + # should we keep doing that? # - # class_traits definition: https://github.com/ipython/traitlets/blob/v5.6.0/traitlets/traitlets.py#L1620-L1652 - # class_own_traits definition: https://github.com/ipython/traitlets/blob/v5.6.0/traitlets/traitlets.py#L1654-L1665 + # See https://github.com/jupyterhub/autodoc-traits/issues/27 # - get_traits = ( - # FIXME: Is this backwards? - # Tracked in https://github.com/jupyterhub/autodoc-traits/issues/19 - # - self.object.class_own_traits - if self.options.inherited_members - else self.object.class_traits - ) - trait_members = [] - for name, trait in sorted(get_traits(config=True).items()): - # put help in __doc__ where autodoc will look for it - trait.__doc__ = trait.help - trait_members.append((name, trait)) - # Remove duplicates between members and trait_members. We - # can't use sets, because not all items are hashable. Modify - # trait_members in place for returning. - for item in members: - if item not in trait_members: - trait_members.append(item) - return check, trait_members + trait_members = self.object.class_traits(config=True).items() + for trait in trait_members: + if trait not in members: + members.append(trait) + + return check, members class TraitDocumenter(AttributeDocumenter): + """ + Links to relevant source code in sphinx.ext.autodoc: + - Documenter: https://github.com/sphinx-doc/sphinx/blob/v6.0.0b2/sphinx/ext/autodoc/__init__.py#L270-L299 + - AttributeDocumenter: https://github.com/sphinx-doc/sphinx/blob/v6.0.0b2/sphinx/ext/autodoc/__init__.py#L2509-L2524 + """ + + # objtype: The suffix to "auto" for a Sphinx directive name that will be + # created (and the default value for "directivetype"). objtype = "trait" + + # directivetype: Clarifies that this Documenter class could be capable of + # documenting this kind of members of other parent like + # Documenter classes. directivetype = "attribute" - member_order = 1 - priority = 100 + + # priority: Declares this class' priority for use if multiple classes + # "can_document_member" of the "directivetype". This is only + # relevant if a parent class has a member. + # + # TraitsDocumenter can document traitlets type attributes, so the + # parent like Documenter class is typically ClassDocumenter, but + # can also be the ConfigurableDocumenter. + # + priority = 100 # AttributeDocumenter has 10 + + # order: order if the autodoc_member_order in conf.py is set to "groupwise", + # by default it is "alphabetical", where lowest order comes first. + # Since traits are relevant configuration, we declare the lowest + # order for high visual priority. + member_order = 0 # AttributeDocumenter has 60 @classmethod def can_document_member(cls, member, membername, isattr, parent): + """ + If the member is a traitlets type we can document it, and we will + document it thanks to a high priority. + + This function is not considered if the ``autotrait`` or + ``autoattribute`` directives are called directly. can_document_member is + only used by other parent like Documenter classes having members of this + class' configured "documentertype" - such as ClassDocumenter. + """ return isinstance(member, TraitType) def add_directive_header(self, sig): - default = self.object.get_default_value() - if default is Undefined: - default_s = "" + """ + add_directive_header is called by the base class' Documenter.generate + method. It is provided by both AttributeDocumenter and Documenter. This + override retains use of the super classes implementations, but influence + them. + + For functions, the directive header describes the function's call + signature, but not the function's docstring. + + Similarly, we look to emit rST to describe how the traitlets + configuration option can be configured and its default value. + + - Documenter.generate: https://github.com/sphinx-doc/sphinx/blob/v6.0.0b2/sphinx/ext/autodoc/__init__.py#L918-L929 + - AttributeDocumenter.add_directive_header: https://github.com/sphinx-doc/sphinx/blob/v6.0.0b2/sphinx/ext/autodoc/__init__.py#L2592-L2620 + - Documenter.add_directive_header: https://github.com/sphinx-doc/sphinx/blob/v6.0.0b2/sphinx/ext/autodoc/__init__.py#L504-L524 + """ + default_value = self.object.get_default_value() + if default_value is Undefined: + default_value = "" else: - default_s = repr(default) - self.options.annotation = "c.{name} = {trait}({default})".format( - name=self.format_name(), - trait=self.object.__class__.__name__, - default=default_s, + default_value = repr(default_value) + + self.options.annotation = "c.{name} = {traitlets_type}({default_value})".format( + name=self.format_name(), # TestConfigurator.trait + traitlets_type=self.object.__class__.__name__, # Bool + default_value=default_value, ) + super().add_directive_header(sig) + def get_doc(self): + """ + get_doc (get docstring) is called by add_content, which is called by + generate. We override it to not unconditionally provide the docstring of + the traitlets type, but instead provide the traits help text if its + available. + + Links to relevant source code in sphinx.ext.autodoc: + - Documenter.generate: https://github.com/sphinx-doc/sphinx/blob/v6.0.0b2/sphinx/ext/autodoc/__init__.py#L918-L929 + - AttributeDocumenter.add_content: https://github.com/sphinx-doc/sphinx/blob/v6.0.0b2/sphinx/ext/autodoc/__init__.py#L2655-L2663 + - Documenter.add_content: https://github.com/sphinx-doc/sphinx/blob/v6.0.0b2/sphinx/ext/autodoc/__init__.py#L568-L605 + - AttributeDocumenter.get_doc: https://github.com/sphinx-doc/sphinx/blob/v6.0.0b2/sphinx/ext/autodoc/__init__.py#L2639-L2653 + """ + if isinstance(self.object.help, str): + return [[self.object.help]] + return super().get_doc() + def setup(app): """ From d3210e58b7a744cc3e604580d431a86427d4e0e1 Mon Sep 17 00:00:00 2001 From: Erik Sundell Date: Wed, 14 Dec 2022 15:20:42 +0100 Subject: [PATCH 07/12] maint: add napoleon extension to test config to avoid warnings Co-authored-by: Min RK --- tests/docs/source/conf.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/docs/source/conf.py b/tests/docs/source/conf.py index 7a297e4..4151f3d 100644 --- a/tests/docs/source/conf.py +++ b/tests/docs/source/conf.py @@ -2,7 +2,12 @@ import sys project = "autodoc_traits tests" -extensions = ["autodoc_traits"] +extensions = [ + "autodoc_traits", + # sphinx.ext.napoleon is added to avoid warnings if testing with :inherited-members:` + # where the traitlets base classes members has numpy or google-format docstrings + "sphinx.ext.napoleon" +] # ensure test_module.py is on path tests_dir = os.path.join(os.path.dirname(__file__), "..") From 49ef96d136dd83a3e2da7622609b917354e35a84 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 14 Dec 2022 14:20:59 +0000 Subject: [PATCH 08/12] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/docs/source/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/docs/source/conf.py b/tests/docs/source/conf.py index 4151f3d..83d0a1c 100644 --- a/tests/docs/source/conf.py +++ b/tests/docs/source/conf.py @@ -6,7 +6,7 @@ "autodoc_traits", # sphinx.ext.napoleon is added to avoid warnings if testing with :inherited-members:` # where the traitlets base classes members has numpy or google-format docstrings - "sphinx.ext.napoleon" + "sphinx.ext.napoleon", ] # ensure test_module.py is on path From cf502d75fede257f4f08524d99169cefd23ac4b0 Mon Sep 17 00:00:00 2001 From: Erik Sundell Date: Wed, 14 Dec 2022 15:11:43 +0100 Subject: [PATCH 09/12] refactor: rename test_module.py and classes to sample_module.py etc --- README.md | 10 +++---- pyproject.toml | 2 +- .../docs/{test_module.py => sample_module.py} | 18 ++++++------ tests/docs/source/autoclass/members.rst | 2 +- tests/docs/source/autoclass/undoc_members.rst | 2 +- .../autoconfigurable/exclude_members.rst | 2 +- .../autoconfigurable/inherited_members.rst | 4 +-- .../docs/source/autoconfigurable/members.rst | 2 +- .../source/autoconfigurable/no_members.rst | 2 +- .../non_configurable_raises_error.rst | 2 +- .../autoconfigurable/specified_members.rst | 2 +- tests/docs/source/automodule/members.rst | 2 +- tests/docs/source/autotrait/help.rst | 2 +- tests/docs/source/autotrait/noconfig.rst | 2 +- tests/docs/source/autotrait/nohelp.rst | 2 +- .../autotrait/non_trait_raises_error.rst | 2 +- tests/docs/source/conf.py | 2 +- tests/test_autodoc_traits.py | 28 +++++++++---------- 18 files changed, 44 insertions(+), 44 deletions(-) rename tests/docs/{test_module.py => sample_module.py} (79%) diff --git a/README.md b/README.md index 284dcff..73fb3ef 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ classes, will with `autodoc-traits` enabled use `autoconfigurable` over not presented. The `autoattribute` directive will provide a header looking like `trait -c.TestConfigurable.trait = Bool(False)`, and as docstring it will use the +c.SampleConfigurable.trait = Bool(False)`, and as docstring it will use the trait's configured help text. ## How to use it @@ -52,12 +52,12 @@ trait's configured help text. From a .rst document: ```rst - .. automodule:: test_module + .. automodule:: sample_module :members: - .. autoconfigurable:: test_module.TestConfigurable + .. autoconfigurable:: sample_module.SampleConfigurable - .. autotrait:: test_module.TestConfigurable.trait + .. autotrait:: sample_module.SampleConfigurable.trait ``` ## Use with MyST Parser @@ -69,7 +69,7 @@ From a .md document, with `myst-parser`: ````markdown ```{eval-rst} -.. autoconfigurable:: test_module.TestConfigurable +.. autoconfigurable:: sample_module.SampleConfigurable ``` ```` diff --git a/pyproject.toml b/pyproject.toml index f778c39..e5d3f10 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -88,7 +88,7 @@ target_version = [ # ref: https://docs.pytest.org/en/stable/ # [tool.pytest.ini_options] -addopts = "--verbose --color=yes --durations=10 --ignore=tests/docs/test_module.py" +addopts = "--verbose --color=yes --durations=10 --ignore=tests/docs/sample_module.py" # tbump is used to simplify and standardize the release process when updating diff --git a/tests/docs/test_module.py b/tests/docs/sample_module.py similarity index 79% rename from tests/docs/test_module.py rename to tests/docs/sample_module.py index 38f5053..3738b24 100644 --- a/tests/docs/test_module.py +++ b/tests/docs/sample_module.py @@ -1,5 +1,5 @@ """ -test_module docstring +sample_module docstring This module provides a module and classes with and without traits to test autodoc_traits against. It does not contain tests. @@ -9,8 +9,8 @@ from traitlets.config.configurable import Configurable -class TestConfigurable(Configurable): - """TestConfigurable docstring""" +class SampleConfigurable(Configurable): + """SampleConfigurable docstring""" non_trait = False @@ -33,8 +33,8 @@ def method(self): """method docstring""" -class TestConfigurableSubclass(TestConfigurable): - """TestConfigurableSubclass docstring""" +class SampleConfigurableSubclass(SampleConfigurable): + """SampleConfigurableSubclass docstring""" subclass_non_trait = False @@ -57,8 +57,8 @@ def subclass_method(self): """subclass_method docstring""" -class TestNonConfigurable: - """TestNonConfigurable docstring""" +class SampleNonConfigurable: + """SampleNonConfigurable docstring""" non_trait = False @@ -70,8 +70,8 @@ def method(self): """method docstring""" -class TestNonConfigurableSubclass(TestNonConfigurable): - """TestNonConfigurableSubclass docstring""" +class SampleNonConfigurableSubclass(SampleNonConfigurable): + """SampleNonConfigurableSubclass docstring""" non_trait = False diff --git a/tests/docs/source/autoclass/members.rst b/tests/docs/source/autoclass/members.rst index 6ccb1c3..5381a8d 100644 --- a/tests/docs/source/autoclass/members.rst +++ b/tests/docs/source/autoclass/members.rst @@ -6,6 +6,6 @@ members. In this test expect no trait members to show up. -.. autoclass:: test_module.TestConfigurable +.. autoclass:: sample_module.SampleConfigurable :noindex: :members: diff --git a/tests/docs/source/autoclass/undoc_members.rst b/tests/docs/source/autoclass/undoc_members.rst index f9b34b2..2205c5d 100644 --- a/tests/docs/source/autoclass/undoc_members.rst +++ b/tests/docs/source/autoclass/undoc_members.rst @@ -5,7 +5,7 @@ The ``members`` and ``undoc-members`` option combined should present all class members, including the traits. And with autodoc_traits installed, the attributes should be presented with their help strings as docstrings. -.. autoclass:: test_module.TestConfigurable +.. autoclass:: sample_module.SampleConfigurable :noindex: :members: :undoc-members: diff --git a/tests/docs/source/autoconfigurable/exclude_members.rst b/tests/docs/source/autoconfigurable/exclude_members.rst index 7a2a36b..5cee7b5 100644 --- a/tests/docs/source/autoconfigurable/exclude_members.rst +++ b/tests/docs/source/autoconfigurable/exclude_members.rst @@ -8,7 +8,7 @@ In this test we provide ``members`` and then exclude the members ``trait`` and ``method`` by specifying them with ``exclude-members`` that otherwise ought to show up, and check that they aren't showing up. -.. autoconfigurable:: test_module.TestConfigurable +.. autoconfigurable:: sample_module.SampleConfigurable :noindex: :members: :exclude-members: trait,method diff --git a/tests/docs/source/autoconfigurable/inherited_members.rst b/tests/docs/source/autoconfigurable/inherited_members.rst index ecda72b..95dc4cc 100644 --- a/tests/docs/source/autoconfigurable/inherited_members.rst +++ b/tests/docs/source/autoconfigurable/inherited_members.rst @@ -2,14 +2,14 @@ autoconfigurable - inherited-members ==================================== With the ``inherited-members`` option, we expect traits from the superclass -TestConfigurable to show up as well as traits from TestConfigurableSubclass. +SampleConfigurable to show up as well as traits from SampleConfigurableSubclass. .. note:: Several members from the ``traitlets.HasTraits`` base class are excluded for now as they cause the sphinx-build warning of ``Unexpected section title`` in sphinx 4. -.. autoconfigurable:: test_module.TestConfigurableSubclass +.. autoconfigurable:: sample_module.SampleConfigurableSubclass :noindex: :inherited-members: :exclude-members: class_config_section,observe,on_trait_change,trait_defaults,trait_events,trait_values,unobserve diff --git a/tests/docs/source/autoconfigurable/members.rst b/tests/docs/source/autoconfigurable/members.rst index cc0cf9e..bf1ab6c 100644 --- a/tests/docs/source/autoconfigurable/members.rst +++ b/tests/docs/source/autoconfigurable/members.rst @@ -6,6 +6,6 @@ members. In this test expect all trait members to show up. -.. autoconfigurable:: test_module.TestConfigurable +.. autoconfigurable:: sample_module.SampleConfigurable :noindex: :members: diff --git a/tests/docs/source/autoconfigurable/no_members.rst b/tests/docs/source/autoconfigurable/no_members.rst index bc6da4f..808b5a4 100644 --- a/tests/docs/source/autoconfigurable/no_members.rst +++ b/tests/docs/source/autoconfigurable/no_members.rst @@ -6,5 +6,5 @@ present them all still, see `Issue27`_. .. _Issue27: https://github.com/jupyterhub/autodoc-traits/issues/27 -.. autoconfigurable:: test_module.TestConfigurable +.. autoconfigurable:: sample_module.SampleConfigurable :noindex: diff --git a/tests/docs/source/autoconfigurable/non_configurable_raises_error.rst b/tests/docs/source/autoconfigurable/non_configurable_raises_error.rst index 782f9aa..966e332 100644 --- a/tests/docs/source/autoconfigurable/non_configurable_raises_error.rst +++ b/tests/docs/source/autoconfigurable/non_configurable_raises_error.rst @@ -7,5 +7,5 @@ Test that we error when used on non-configurable classes. This file is targeted by ``exclude_patterns`` in ``source/conf.py`` to avoid failing unless we want to explicitly test such failure. -.. autoconfigurable:: test_module.TestNonConfigurable +.. autoconfigurable:: sample_module.SampleNonConfigurable :noindex: diff --git a/tests/docs/source/autoconfigurable/specified_members.rst b/tests/docs/source/autoconfigurable/specified_members.rst index eba421f..c37ddfc 100644 --- a/tests/docs/source/autoconfigurable/specified_members.rst +++ b/tests/docs/source/autoconfigurable/specified_members.rst @@ -10,6 +10,6 @@ still, see `Issue27`_. .. _Issue27: https://github.com/jupyterhub/autodoc-traits/issues/27 -.. autoconfigurable:: test_module.TestConfigurable +.. autoconfigurable:: sample_module.SampleConfigurable :noindex: :members: method,trait_nohelp diff --git a/tests/docs/source/automodule/members.rst b/tests/docs/source/automodule/members.rst index 1c7f485..ad12fed 100644 --- a/tests/docs/source/automodule/members.rst +++ b/tests/docs/source/automodule/members.rst @@ -4,6 +4,6 @@ automodule - members Test that we can present a module with a mix of traitlets configurable member classes and normal classes, and they all show up. -.. automodule:: test_module +.. automodule:: sample_module :noindex: :members: diff --git a/tests/docs/source/autotrait/help.rst b/tests/docs/source/autotrait/help.rst index b5e191e..be5e876 100644 --- a/tests/docs/source/autotrait/help.rst +++ b/tests/docs/source/autotrait/help.rst @@ -3,5 +3,5 @@ autotrait - help Test that we present the trait's provided ``help``. -.. autotrait:: test_module.TestConfigurable.trait +.. autotrait:: sample_module.SampleConfigurable.trait :noindex: diff --git a/tests/docs/source/autotrait/noconfig.rst b/tests/docs/source/autotrait/noconfig.rst index f946551..b5ac431 100644 --- a/tests/docs/source/autotrait/noconfig.rst +++ b/tests/docs/source/autotrait/noconfig.rst @@ -4,5 +4,5 @@ autotrait - no config Test that we still present a trait without ``config=True`` if directly requested via the ``autotrait`` directive. -.. autotrait:: test_module.TestConfigurable.trait_noconfig +.. autotrait:: sample_module.SampleConfigurable.trait_noconfig :noindex: diff --git a/tests/docs/source/autotrait/nohelp.rst b/tests/docs/source/autotrait/nohelp.rst index 8cab158..36878fc 100644 --- a/tests/docs/source/autotrait/nohelp.rst +++ b/tests/docs/source/autotrait/nohelp.rst @@ -4,5 +4,5 @@ autotrait - no help Test that we fall back to present the trait's header even if it lacks a ``help`` string. -.. autotrait:: test_module.TestConfigurable.trait_nohelp +.. autotrait:: sample_module.SampleConfigurable.trait_nohelp :noindex: diff --git a/tests/docs/source/autotrait/non_trait_raises_error.rst b/tests/docs/source/autotrait/non_trait_raises_error.rst index 76f4645..d908fe9 100644 --- a/tests/docs/source/autotrait/non_trait_raises_error.rst +++ b/tests/docs/source/autotrait/non_trait_raises_error.rst @@ -7,5 +7,5 @@ Test that we error when used on non-trait attributes. This file is targeted by ``exclude_patterns`` in ``source/conf.py`` to avoid failing unless we want to explicitly test such failure. -.. autotrait:: test_module.TestConfigurable.non_trait +.. autotrait:: sample_module.SampleConfigurable.non_trait :noindex: diff --git a/tests/docs/source/conf.py b/tests/docs/source/conf.py index 83d0a1c..7e646ee 100644 --- a/tests/docs/source/conf.py +++ b/tests/docs/source/conf.py @@ -9,7 +9,7 @@ "sphinx.ext.napoleon", ] -# ensure test_module.py is on path +# ensure sample_module.py is on path tests_dir = os.path.join(os.path.dirname(__file__), "..") tests_dir = os.path.abspath(tests_dir) sys.path.insert(0, tests_dir) diff --git a/tests/test_autodoc_traits.py b/tests/test_autodoc_traits.py index f0bc976..201d550 100644 --- a/tests/test_autodoc_traits.py +++ b/tests/test_autodoc_traits.py @@ -20,18 +20,18 @@ def test_sphinx_build_all_docs(temp_docs_dir, monkeypatch): @pytest.mark.parametrize( "rst_file_to_test, strings_in_html, strings_not_in_html", [ - ("autoclass/members.rst", [], ["c.TestConfigurable.trait"]), - ("autoclass/undoc_members.rst", ["c.TestConfigurable.trait"], []), + ("autoclass/members.rst", [], ["c.SampleConfigurable.trait"]), + ("autoclass/undoc_members.rst", ["c.SampleConfigurable.trait"], []), ( "autoconfigurable/exclude_members.rst", - ["c.TestConfigurable.trait_nohelp"], + ["c.SampleConfigurable.trait_nohelp"], ["trait help text", "method docstring"], ), ( "autoconfigurable/inherited_members.rst", [ - "c.TestConfigurableSubclass.trait", - "c.TestConfigurableSubclass.subclass_trait", + "c.SampleConfigurableSubclass.trait", + "c.SampleConfigurableSubclass.subclass_trait", "method docstring", ], [], @@ -49,23 +49,23 @@ def test_sphinx_build_all_docs(temp_docs_dir, monkeypatch): ("autoconfigurable/non_configurable_raises_error.rst", [], []), ( "autoconfigurable/specified_members.rst", - ["method docstring", "c.TestConfigurable.trait_nohelp", "trait help text"], + ["method docstring", "c.SampleConfigurable.trait_nohelp", "trait help text"], [], ), ( "automodule/members.rst", [ - "test_module docstring", - "TestConfigurable docstring", - "TestConfigurableSubclass docstring", - "TestNonConfigurable docstring", - "TestNonConfigurableSubclass docstring", + "sample_module docstring", + "SampleConfigurable docstring", + "SampleConfigurableSubclass docstring", + "SampleNonConfigurable docstring", + "SampleNonConfigurableSubclass docstring", ], [], ), - ("autotrait/help.rst", ["c.TestConfigurable.trait", "trait help text"], []), - ("autotrait/noconfig.rst", ["c.TestConfigurable.trait_noconfig"], []), - ("autotrait/nohelp.rst", ["c.TestConfigurable.trait_nohelp"], []), + ("autotrait/help.rst", ["c.SampleConfigurable.trait", "trait help text"], []), + ("autotrait/noconfig.rst", ["c.SampleConfigurable.trait_noconfig"], []), + ("autotrait/nohelp.rst", ["c.SampleConfigurable.trait_nohelp"], []), ("autotrait/non_trait_raises_error.rst", [], []), ], ) From 234dd6a0584d243238e0c997ecb9befedfbab9e7 Mon Sep 17 00:00:00 2001 From: Erik Sundell Date: Wed, 14 Dec 2022 15:42:42 +0100 Subject: [PATCH 10/12] docs: fix tests/README.md on how to use sphinx-autobuild --- tests/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/README.md b/tests/README.md index 322cda6..c43d299 100644 --- a/tests/README.md +++ b/tests/README.md @@ -24,7 +24,6 @@ sphinx-autobuild \ --watch="test_module.py" \ --watch="../../autodoc_traits.py" \ --pre-build="rm -rf build" \ - --ignore source \ build ``` From ab21f119c0e165d6edcf0fb374cb42819ede1a57 Mon Sep 17 00:00:00 2001 From: Erik Sundell Date: Wed, 14 Dec 2022 15:48:11 +0100 Subject: [PATCH 11/12] maint: test and clarify outcome with/without members using subclass The current behavior before and after the PR adding this commit, is that also the inherited configurable traitlets will be presented. This commit make us test against a class with inherited configurable traitlets to clarify that. --- .../docs/source/autoconfigurable/members.rst | 5 +- .../source/autoconfigurable/no_members.rst | 5 +- tests/test_autodoc_traits.py | 72 ++++++++++++++++--- 3 files changed, 67 insertions(+), 15 deletions(-) diff --git a/tests/docs/source/autoconfigurable/members.rst b/tests/docs/source/autoconfigurable/members.rst index bf1ab6c..bace0a7 100644 --- a/tests/docs/source/autoconfigurable/members.rst +++ b/tests/docs/source/autoconfigurable/members.rst @@ -4,8 +4,9 @@ autoconfigurable - members The ``members`` option without specified members should present all class members. -In this test expect all trait members to show up. +In this test expect all trait members with ``.config(True)`` to show up, even +those inherited from super classes. -.. autoconfigurable:: sample_module.SampleConfigurable +.. autoconfigurable:: sample_module.SampleConfigurableSubclass :noindex: :members: diff --git a/tests/docs/source/autoconfigurable/no_members.rst b/tests/docs/source/autoconfigurable/no_members.rst index 808b5a4..2e6378a 100644 --- a/tests/docs/source/autoconfigurable/no_members.rst +++ b/tests/docs/source/autoconfigurable/no_members.rst @@ -2,9 +2,10 @@ autoconfigurable - no members ============================= Without the ``members`` option, one may expect no members to show up, but we -present them all still, see `Issue27`_. +present all configurable traits still, including inherited configurable traits, +see `Issue27`_. .. _Issue27: https://github.com/jupyterhub/autodoc-traits/issues/27 -.. autoconfigurable:: sample_module.SampleConfigurable +.. autoconfigurable:: sample_module.SampleConfigurableSubclass :noindex: diff --git a/tests/test_autodoc_traits.py b/tests/test_autodoc_traits.py index 201d550..fc205ff 100644 --- a/tests/test_autodoc_traits.py +++ b/tests/test_autodoc_traits.py @@ -20,12 +20,27 @@ def test_sphinx_build_all_docs(temp_docs_dir, monkeypatch): @pytest.mark.parametrize( "rst_file_to_test, strings_in_html, strings_not_in_html", [ - ("autoclass/members.rst", [], ["c.SampleConfigurable.trait"]), - ("autoclass/undoc_members.rst", ["c.SampleConfigurable.trait"], []), + ( + "autoclass/members.rst", + [], + [ + "c.SampleConfigurable.trait", + ], + ), + ( + "autoclass/undoc_members.rst", + [ + "c.SampleConfigurable.trait", + ], + [], + ), ( "autoconfigurable/exclude_members.rst", ["c.SampleConfigurable.trait_nohelp"], - ["trait help text", "method docstring"], + [ + "trait help text", + "method docstring", + ], ), ( "autoconfigurable/inherited_members.rst", @@ -38,18 +53,34 @@ def test_sphinx_build_all_docs(temp_docs_dir, monkeypatch): ), ( "autoconfigurable/members.rst", - ["trait help text", "method docstring"], - ["trait_noconfig help text"], + [ + "c.SampleConfigurableSubclass.subclass_trait", + "c.SampleConfigurableSubclass.trait", + "method docstring", + ], + [ + "trait_noconfig help text", + ], ), ( "autoconfigurable/no_members.rst", - ["trait help text"], - ["trait_noconfig help text", "method docstring"], + [ + "c.SampleConfigurableSubclass.subclass_trait", + "c.SampleConfigurableSubclass.trait", + ], + [ + "trait_noconfig help text", + "method docstring", + ], ), ("autoconfigurable/non_configurable_raises_error.rst", [], []), ( "autoconfigurable/specified_members.rst", - ["method docstring", "c.SampleConfigurable.trait_nohelp", "trait help text"], + [ + "method docstring", + "c.SampleConfigurable.trait_nohelp", + "trait help text", + ], [], ), ( @@ -63,9 +94,28 @@ def test_sphinx_build_all_docs(temp_docs_dir, monkeypatch): ], [], ), - ("autotrait/help.rst", ["c.SampleConfigurable.trait", "trait help text"], []), - ("autotrait/noconfig.rst", ["c.SampleConfigurable.trait_noconfig"], []), - ("autotrait/nohelp.rst", ["c.SampleConfigurable.trait_nohelp"], []), + ( + "autotrait/help.rst", + [ + "c.SampleConfigurable.trait", + "trait help text", + ], + [], + ), + ( + "autotrait/noconfig.rst", + [ + "c.SampleConfigurable.trait_noconfig", + ], + [], + ), + ( + "autotrait/nohelp.rst", + [ + "c.SampleConfigurable.trait_nohelp", + ], + [], + ), ("autotrait/non_trait_raises_error.rst", [], []), ], ) From e2e11eb21094b0771e1468319ee762f071e4cdcd Mon Sep 17 00:00:00 2001 From: Erik Sundell Date: Wed, 14 Dec 2022 16:00:26 +0100 Subject: [PATCH 12/12] maint: rely on sphinx.ext.napoleon in tests --- tests/docs/source/autoconfigurable/inherited_members.rst | 6 ------ tests/docs/source/conf.py | 5 +++-- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/tests/docs/source/autoconfigurable/inherited_members.rst b/tests/docs/source/autoconfigurable/inherited_members.rst index 95dc4cc..2ea3205 100644 --- a/tests/docs/source/autoconfigurable/inherited_members.rst +++ b/tests/docs/source/autoconfigurable/inherited_members.rst @@ -4,12 +4,6 @@ autoconfigurable - inherited-members With the ``inherited-members`` option, we expect traits from the superclass SampleConfigurable to show up as well as traits from SampleConfigurableSubclass. -.. note:: - Several members from the ``traitlets.HasTraits`` base class are excluded for - now as they cause the sphinx-build warning of ``Unexpected section title`` in - sphinx 4. - .. autoconfigurable:: sample_module.SampleConfigurableSubclass :noindex: :inherited-members: - :exclude-members: class_config_section,observe,on_trait_change,trait_defaults,trait_events,trait_values,unobserve diff --git a/tests/docs/source/conf.py b/tests/docs/source/conf.py index 7e646ee..4ce6d98 100644 --- a/tests/docs/source/conf.py +++ b/tests/docs/source/conf.py @@ -4,8 +4,9 @@ project = "autodoc_traits tests" extensions = [ "autodoc_traits", - # sphinx.ext.napoleon is added to avoid warnings if testing with :inherited-members:` - # where the traitlets base classes members has numpy or google-format docstrings + # sphinx.ext.napoleon is added to avoid warnings if testing with + # :inherited-members:` where the super classe traitlets.HasTraits has numpy + # or google-format docstrings that the napoleon can help interpret. "sphinx.ext.napoleon", ]