From 352bb1fb5f30bfdda8c0240b463afef952944efd Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Sun, 25 Sep 2022 00:34:02 +0200 Subject: [PATCH] Generalize validation that pyplot commands are documented Until now, the test made some exclusions (_NON_PLOT_COMMANDS) and reqired all functions to be documented in a single autosummary block. This change ensures the documentation of the _NON_PLOT_COMMANDS and it allows the commands to be spread across arbitrary many autosummary sections. This is in preparation of regrouping the pyplot commands similar to the Axes documentation. This also pending deprecates `pyplot.get_plot_commands`, which should not be a public function. I'm defensive by using pending, because if `get_plot_commands` is used somewhere, that's most likely some downstream lib and we want to give them time to adapt. Co-authored-by: hannah --- .../deprecations/24000-TH.rst | 5 +++ lib/matplotlib/pyplot.py | 17 ++++---- lib/matplotlib/tests/test_pyplot.py | 41 ++++++++++++++++--- 3 files changed, 51 insertions(+), 12 deletions(-) create mode 100644 doc/api/next_api_changes/deprecations/24000-TH.rst diff --git a/doc/api/next_api_changes/deprecations/24000-TH.rst b/doc/api/next_api_changes/deprecations/24000-TH.rst new file mode 100644 index 000000000000..d1025d1fbb95 --- /dev/null +++ b/doc/api/next_api_changes/deprecations/24000-TH.rst @@ -0,0 +1,5 @@ +``matplotlib.pyplot.get_plot_commands`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... is a pending deprecation. This is considered internal and no end-user +should need it. diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index 6f757ae031ef..d6c7e54baa7e 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -2028,20 +2028,23 @@ def thetagrids(angles=None, labels=None, fmt=None, **kwargs): return lines, labels -_NON_PLOT_COMMANDS = { - 'connect', 'disconnect', 'get_current_fig_manager', 'ginput', - 'new_figure_manager', 'waitforbuttonpress'} - - +@_api.deprecated("3.7", pending=True) def get_plot_commands(): """ Get a sorted list of all of the plotting commands. """ + NON_PLOT_COMMANDS = { + 'connect', 'disconnect', 'get_current_fig_manager', 'ginput', + 'new_figure_manager', 'waitforbuttonpress'} + return (name for name in _get_pyplot_commands() + if name not in NON_PLOT_COMMANDS) + + +def _get_pyplot_commands(): # This works by searching for all functions in this module and removing # a few hard-coded exclusions, as well as all of the colormap-setting # functions, and anything marked as private with a preceding underscore. - exclude = {'colormaps', 'colors', 'get_plot_commands', - *_NON_PLOT_COMMANDS, *colormaps} + exclude = {'colormaps', 'colors', 'get_plot_commands', *colormaps} this_module = inspect.getmodule(get_plot_commands) return sorted( name for name, obj in globals().items() diff --git a/lib/matplotlib/tests/test_pyplot.py b/lib/matplotlib/tests/test_pyplot.py index 2e51af54ea88..2427ac8af65e 100644 --- a/lib/matplotlib/tests/test_pyplot.py +++ b/lib/matplotlib/tests/test_pyplot.py @@ -1,5 +1,4 @@ import difflib -import re import numpy as np import subprocess @@ -367,10 +366,42 @@ def test_doc_pyplot_summary(): if not pyplot_docs.exists(): pytest.skip("Documentation sources not available") - lines = pyplot_docs.read_text() - m = re.search(r':nosignatures:\n\n(.*?)\n\n', lines, re.DOTALL) - doc_functions = set(line.strip() for line in m.group(1).split('\n')) - plot_commands = set(plt.get_plot_commands()) + def extract_documented_functions(lines): + """ + Return a list of all the functions that are mentioned in the + autosummary blocks contained in *lines*. + + An autosummary block looks like this:: + + .. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + plot + plot_date + + """ + functions = [] + in_autosummary = False + for line in lines: + if not in_autosummary: + if line.startswith(".. autosummary::"): + in_autosummary = True + else: + if not line or line.startswith(" :"): + # empty line or autosummary parameter + continue + if not line[0].isspace(): + # no more indentation: end of autosummary block + in_autosummary = False + continue + functions.append(line.strip()) + return functions + + lines = pyplot_docs.read_text().split("\n") + doc_functions = set(extract_documented_functions(lines)) + plot_commands = set(plt._get_pyplot_commands()) missing = plot_commands.difference(doc_functions) if missing: raise AssertionError(