From 158219b6d8e69da955b4d33e5e99ffe83cedb420 Mon Sep 17 00:00:00 2001 From: Jim DeLaHunt Date: Sat, 11 Feb 2017 23:57:52 -0800 Subject: [PATCH 1/3] bpo-29428: make doctest documentation clearer Clarify the introduction of section, "How are Docstring Examples Recognized", by moving it to above the example and rewriting for clarity. Change the example in that section to use more plausible code, which also demonstrates a multi-line test fixture. Add three "fine print" points, about the example prefix strings, blank expected output, and multi-line expected output. Clarify the introduction of section, "What's the Execution Context", by rewriting for clarity, and breaking into three paragraphs. Copy-edit the first paragraph in section, "Which Docstrings Are Examined?". --- Doc/library/doctest.rst | 71 ++++++++++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 23 deletions(-) diff --git a/Doc/library/doctest.rst b/Doc/library/doctest.rst index 15b12f7aa786ea..5dd6520346b668 100644 --- a/Doc/library/doctest.rst +++ b/Doc/library/doctest.rst @@ -276,8 +276,9 @@ sections. Which Docstrings Are Examined? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The module docstring, and all function, class and method docstrings are -searched. Objects imported into the module are not searched. +The docstring for the module, and the docstrings for all functions, +classes, and methods in that module, are searched. +Objects imported into the module are not searched. In addition, if ``M.__test__`` exists and "is true", it must be a dict, and each entry maps a (string) name to a function object, class object, or string. @@ -300,33 +301,49 @@ their contained methods and nested classes. How are Docstring Examples Recognized? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The :mod:`doctest` module treats any line beginning with ``>>>`` as an +example to be tested. +Following lines which begin with ``...`` continue the example. +Subsequent non-blank lines, if any, form an expected output string. +A blank (all-whitespace) line, or a line with ``>>>`` (beginning the +next example), ends the expected output string. + In most cases a copy-and-paste of an interactive console session works fine, but doctest isn't trying to do an exact emulation of any specific Python shell. :: >>> # comments are ignored - >>> x = 12 - >>> x - 12 - >>> if x == 13: - ... print("yes") + ... + >>> import math + >>> x = factorial(10); math.ceil(math.log10(x)) + 7 + >>> if x == factorial(9)*10: + ... print("same:\n{0}".format(x)) ... else: - ... print("no") - ... print("NO") - ... print("NO!!!") + ... print("differ:\n{0}\n{1}".format(x, factorial(9)*10)) ... - no - NO - NO!!! + same: + 3628800 >>> -Any expected output must immediately follow the final ``'>>> '`` or ``'... '`` -line containing the code, and the expected output (if any) extends to the next -``'>>> '`` or all-whitespace line. - The fine print: +* The ``>>>`` string tells the module to look for an interactive statement: + that is, a statement list ending with a newline, or a + :ref:`compound statement `. + The ``...`` string tells the module that the line continues a compound + statement. (Actually, doctest gets these strings from the PS1 and PS2 + values of the :mod:`sys` module.) + +* The expected output can be absent. This indicates that the example generates + no output when run. If the example does generate output, the module reports + it as a failure. + +* The expected output can contain multiple lines. These lines become a + string, which is compared to the string of actual output from + testing the example. + * Expected output cannot contain an all-whitespace line, since such a line is taken to signal the end of expected output. If expected output does contain a blank line, put ```` in your doctest example each place a blank line @@ -381,12 +398,20 @@ The fine print: What's the Execution Context? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -By default, each time :mod:`doctest` finds a docstring to test, it uses a -*shallow copy* of :mod:`M`'s globals, so that running tests doesn't change the -module's real globals, and so that one test in :mod:`M` can't leave behind -crumbs that accidentally allow another test to work. This means examples can -freely use any names defined at top-level in :mod:`M`, and names defined earlier -in the docstring being run. Examples cannot see names defined in other +Within a docstring, later examples can use names defined by earlier +examples. It's fine for an example to set up state, and +have no output. + +For each docstring, :mod:`doctest` makes (by default) a +*shallow copy* of :mod:`M`'s globals. +This means examples can freely use any names defined at the top level of +:mod:`M`. +When doctest tests examples, it doesn't change the module's real globals. + +This shallow copy of globals is discarded at the end of each docstring, +and copied afresh for the next docstring. Thus, examples in one docstring +in :mod:`M` can't leave behind crumbs that accidentally allow an example +in another docstring to work. Examples cannot see names defined in other docstrings. You can force use of your own dict as the execution context by passing From a140a7fc144f7e03ff94127731633e92320d56cd Mon Sep 17 00:00:00 2001 From: Jim DeLaHunt Date: Sun, 12 Feb 2017 20:53:36 -0800 Subject: [PATCH 2/3] Address bitdancer review comments, Doc/library/doctest.rst --- Doc/library/doctest.rst | 65 +++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/Doc/library/doctest.rst b/Doc/library/doctest.rst index 5dd6520346b668..04f6a466eac119 100644 --- a/Doc/library/doctest.rst +++ b/Doc/library/doctest.rst @@ -301,20 +301,19 @@ their contained methods and nested classes. How are Docstring Examples Recognized? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The :mod:`doctest` module treats any line beginning with ``>>>`` as an -example to be tested. -Following lines which begin with ``...`` continue the example. -Subsequent non-blank lines, if any, form an expected output string. -A blank (all-whitespace) line, or a line with ``>>>`` (beginning the -next example), ends the expected output string. +A doctest example is composed of one or more tests. An individual test +starts with a line that starts with '>>>', has zero or more code +continuation lines that start with '...', and ends with zero or more +expected output lines. The expected output ends at the first line that +starts with '>>>' or is blank. All lines in an example block must have +the same indentation level. In most cases a copy-and-paste of an interactive console session works fine, -but doctest isn't trying to do an exact emulation of any specific Python shell. +but doctest isn't trying to do an exact emulation of the Python shell. :: >>> # comments are ignored - ... >>> import math >>> x = factorial(10); math.ceil(math.log10(x)) 7 @@ -329,24 +328,27 @@ but doctest isn't trying to do an exact emulation of any specific Python shell. The fine print: -* The ``>>>`` string tells the module to look for an interactive statement: - that is, a statement list ending with a newline, or a - :ref:`compound statement `. - The ``...`` string tells the module that the line continues a compound - statement. (Actually, doctest gets these strings from the PS1 and PS2 - values of the :mod:`sys` module.) +* The >>> marks the start of an interactive statement: that is, a + statement list ending with a newline, or a :ref:`compound statement `. + The ... string indicates that the line continues a compound statement. -* The expected output can be absent. This indicates that the example generates - no output when run. If the example does generate output, the module reports +* If the expected output is empty, it indicates that the test generates + no output when run. If the test does generate output, the module reports it as a failure. * The expected output can contain multiple lines. These lines become a - string, which is compared to the string of actual output from - testing the example. + string containing newlines. The leading indentation of the example + block is stripped when building the string. The resulting string is + compared to the string of actual output from running the test. + +* The last code continuation line of an example copied from the + interactive shell (the line starting with "..." that is otherwise + blank in the example above) may be omitted without changing the + meaning of the test. * Expected output cannot contain an all-whitespace line, since such a line is taken to signal the end of expected output. If expected output does contain a - blank line, put ```` in your doctest example each place a blank line + blank line, put ```` in your doctest test each place a blank line is expected. * All hard tab characters are expanded to spaces, using 8-column tab stops. @@ -390,7 +392,7 @@ The fine print: 1 and as many leading whitespace characters are stripped from the expected output - as appeared in the initial ``'>>> '`` line that started the example. + as appeared in the initial ``'>>> '`` line that started the test. .. _doctest-execution-context: @@ -398,21 +400,20 @@ The fine print: What's the Execution Context? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Within a docstring, later examples can use names defined by earlier -examples. It's fine for an example to set up state, and +Within a docstring, later tests can use names defined by earlier +examples. It's fine for an test to set up state, and have no output. For each docstring, :mod:`doctest` makes (by default) a -*shallow copy* of :mod:`M`'s globals. -This means examples can freely use any names defined at the top level of -:mod:`M`. -When doctest tests examples, it doesn't change the module's real globals. - -This shallow copy of globals is discarded at the end of each docstring, -and copied afresh for the next docstring. Thus, examples in one docstring -in :mod:`M` can't leave behind crumbs that accidentally allow an example -in another docstring to work. Examples cannot see names defined in other -docstrings. +*shallow copy* of :mod:`M`'s globals. This means tests can freely +use any names defined at the top level of :mod:`M`. +When doctest performs tests, it doesn't change the module's real globals. + +This shallow copy of globals is discarded after the docstring has been +processed, and copied afresh for the next docstring. Thus, tests in one +docstring in :mod:`M` can't leave behind crumbs that accidentally allow an +test in another docstring to work. Tests cannot see names defined in +other docstrings. You can force use of your own dict as the execution context by passing ``globs=your_dict`` to :func:`testmod` or :func:`testfile` instead. From 62a9a4683c20c5348fd9f219e6d93d3b309b0211 Mon Sep 17 00:00:00 2001 From: Jim DeLaHunt Date: Sun, 12 Feb 2017 20:56:05 -0800 Subject: [PATCH 3/3] Fix typo "an test" -> "a test" --- Doc/library/doctest.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/doctest.rst b/Doc/library/doctest.rst index 04f6a466eac119..5eed34b1f5f2e6 100644 --- a/Doc/library/doctest.rst +++ b/Doc/library/doctest.rst @@ -401,7 +401,7 @@ What's the Execution Context? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Within a docstring, later tests can use names defined by earlier -examples. It's fine for an test to set up state, and +examples. It's fine for a test to set up state, and have no output. For each docstring, :mod:`doctest` makes (by default) a