Commit bb431473 authored by Tim Peters's avatar Tim Peters

Drop the excruciating newline requirements on arguments to

Example.__init__.  The constructor now adds trailing newlines when
needed, and no longer distinguishes between multi- and single-line
cases for source.
parent dd0e4752
...@@ -493,24 +493,24 @@ class Example: ...@@ -493,24 +493,24 @@ class Example:
A single doctest example, consisting of source code and expected A single doctest example, consisting of source code and expected
output. Example defines the following attributes: output. Example defines the following attributes:
- source: A single python statement, ending in a newline iff the - source: A single Python statement, always ending with a newline.
statement spans more than one line. The constructor adds a newline if needed.
- want: The expected output from running the source code (either - want: The expected output from running the source code (either
from stdout, or a traceback in case of exception). `want` from stdout, or a traceback in case of exception). `want` ends
should always end with a newline, unless no output is expected, with a newline unless it's empty, in which case it's an empty
string. The constructor adds a newline if needed.
- lineno: The line number within the DocTest string containing - lineno: The line number within the DocTest string containing
this Example where the Example begins. This line number is this Example where the Example begins. This line number is
zero-based, with respect to the beginning of the DocTest. zero-based, with respect to the beginning of the DocTest.
""" """
def __init__(self, source, want, lineno): def __init__(self, source, want, lineno):
# Check invariants. # Normalize inputs.
if (source[-1:] == '\n') != ('\n' in source[:-1]): if not source.endswith('\n'):
raise AssertionError("source must end with newline iff " source += '\n'
"source contains more than one line") if want and not want.endswith('\n'):
if want and want[-1] != '\n': want += '\n'
raise AssertionError("non-empty want must end with newline")
# Store properties. # Store properties.
self.source = source self.source = source
self.want = want self.want = want
...@@ -625,9 +625,9 @@ class Parser: ...@@ -625,9 +625,9 @@ class Parser:
... ''' ... '''
>>> for x in Parser('<string>', text).get_examples(): >>> for x in Parser('<string>', text).get_examples():
... print (x.source, x.want, x.lineno) ... print (x.source, x.want, x.lineno)
('x, y = 2, 3 # no output expected', '', 1) ('x, y = 2, 3 # no output expected\\n', '', 1)
('if 1:\\n print x\\n print y\\n', '2\\n3\\n', 2) ('if 1:\\n print x\\n print y\\n', '2\\n3\\n', 2)
('x+y', '5\\n', 9) ('x+y\\n', '5\\n', 9)
""" """
examples = [] examples = []
charno, lineno = 0, 0 charno, lineno = 0, 0
...@@ -1283,7 +1283,7 @@ class DocTestRunner: ...@@ -1283,7 +1283,7 @@ class DocTestRunner:
# like "if 1: print 2", then compile() requires a # like "if 1: print 2", then compile() requires a
# trailing newline. Rather than analyze that, always # trailing newline. Rather than analyze that, always
# append one (it never hurts). # append one (it never hurts).
exec compile(example.source + '\n', "<string>", "single", exec compile(example.source, "<string>", "single",
compileflags, 1) in test.globs compileflags, 1) in test.globs
exception = None exception = None
except KeyboardInterrupt: except KeyboardInterrupt:
......
...@@ -127,31 +127,41 @@ an expected output string, and a line number (within the docstring): ...@@ -127,31 +127,41 @@ an expected output string, and a line number (within the docstring):
>>> example = doctest.Example('print 1', '1\n', 0) >>> example = doctest.Example('print 1', '1\n', 0)
>>> (example.source, example.want, example.lineno) >>> (example.source, example.want, example.lineno)
('print 1', '1\n', 0) ('print 1\n', '1\n', 0)
The `source` string should end in a newline iff the source spans more The `source` string ends in a newline:
than one line:
>>> # Source spans a single line: no terminating newline. Source spans a single line: no terminating newline.
>>> e = doctest.Example('print 1', '1\n', 0) >>> e = doctest.Example('print 1', '1\n', 0)
>>> e.source, e.want
('print 1\n', '1\n')
>>> e = doctest.Example('print 1\n', '1\n', 0) >>> e = doctest.Example('print 1\n', '1\n', 0)
Traceback (most recent call last): >>> e.source, e.want
AssertionError: source must end with newline iff source contains more than one line ('print 1\n', '1\n')
>>> # Source spans multiple lines: require terminating newline. Source spans multiple lines: require terminating newline.
>>> e = doctest.Example('print 1;\nprint 2\n', '1\n2\n', 0) >>> e = doctest.Example('print 1;\nprint 2\n', '1\n2\n', 0)
>>> e.source, e.want
('print 1;\nprint 2\n', '1\n2\n')
>>> e = doctest.Example('print 1;\nprint 2', '1\n2\n', 0) >>> e = doctest.Example('print 1;\nprint 2', '1\n2\n', 0)
Traceback (most recent call last): >>> e.source, e.want
AssertionError: source must end with newline iff source contains more than one line ('print 1;\nprint 2\n', '1\n2\n')
The `want` string should be terminated by a newline, unless it's the The `want` string ends with a newline, unless it's the empty string:
empty string:
>>> e = doctest.Example('print 1', '1\n', 0) >>> e = doctest.Example('print 1', '1\n', 0)
>>> e.source, e.want
('print 1\n', '1\n')
>>> e = doctest.Example('print 1', '1', 0) >>> e = doctest.Example('print 1', '1', 0)
Traceback (most recent call last): >>> e.source, e.want
AssertionError: non-empty want must end with newline ('print 1\n', '1\n')
>>> e = doctest.Example('print', '', 0) >>> e = doctest.Example('print', '', 0)
>>> e.source, e.want
('print\n', '')
""" """
def test_DocTest(): r""" def test_DocTest(): r"""
...@@ -180,9 +190,9 @@ constructor: ...@@ -180,9 +190,9 @@ constructor:
2 2
>>> e1, e2 = test.examples >>> e1, e2 = test.examples
>>> (e1.source, e1.want, e1.lineno) >>> (e1.source, e1.want, e1.lineno)
('print 12', '12\n', 1) ('print 12\n', '12\n', 1)
>>> (e2.source, e2.want, e2.lineno) >>> (e2.source, e2.want, e2.lineno)
("print 'another\\example'", 'another\nexample\n', 6) ("print 'another\\example'\n", 'another\nexample\n', 6)
Source information (name, filename, and line number) is available as Source information (name, filename, and line number) is available as
attributes on the doctest object: attributes on the doctest object:
...@@ -264,8 +274,8 @@ will return a single test (for that function's docstring): ...@@ -264,8 +274,8 @@ will return a single test (for that function's docstring):
>>> print tests >>> print tests
[<DocTest sample_func from ...:12 (1 example)>] [<DocTest sample_func from ...:12 (1 example)>]
>>> e = tests[0].examples[0] >>> e = tests[0].examples[0]
>>> print (e.source, e.want, e.lineno) >>> (e.source, e.want, e.lineno)
('print sample_func(22)', '44\n', 3) ('print sample_func(22)\n', '44\n', 3)
>>> doctest: -ELLIPSIS # Turn ellipsis back off >>> doctest: -ELLIPSIS # Turn ellipsis back off
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment