Merged revisions 59883-59920 via svnmerge from

svn+ssh://pythondev@svn.python.org/python/trunk

........
  r59887 | neal.norwitz | 2008-01-10 06:42:58 +0100 (Thu, 10 Jan 2008) | 1 line

  Reword entry, not sure I made it much better though.
........
  r59888 | andrew.kuchling | 2008-01-10 14:37:12 +0100 (Thu, 10 Jan 2008) | 1 line

  Check for fd of -1 to save fsync() and fstat() call
........
  r59891 | thomas.heller | 2008-01-10 19:45:40 +0100 (Thu, 10 Jan 2008) | 1 line

  Reflow a paragraph, and fix a typo.
........
  r59892 | raymond.hettinger | 2008-01-10 20:15:10 +0100 (Thu, 10 Jan 2008) | 1 line

  Examples for named tuple subclassing should include __slots__
........
  r59895 | raymond.hettinger | 2008-01-10 21:37:12 +0100 (Thu, 10 Jan 2008) | 1 line

  Clarify how to add a field to a named tuple.
........
  r59896 | amaury.forgeotdarc | 2008-01-10 22:59:42 +0100 (Thu, 10 Jan 2008) | 12 lines

  Closing issue1761.
  Surprising behaviour of the "$" regexp: it matches the
  end of the string, AND just before the newline at the end
  of the string::

      re.sub('$', '#', 'foo\n') == 'foo#\n#'

  Python is consistent with Perl and the pcre library, so
  we just document it.
  Guido prefers "\Z" to match only the end of the string.
........
  r59898 | raymond.hettinger | 2008-01-11 00:00:01 +0100 (Fri, 11 Jan 2008) | 1 line

  Neaten-up the named tuple docs
........
  r59900 | raymond.hettinger | 2008-01-11 01:23:13 +0100 (Fri, 11 Jan 2008) | 1 line

  Run doctests on the collections module
........
  r59903 | raymond.hettinger | 2008-01-11 02:25:54 +0100 (Fri, 11 Jan 2008) | 1 line

  Doctest results return a named tuple for readability
........
  r59904 | raymond.hettinger | 2008-01-11 03:12:33 +0100 (Fri, 11 Jan 2008) | 1 line

  Comment-out missing constant (from rev 59819)
........
  r59905 | raymond.hettinger | 2008-01-11 03:24:13 +0100 (Fri, 11 Jan 2008) | 1 line

  Have Decimal.as_tuple return a named tuple.
........
  r59906 | raymond.hettinger | 2008-01-11 04:04:50 +0100 (Fri, 11 Jan 2008) | 1 line

  Let most inspect functions return named tuples
........
  r59907 | raymond.hettinger | 2008-01-11 04:20:54 +0100 (Fri, 11 Jan 2008) | 1 line

  Improve usability of the SequenceMatcher by returning named tuples describing match ranges.
........
  r59909 | thomas.heller | 2008-01-11 09:04:03 +0100 (Fri, 11 Jan 2008) | 1 line

  Add an important missing blank.
........
  r59910 | georg.brandl | 2008-01-11 10:19:11 +0100 (Fri, 11 Jan 2008) | 2 lines

  Guard definition of TIPC_SUB_CANCEL with an #ifdef.
........
  r59911 | georg.brandl | 2008-01-11 10:20:58 +0100 (Fri, 11 Jan 2008) | 2 lines

  News entries for rev. 5990[567].
........
  r59912 | georg.brandl | 2008-01-11 10:55:53 +0100 (Fri, 11 Jan 2008) | 2 lines

  Documentation for r5990[3567].
........
  r59913 | thomas.heller | 2008-01-11 13:41:39 +0100 (Fri, 11 Jan 2008) | 4 lines

  The sqlite3 dll, when compiled in debug mode, must be linked with /MDd
  to use the debug runtime library.  Further, the dll will be named
  sqlite3_d.dll.
........
  r59919 | thomas.heller | 2008-01-11 16:38:46 +0100 (Fri, 11 Jan 2008) | 6 lines

  Revert revision 59913, because it was wrong:

    The sqlite3 dll, when compiled in debug mode, must be linked with
    /MDd to use the debug runtime library.  Further, the dll will be
    named sqlite3_d.dll.
........
  r59920 | christian.heimes | 2008-01-11 16:42:29 +0100 (Fri, 11 Jan 2008) | 1 line

  Removed unused variable
........
This commit is contained in:
Christian Heimes 2008-01-11 16:17:00 +00:00
parent 222e1279f8
commit 25bb783c03
20 changed files with 203 additions and 125 deletions

View file

@ -327,6 +327,13 @@ Glossary
mutable mutable
Mutable objects can change their value but keep their :func:`id`. See Mutable objects can change their value but keep their :func:`id`. See
also :term:`immutable`. also :term:`immutable`.
named tuple
A tuple subclass whose elements also are accessible as attributes via
fixed names (the class name and field names are indicated in the
individual documentation of a named tuple type, like ``TestResults(failed,
attempted)``). Named tuple classes are created by
:func:`collections.namedtuple`.
namespace namespace
The place where a variable is stored. Namespaces are implemented as The place where a variable is stored. Namespaces are implemented as

View file

@ -397,8 +397,8 @@ they add the ability to access fields by name instead of position index.
method which lists the tuple contents in a ``name=value`` format. method which lists the tuple contents in a ``name=value`` format.
The *fieldnames* are a single string with each fieldname separated by whitespace The *fieldnames* are a single string with each fieldname separated by whitespace
and/or commas (for example 'x y' or 'x, y'). Alternatively, *fieldnames* and/or commas, for example ``'x y'`` or ``'x, y'``. Alternatively, *fieldnames*
can be a sequence of strings (such as ['x', 'y']). can be a sequence of strings such as ``['x', 'y']``.
Any valid Python identifier may be used for a fieldname except for names Any valid Python identifier may be used for a fieldname except for names
starting with an underscore. Valid identifiers consist of letters, digits, starting with an underscore. Valid identifiers consist of letters, digits,
@ -406,7 +406,7 @@ they add the ability to access fields by name instead of position index.
a :mod:`keyword` such as *class*, *for*, *return*, *global*, *pass*, *print*, a :mod:`keyword` such as *class*, *for*, *return*, *global*, *pass*, *print*,
or *raise*. or *raise*.
If *verbose* is true, will print the class definition. If *verbose* is true, the class definition is printed just before being built.
Named tuple instances do not have per-instance dictionaries, so they are Named tuple instances do not have per-instance dictionaries, so they are
lightweight and require no more memory than regular tuples. lightweight and require no more memory than regular tuples.
@ -533,7 +533,7 @@ function::
>>> getattr(p, 'x') >>> getattr(p, 'x')
11 11
To cast a dictionary to a named tuple, use the double-star-operator [#]_:: To convert a dictionary to a named tuple, use the double-star-operator [#]_::
>>> d = {'x': 11, 'y': 22} >>> d = {'x': 11, 'y': 22}
>>> Point(**d) >>> Point(**d)
@ -544,23 +544,24 @@ functionality with a subclass. Here is how to add a calculated field and
a fixed-width print format:: a fixed-width print format::
>>> class Point(namedtuple('Point', 'x y')): >>> class Point(namedtuple('Point', 'x y')):
... __slots__ = ()
... @property ... @property
... def hypot(self): ... def hypot(self):
... return (self.x ** 2 + self.y ** 2) ** 0.5 ... return (self.x ** 2 + self.y ** 2) ** 0.5
... def __str__(self): ... def __str__(self):
... return 'Point: x=%6.3f y=%6.3f hypot=%6.3f' % (self.x, self.y, self.hypot) ... return 'Point: x=%6.3f y=%6.3f hypot=%6.3f' % (self.x, self.y, self.hypot)
>>> for p in Point(3,4), Point(14,5), Point(9./7,6): >>> for p in Point(3, 4), Point(14, 5/7.):
... print(p) ... print(p)
Point: x= 3.000 y= 4.000 hypot= 5.000 Point: x= 3.000 y= 4.000 hypot= 5.000
Point: x=14.000 y= 5.000 hypot=14.866 Point: x=14.000 y= 0.714 hypot=14.018
Point: x= 1.286 y= 6.000 hypot= 6.136
Another use for subclassing is to replace performance critcal methods with Another use for subclassing is to replace performance critcal methods with
faster versions that bypass error-checking and that localize variable access:: faster versions that bypass error-checking::
class Point(namedtuple('Point', 'x y')): class Point(namedtuple('Point', 'x y')):
__slots__ = ()
_make = classmethod(tuple.__new__) _make = classmethod(tuple.__new__)
def _replace(self, _map=map, **kwds): def _replace(self, _map=map, **kwds):
return self._make(_map(kwds.get, ('x', 'y'), self)) return self._make(_map(kwds.get, ('x', 'y'), self))
@ -569,7 +570,7 @@ faster versions that bypass error-checking and that localize variable access::
Subclassing is not useful for adding new, stored fields. Instead, simply Subclassing is not useful for adding new, stored fields. Instead, simply
create a new named tuple type from the :attr:`_fields` attribute:: create a new named tuple type from the :attr:`_fields` attribute::
>>> Pixel = namedtuple('Pixel', Point._fields + Color._fields) >>> Point3D = namedtuple('Point3D', Point._fields + ('z',))
Default values can be implemented by using :meth:`_replace` to Default values can be implemented by using :meth:`_replace` to
customize a prototype instance:: customize a prototype instance::

View file

@ -328,7 +328,11 @@ also have a number of specialized methods:
.. method:: Decimal.as_tuple() .. method:: Decimal.as_tuple()
Return a tuple representation of the number: ``(sign, digit_tuple, exponent)``. Return a :term:`named tuple` representation of the number:
``DecimalTuple(sign, digits, exponent)``.
.. versionchanged:: 2.6
Use a named tuple.
.. method:: Decimal.canonical() .. method:: Decimal.canonical()

View file

@ -336,7 +336,7 @@ use :meth:`set_seq2` to set the commonly used sequence once and call
Find longest matching block in ``a[alo:ahi]`` and ``b[blo:bhi]``. Find longest matching block in ``a[alo:ahi]`` and ``b[blo:bhi]``.
If *isjunk* was omitted or ``None``, :meth:`get_longest_match` returns ``(i, j, If *isjunk* was omitted or ``None``, :meth:`find_longest_match` returns ``(i, j,
k)`` such that ``a[i:i+k]`` is equal to ``b[j:j+k]``, where ``alo <= i <= i+k <= k)`` such that ``a[i:i+k]`` is equal to ``b[j:j+k]``, where ``alo <= i <= i+k <=
ahi`` and ``blo <= j <= j+k <= bhi``. For all ``(i', j', k')`` meeting those ahi`` and ``blo <= j <= j+k <= bhi``. For all ``(i', j', k')`` meeting those
conditions, the additional conditions ``k >= k'``, ``i <= i'``, and if ``i == conditions, the additional conditions ``k >= k'``, ``i <= i'``, and if ``i ==
@ -365,6 +365,9 @@ use :meth:`set_seq2` to set the commonly used sequence once and call
If no blocks match, this returns ``(alo, blo, 0)``. If no blocks match, this returns ``(alo, blo, 0)``.
.. versionchanged:: 2.6
This method returns a :term:`named tuple` ``Match(a, b, size)``.
.. method:: SequenceMatcher.get_matching_blocks() .. method:: SequenceMatcher.get_matching_blocks()

View file

@ -1436,11 +1436,14 @@ DocTestRunner objects
.. method:: DocTestRunner.summarize([verbose]) .. method:: DocTestRunner.summarize([verbose])
Print a summary of all the test cases that have been run by this DocTestRunner, Print a summary of all the test cases that have been run by this DocTestRunner,
and return a tuple ``(failure_count, test_count)``. and return a :term:`named tuple` ``TestResults(failed, attempted)``.
The optional *verbose* argument controls how detailed the summary is. If the The optional *verbose* argument controls how detailed the summary is. If the
verbosity is not specified, then the :class:`DocTestRunner`'s verbosity is used. verbosity is not specified, then the :class:`DocTestRunner`'s verbosity is used.
.. versionchanged:: 2.6
Use a named tuple.
.. _doctest-outputchecker: .. _doctest-outputchecker:

View file

@ -188,7 +188,8 @@ attributes:
.. function:: getmoduleinfo(path) .. function:: getmoduleinfo(path)
Return a tuple of values that describe how Python will interpret the file Returns a :term:`named tuple` ``ModuleInfo(name, suffix, mode,
module_type)`` of values that describe how Python will interpret the file
identified by *path* if it is a module, or ``None`` if it would not be identified by *path* if it is a module, or ``None`` if it would not be
identified as a module. The return tuple is ``(name, suffix, mode, mtype)``, identified as a module. The return tuple is ``(name, suffix, mode, mtype)``,
where *name* is the name of the module without the name of any enclosing where *name* is the name of the module without the name of any enclosing
@ -377,8 +378,9 @@ Classes and functions
.. function:: getargspec(func) .. function:: getargspec(func)
Get the names and default values of a function's arguments. A tuple of four Get the names and default values of a function's arguments. A
things is returned: ``(args, varargs, varkw, defaults)``. *args* is a list of :term:`named tuple` ``ArgSpec(args, varargs, keywords,
defaults)`` is returned. *args* is a list of
the argument names. *varargs* and *varkw* are the names of the ``*`` and the argument names. *varargs* and *varkw* are the names of the ``*`` and
``**`` arguments or ``None``. *defaults* is a tuple of default argument ``**`` arguments or ``None``. *defaults* is a tuple of default argument
values or None if there are no default arguments; if this tuple has *n* values or None if there are no default arguments; if this tuple has *n*
@ -391,10 +393,10 @@ Classes and functions
.. function:: getfullargspec(func) .. function:: getfullargspec(func)
Get the names and default values of a function's arguments. A tuple of seven Get the names and default values of a function's arguments. A :term:`named tuple`
things is returned: is returned:
``(args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, annotations)`` ``FullArgSpec(args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, annotations)``
*args* is a list of the argument names. *varargs* and *varkw* are the names *args* is a list of the argument names. *varargs* and *varkw* are the names
of the ``*`` and ``**`` arguments or ``None``. *defaults* is an n-tuple of of the ``*`` and ``**`` arguments or ``None``. *defaults* is an n-tuple of
@ -408,8 +410,8 @@ Classes and functions
.. function:: getargvalues(frame) .. function:: getargvalues(frame)
Get information about arguments passed into a particular frame. A tuple of four Get information about arguments passed into a particular frame. A :term:`named tuple`
things is returned: ``(args, varargs, varkw, locals)``. *args* is a list of the ``ArgInfo(args, varargs, keywords, locals)`` is returned. *args* is a list of the
argument names (it may contain nested lists). *varargs* and *varkw* are the argument names (it may contain nested lists). *varargs* and *varkw* are the
names of the ``*`` and ``**`` arguments or ``None``. *locals* is the locals names of the ``*`` and ``**`` arguments or ``None``. *locals* is the locals
dictionary of the given frame. dictionary of the given frame.
@ -476,8 +478,8 @@ line.
.. function:: getframeinfo(frame[, context]) .. function:: getframeinfo(frame[, context])
Get information about a frame or traceback object. A 5-tuple is returned, the Get information about a frame or traceback object. A :term:`named tuple`
last five elements of the frame's frame record. ``Traceback(filename, lineno, function, code_context, index)`` is returned.
.. function:: getouterframes(frame[, context]) .. function:: getouterframes(frame[, context])

View file

@ -98,7 +98,9 @@ The special characters are:
string, and in :const:`MULTILINE` mode also matches before a newline. ``foo`` string, and in :const:`MULTILINE` mode also matches before a newline. ``foo``
matches both 'foo' and 'foobar', while the regular expression ``foo$`` matches matches both 'foo' and 'foobar', while the regular expression ``foo$`` matches
only 'foo'. More interestingly, searching for ``foo.$`` in ``'foo1\nfoo2\n'`` only 'foo'. More interestingly, searching for ``foo.$`` in ``'foo1\nfoo2\n'``
matches 'foo2' normally, but 'foo1' in :const:`MULTILINE` mode. matches 'foo2' normally, but 'foo1' in :const:`MULTILINE` mode; searching for
a single ``$`` in ``'foo\n'`` will find two (empty) matches: one just before
the newline, and one at the end of the string.
``'*'`` ``'*'``
Causes the resulting RE to match 0 or more repetitions of the preceding RE, as Causes the resulting RE to match 0 or more repetitions of the preceding RE, as

View file

@ -117,23 +117,28 @@ if __name__ == '__main__':
# test and demonstrate ability to override methods # test and demonstrate ability to override methods
class Point(namedtuple('Point', 'x y')): class Point(namedtuple('Point', 'x y')):
__slots__ = ()
@property @property
def hypot(self): def hypot(self):
return (self.x ** 2 + self.y ** 2) ** 0.5 return (self.x ** 2 + self.y ** 2) ** 0.5
def __str__(self): def __str__(self):
return 'Point: x=%6.3f y=%6.3f hypot=%6.3f' % (self.x, self.y, self.hypot) return 'Point: x=%6.3f y=%6.3f hypot=%6.3f' % (self.x, self.y, self.hypot)
for p in Point(3,4), Point(14,5), Point(9./7,6): for p in Point(3, 4), Point(14, 5/7.):
print (p) print (p)
class Point(namedtuple('Point', 'x y')): class Point(namedtuple('Point', 'x y')):
'Point class with optimized _make() and _replace() without error-checking' 'Point class with optimized _make() and _replace() without error-checking'
__slots__ = ()
_make = classmethod(tuple.__new__) _make = classmethod(tuple.__new__)
def _replace(self, _map=map, **kwds): def _replace(self, _map=map, **kwds):
return self._make(_map(kwds.get, ('x', 'y'), self)) return self._make(_map(kwds.get, ('x', 'y'), self))
print(Point(11, 22)._replace(x=100)) print(Point(11, 22)._replace(x=100))
Point3D = namedtuple('Point3D', Point._fields + ('z',))
print(Point3D.__doc__)
import doctest import doctest
TestResults = namedtuple('TestResults', 'failed attempted') TestResults = namedtuple('TestResults', 'failed attempted')
print(TestResults(*doctest.testmod())) print(TestResults(*doctest.testmod()))

View file

@ -137,6 +137,12 @@ __all__ = [
import numbers as _numbers import numbers as _numbers
import copy as _copy import copy as _copy
try:
from collections import namedtuple as _namedtuple
DecimalTuple = _namedtuple('DecimalTuple', 'sign digits exponent')
except ImportError:
DecimalTuple = lambda *args: args
# Rounding # Rounding
ROUND_DOWN = 'ROUND_DOWN' ROUND_DOWN = 'ROUND_DOWN'
ROUND_HALF_UP = 'ROUND_HALF_UP' ROUND_HALF_UP = 'ROUND_HALF_UP'
@ -841,7 +847,7 @@ class Decimal(_numbers.Real, _numbers.Inexact):
To show the internals exactly as they are. To show the internals exactly as they are.
""" """
return (self._sign, tuple(map(int, self._int)), self._exp) return DecimalTuple(self._sign, tuple(map(int, self._int)), self._exp)
def __repr__(self): def __repr__(self):
"""Represents the number as an instance of Decimal.""" """Represents the number as an instance of Decimal."""

View file

@ -30,9 +30,12 @@ Class HtmlDiff:
__all__ = ['get_close_matches', 'ndiff', 'restore', 'SequenceMatcher', __all__ = ['get_close_matches', 'ndiff', 'restore', 'SequenceMatcher',
'Differ','IS_CHARACTER_JUNK', 'IS_LINE_JUNK', 'context_diff', 'Differ','IS_CHARACTER_JUNK', 'IS_LINE_JUNK', 'context_diff',
'unified_diff', 'HtmlDiff'] 'unified_diff', 'HtmlDiff', 'Match']
import heapq import heapq
from collections import namedtuple as _namedtuple
Match = _namedtuple('Match', 'a b size')
def _calculate_ratio(matches, length): def _calculate_ratio(matches, length):
if length: if length:
@ -363,7 +366,7 @@ class SequenceMatcher:
>>> s = SequenceMatcher(None, " abcd", "abcd abcd") >>> s = SequenceMatcher(None, " abcd", "abcd abcd")
>>> s.find_longest_match(0, 5, 0, 9) >>> s.find_longest_match(0, 5, 0, 9)
(0, 4, 5) Match(a=0, b=4, size=5)
If isjunk is defined, first the longest matching block is If isjunk is defined, first the longest matching block is
determined as above, but with the additional restriction that no determined as above, but with the additional restriction that no
@ -379,13 +382,13 @@ class SequenceMatcher:
>>> s = SequenceMatcher(lambda x: x==" ", " abcd", "abcd abcd") >>> s = SequenceMatcher(lambda x: x==" ", " abcd", "abcd abcd")
>>> s.find_longest_match(0, 5, 0, 9) >>> s.find_longest_match(0, 5, 0, 9)
(1, 0, 4) Match(a=1, b=0, size=4)
If no blocks match, return (alo, blo, 0). If no blocks match, return (alo, blo, 0).
>>> s = SequenceMatcher(None, "ab", "c") >>> s = SequenceMatcher(None, "ab", "c")
>>> s.find_longest_match(0, 2, 0, 1) >>> s.find_longest_match(0, 2, 0, 1)
(0, 0, 0) Match(a=0, b=0, size=0)
""" """
# CAUTION: stripping common prefix or suffix would be incorrect. # CAUTION: stripping common prefix or suffix would be incorrect.
@ -452,7 +455,7 @@ class SequenceMatcher:
a[besti+bestsize] == b[bestj+bestsize]: a[besti+bestsize] == b[bestj+bestsize]:
bestsize = bestsize + 1 bestsize = bestsize + 1
return besti, bestj, bestsize return Match(besti, bestj, bestsize)
def get_matching_blocks(self): def get_matching_blocks(self):
"""Return list of triples describing matching subsequences. """Return list of triples describing matching subsequences.
@ -469,8 +472,8 @@ class SequenceMatcher:
triple with n==0. triple with n==0.
>>> s = SequenceMatcher(None, "abxcd", "abcd") >>> s = SequenceMatcher(None, "abxcd", "abcd")
>>> s.get_matching_blocks() >>> list(s.get_matching_blocks())
[(0, 0, 2), (3, 2, 2), (5, 4, 0)] [Match(a=0, b=0, size=2), Match(a=3, b=2, size=2), Match(a=5, b=4, size=0)]
""" """
if self.matching_blocks is not None: if self.matching_blocks is not None:
@ -523,7 +526,7 @@ class SequenceMatcher:
non_adjacent.append( (la, lb, 0) ) non_adjacent.append( (la, lb, 0) )
self.matching_blocks = non_adjacent self.matching_blocks = non_adjacent
return self.matching_blocks return map(Match._make, self.matching_blocks)
def get_opcodes(self): def get_opcodes(self):
"""Return list of 5-tuples describing how to turn a into b. """Return list of 5-tuples describing how to turn a into b.

View file

@ -99,6 +99,9 @@ import sys, traceback, inspect, linecache, os, re
import unittest, difflib, pdb, tempfile import unittest, difflib, pdb, tempfile
import warnings import warnings
from io import StringIO from io import StringIO
from collections import namedtuple
TestResults = namedtuple('TestResults', 'failed attempted')
# There are 4 basic classes: # There are 4 basic classes:
# - Example: a <source, want> pair, plus an intra-docstring line number. # - Example: a <source, want> pair, plus an intra-docstring line number.
@ -1024,10 +1027,10 @@ class DocTestRunner:
>>> tests.sort(key = lambda test: test.name) >>> tests.sort(key = lambda test: test.name)
>>> for test in tests: >>> for test in tests:
... print(test.name, '->', runner.run(test)) ... print(test.name, '->', runner.run(test))
_TestClass -> (0, 2) _TestClass -> TestResults(failed=0, attempted=2)
_TestClass.__init__ -> (0, 2) _TestClass.__init__ -> TestResults(failed=0, attempted=2)
_TestClass.get -> (0, 2) _TestClass.get -> TestResults(failed=0, attempted=2)
_TestClass.square -> (0, 1) _TestClass.square -> TestResults(failed=0, attempted=1)
The `summarize` method prints a summary of all the test cases that The `summarize` method prints a summary of all the test cases that
have been run by the runner, and returns an aggregated `(f, t)` have been run by the runner, and returns an aggregated `(f, t)`
@ -1042,7 +1045,7 @@ class DocTestRunner:
7 tests in 4 items. 7 tests in 4 items.
7 passed and 0 failed. 7 passed and 0 failed.
Test passed. Test passed.
(0, 7) TestResults(failed=0, attempted=7)
The aggregated number of tried examples and failed examples is The aggregated number of tried examples and failed examples is
also available via the `tries` and `failures` attributes: also available via the `tries` and `failures` attributes:
@ -1285,7 +1288,7 @@ class DocTestRunner:
# Record and return the number of failures and tries. # Record and return the number of failures and tries.
self.__record_outcome(test, failures, tries) self.__record_outcome(test, failures, tries)
return failures, tries return TestResults(failures, tries)
def __record_outcome(self, test, f, t): def __record_outcome(self, test, f, t):
""" """
@ -1417,7 +1420,7 @@ class DocTestRunner:
print("***Test Failed***", totalf, "failures.") print("***Test Failed***", totalf, "failures.")
elif verbose: elif verbose:
print("Test passed.") print("Test passed.")
return totalf, totalt return TestResults(totalf, totalt)
#///////////////////////////////////////////////////////////////// #/////////////////////////////////////////////////////////////////
# Backward compatibility cruft to maintain doctest.master. # Backward compatibility cruft to maintain doctest.master.
@ -1688,7 +1691,7 @@ class DebugRunner(DocTestRunner):
... ''', {}, 'foo', 'foo.py', 0) ... ''', {}, 'foo', 'foo.py', 0)
>>> runner.run(test) >>> runner.run(test)
(0, 1) TestResults(failed=0, attempted=1)
>>> test.globs >>> test.globs
{} {}
@ -1818,7 +1821,7 @@ def testmod(m=None, name=None, globs=None, verbose=None,
else: else:
master.merge(runner) master.merge(runner)
return runner.failures, runner.tries return TestResults(runner.failures, runner.tries)
def testfile(filename, module_relative=True, name=None, package=None, def testfile(filename, module_relative=True, name=None, package=None,
globs=None, verbose=None, report=True, optionflags=0, globs=None, verbose=None, report=True, optionflags=0,
@ -1939,7 +1942,7 @@ def testfile(filename, module_relative=True, name=None, package=None,
else: else:
master.merge(runner) master.merge(runner)
return runner.failures, runner.tries return TestResults(runner.failures, runner.tries)
def run_docstring_examples(f, globs, verbose=False, name="NoName", def run_docstring_examples(f, globs, verbose=False, name="NoName",
compileflags=None, optionflags=0): compileflags=None, optionflags=0):
@ -1998,7 +2001,7 @@ class Tester:
(f,t) = self.testrunner.run(test) (f,t) = self.testrunner.run(test)
if self.verbose: if self.verbose:
print(f, "of", t, "examples failed in string", name) print(f, "of", t, "examples failed in string", name)
return (f,t) return TestResults(f,t)
def rundoc(self, object, name=None, module=None): def rundoc(self, object, name=None, module=None):
f = t = 0 f = t = 0
@ -2007,7 +2010,7 @@ class Tester:
for test in tests: for test in tests:
(f2, t2) = self.testrunner.run(test) (f2, t2) = self.testrunner.run(test)
(f,t) = (f+f2, t+t2) (f,t) = (f+f2, t+t2)
return (f,t) return TestResults(f,t)
def rundict(self, d, name, module=None): def rundict(self, d, name, module=None):
import types import types

View file

@ -31,6 +31,7 @@ __date__ = '1 Jan 2001'
import sys, os, types, re, dis, imp, tokenize, linecache import sys, os, types, re, dis, imp, tokenize, linecache
from operator import attrgetter from operator import attrgetter
from collections import namedtuple
# ----------------------------------------------------------- type-checking # ----------------------------------------------------------- type-checking
def ismodule(object): def ismodule(object):
@ -208,6 +209,8 @@ def getmembers(object, predicate=None):
results.sort() results.sort()
return results return results
Attribute = namedtuple('Attribute', 'name kind defining_class object')
def classify_class_attrs(cls): def classify_class_attrs(cls):
"""Return list of attribute-descriptor tuples. """Return list of attribute-descriptor tuples.
@ -274,7 +277,7 @@ def classify_class_attrs(cls):
else: else:
kind = "data" kind = "data"
result.append((name, kind, homecls, obj)) result.append(Attribute(name, kind, homecls, obj))
return result return result
@ -362,6 +365,8 @@ def getfile(object):
raise TypeError('arg is not a module, class, method, ' raise TypeError('arg is not a module, class, method, '
'function, traceback, frame, or code object') 'function, traceback, frame, or code object')
ModuleInfo = namedtuple('ModuleInfo', 'name suffix mode module_type')
def getmoduleinfo(path): def getmoduleinfo(path):
"""Get the module name, suffix, mode, and module type for a given file.""" """Get the module name, suffix, mode, and module type for a given file."""
filename = os.path.basename(path) filename = os.path.basename(path)
@ -370,7 +375,7 @@ def getmoduleinfo(path):
suffixes.sort() # try longest suffixes first, in case they overlap suffixes.sort() # try longest suffixes first, in case they overlap
for neglen, suffix, mode, mtype in suffixes: for neglen, suffix, mode, mtype in suffixes:
if filename[neglen:] == suffix: if filename[neglen:] == suffix:
return filename[:neglen], suffix, mode, mtype return ModuleInfo(filename[:neglen], suffix, mode, mtype)
def getmodulename(path): def getmodulename(path):
"""Return the module name for a given file, or None.""" """Return the module name for a given file, or None."""
@ -668,6 +673,8 @@ def getclasstree(classes, unique=0):
# These constants are from Python's compile.h. # These constants are from Python's compile.h.
CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS = 1, 2, 4, 8 CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS = 1, 2, 4, 8
Arguments = namedtuple('Arguments', 'args, varargs, varkw')
def getargs(co): def getargs(co):
"""Get information about the arguments accepted by a code object. """Get information about the arguments accepted by a code object.
@ -676,7 +683,7 @@ def getargs(co):
lists. Keyword-only arguments are appended. 'varargs' and 'varkw' lists. Keyword-only arguments are appended. 'varargs' and 'varkw'
are the names of the * and ** arguments or None.""" are the names of the * and ** arguments or None."""
args, varargs, kwonlyargs, varkw = _getfullargs(co) args, varargs, kwonlyargs, varkw = _getfullargs(co)
return args + kwonlyargs, varargs, varkw return Arguments(args + kwonlyargs, varargs, varkw)
def _getfullargs(co): def _getfullargs(co):
"""Get information about the arguments accepted by a code object. """Get information about the arguments accepted by a code object.
@ -706,6 +713,9 @@ def _getfullargs(co):
varkw = co.co_varnames[nargs] varkw = co.co_varnames[nargs]
return args, varargs, kwonlyargs, varkw return args, varargs, kwonlyargs, varkw
ArgSpec = namedtuple('ArgSpec', 'args varargs keywords defaults')
def getargspec(func): def getargspec(func):
"""Get the names and default values of a function's arguments. """Get the names and default values of a function's arguments.
@ -725,7 +735,10 @@ def getargspec(func):
if kwonlyargs or ann: if kwonlyargs or ann:
raise ValueError("Function has keyword-only arguments or annotations" raise ValueError("Function has keyword-only arguments or annotations"
", use getfullargspec() API which can support them") ", use getfullargspec() API which can support them")
return (args, varargs, varkw, defaults) return ArgSpec(args, varargs, varkw, defaults)
FullArgSpec = namedtuple('FullArgSpec',
'args, varargs, varkw, defaults, kwonlyargs, kwdefaults, annotations')
def getfullargspec(func): def getfullargspec(func):
"""Get the names and default values of a function's arguments. """Get the names and default values of a function's arguments.
@ -747,9 +760,11 @@ def getfullargspec(func):
if not isfunction(func): if not isfunction(func):
raise TypeError('arg is not a Python function') raise TypeError('arg is not a Python function')
args, varargs, kwonlyargs, varkw = _getfullargs(func.__code__) args, varargs, kwonlyargs, varkw = _getfullargs(func.__code__)
return (args, varargs, varkw, func.__defaults__, return FullArgSpec(args, varargs, varkw, func.__defaults__,
kwonlyargs, func.__kwdefaults__, func.__annotations__) kwonlyargs, func.__kwdefaults__, func.__annotations__)
ArgInfo = namedtuple('ArgInfo', 'args varargs keywords locals')
def getargvalues(frame): def getargvalues(frame):
"""Get information about arguments passed into a particular frame. """Get information about arguments passed into a particular frame.
@ -859,6 +874,9 @@ def formatargvalues(args, varargs, varkw, locals,
return '(' + ', '.join(specs) + ')' return '(' + ', '.join(specs) + ')'
# -------------------------------------------------- stack frame extraction # -------------------------------------------------- stack frame extraction
Traceback = namedtuple('Traceback', 'filename lineno function code_context index')
def getframeinfo(frame, context=1): def getframeinfo(frame, context=1):
"""Get information about a frame or traceback object. """Get information about a frame or traceback object.
@ -890,7 +908,7 @@ def getframeinfo(frame, context=1):
else: else:
lines = index = None lines = index = None
return (filename, lineno, frame.f_code.co_name, lines, index) return Traceback(filename, lineno, frame.f_code.co_name, lines, index)
def getlineno(frame): def getlineno(frame):
"""Get the line number from a frame object, allowing for optimization.""" """Get the line number from a frame object, allowing for optimization."""

View file

@ -1,6 +1,6 @@
"""Unit tests for collections.py.""" """Unit tests for collections.py."""
import unittest import unittest, doctest
from test import test_support from test import test_support
from collections import namedtuple from collections import namedtuple
from collections import Hashable, Iterable, Iterator from collections import Hashable, Iterable, Iterator
@ -316,10 +316,12 @@ class TestCollectionABCs(unittest.TestCase):
self.failUnless(issubclass(sample, MutableSequence)) self.failUnless(issubclass(sample, MutableSequence))
self.failIf(issubclass(str, MutableSequence)) self.failIf(issubclass(str, MutableSequence))
import doctest, collections
NamedTupleDocs = doctest.DocTestSuite(module=collections)
def test_main(verbose=None): def test_main(verbose=None):
import collections as CollectionsModule import collections as CollectionsModule
test_classes = [TestNamedTuple, TestOneTrickPonyABCs, TestCollectionABCs] test_classes = [TestNamedTuple, NamedTupleDocs, TestOneTrickPonyABCs, TestCollectionABCs]
test_support.run_unittest(*test_classes) test_support.run_unittest(*test_classes)
test_support.run_doctest(CollectionsModule, verbose) test_support.run_doctest(CollectionsModule, verbose)

View file

@ -658,7 +658,7 @@ given DocTest case in a given namespace (globs). It returns a tuple
of tried tests. of tried tests.
>>> doctest.DocTestRunner(verbose=False).run(test) >>> doctest.DocTestRunner(verbose=False).run(test)
(0, 3) TestResults(failed=0, attempted=3)
If any example produces incorrect output, then the test runner reports If any example produces incorrect output, then the test runner reports
the failure and proceeds to the next example: the failure and proceeds to the next example:
@ -695,7 +695,7 @@ the failure and proceeds to the next example:
Expecting: Expecting:
6 6
ok ok
(1, 3) TestResults(failed=1, attempted=3)
""" """
def verbose_flag(): r""" def verbose_flag(): r"""
The `verbose` flag makes the test runner generate more detailed The `verbose` flag makes the test runner generate more detailed
@ -726,7 +726,7 @@ output:
Expecting: Expecting:
6 6
ok ok
(0, 3) TestResults(failed=0, attempted=3)
If the `verbose` flag is unspecified, then the output will be verbose If the `verbose` flag is unspecified, then the output will be verbose
iff `-v` appears in sys.argv: iff `-v` appears in sys.argv:
@ -737,7 +737,7 @@ iff `-v` appears in sys.argv:
>>> # If -v does not appear in sys.argv, then output isn't verbose. >>> # If -v does not appear in sys.argv, then output isn't verbose.
>>> sys.argv = ['test'] >>> sys.argv = ['test']
>>> doctest.DocTestRunner().run(test) >>> doctest.DocTestRunner().run(test)
(0, 3) TestResults(failed=0, attempted=3)
>>> # If -v does appear in sys.argv, then output is verbose. >>> # If -v does appear in sys.argv, then output is verbose.
>>> sys.argv = ['test', '-v'] >>> sys.argv = ['test', '-v']
@ -756,7 +756,7 @@ iff `-v` appears in sys.argv:
Expecting: Expecting:
6 6
ok ok
(0, 3) TestResults(failed=0, attempted=3)
>>> # Restore sys.argv >>> # Restore sys.argv
>>> sys.argv = old_argv >>> sys.argv = old_argv
@ -780,7 +780,7 @@ replaced with any other string:
... ''' ... '''
>>> test = doctest.DocTestFinder().find(f)[0] >>> test = doctest.DocTestFinder().find(f)[0]
>>> doctest.DocTestRunner(verbose=False).run(test) >>> doctest.DocTestRunner(verbose=False).run(test)
(0, 2) TestResults(failed=0, attempted=2)
An example may not generate output before it raises an exception; if An example may not generate output before it raises an exception; if
it does, then the traceback message will not be recognized as it does, then the traceback message will not be recognized as
@ -805,7 +805,7 @@ unexpected exception:
Exception raised: Exception raised:
... ...
ZeroDivisionError: integer division or modulo by zero ZeroDivisionError: integer division or modulo by zero
(1, 2) TestResults(failed=1, attempted=2)
Exception messages may contain newlines: Exception messages may contain newlines:
@ -819,7 +819,7 @@ Exception messages may contain newlines:
... ''' ... '''
>>> test = doctest.DocTestFinder().find(f)[0] >>> test = doctest.DocTestFinder().find(f)[0]
>>> doctest.DocTestRunner(verbose=False).run(test) >>> doctest.DocTestRunner(verbose=False).run(test)
(0, 1) TestResults(failed=0, attempted=1)
If an exception is expected, but an exception with the wrong type or If an exception is expected, but an exception with the wrong type or
message is raised, then it is reported as a failure: message is raised, then it is reported as a failure:
@ -844,7 +844,7 @@ message is raised, then it is reported as a failure:
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValueError: message ValueError: message
(1, 1) TestResults(failed=1, attempted=1)
However, IGNORE_EXCEPTION_DETAIL can be used to allow a mismatch in the However, IGNORE_EXCEPTION_DETAIL can be used to allow a mismatch in the
detail: detail:
@ -857,7 +857,7 @@ detail:
... ''' ... '''
>>> test = doctest.DocTestFinder().find(f)[0] >>> test = doctest.DocTestFinder().find(f)[0]
>>> doctest.DocTestRunner(verbose=False).run(test) >>> doctest.DocTestRunner(verbose=False).run(test)
(0, 1) TestResults(failed=0, attempted=1)
But IGNORE_EXCEPTION_DETAIL does not allow a mismatch in the exception type: But IGNORE_EXCEPTION_DETAIL does not allow a mismatch in the exception type:
@ -881,7 +881,7 @@ But IGNORE_EXCEPTION_DETAIL does not allow a mismatch in the exception type:
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValueError: message ValueError: message
(1, 1) TestResults(failed=1, attempted=1)
If an exception is raised but not expected, then it is reported as an If an exception is raised but not expected, then it is reported as an
unexpected exception: unexpected exception:
@ -902,7 +902,7 @@ unexpected exception:
Traceback (most recent call last): Traceback (most recent call last):
... ...
ZeroDivisionError: integer division or modulo by zero ZeroDivisionError: integer division or modulo by zero
(1, 1) TestResults(failed=1, attempted=1)
""" """
def optionflags(): r""" def optionflags(): r"""
Tests of `DocTestRunner`'s option flag handling. Tests of `DocTestRunner`'s option flag handling.
@ -921,7 +921,7 @@ and 1/0:
>>> # Without the flag: >>> # Without the flag:
>>> test = doctest.DocTestFinder().find(f)[0] >>> test = doctest.DocTestFinder().find(f)[0]
>>> doctest.DocTestRunner(verbose=False).run(test) >>> doctest.DocTestRunner(verbose=False).run(test)
(0, 1) TestResults(failed=0, attempted=1)
>>> # With the flag: >>> # With the flag:
>>> test = doctest.DocTestFinder().find(f)[0] >>> test = doctest.DocTestFinder().find(f)[0]
@ -936,7 +936,7 @@ and 1/0:
1 1
Got: Got:
True True
(1, 1) TestResults(failed=1, attempted=1)
The DONT_ACCEPT_BLANKLINE flag disables the match between blank lines The DONT_ACCEPT_BLANKLINE flag disables the match between blank lines
and the '<BLANKLINE>' marker: and the '<BLANKLINE>' marker:
@ -947,7 +947,7 @@ and the '<BLANKLINE>' marker:
>>> # Without the flag: >>> # Without the flag:
>>> test = doctest.DocTestFinder().find(f)[0] >>> test = doctest.DocTestFinder().find(f)[0]
>>> doctest.DocTestRunner(verbose=False).run(test) >>> doctest.DocTestRunner(verbose=False).run(test)
(0, 1) TestResults(failed=0, attempted=1)
>>> # With the flag: >>> # With the flag:
>>> test = doctest.DocTestFinder().find(f)[0] >>> test = doctest.DocTestFinder().find(f)[0]
@ -966,7 +966,7 @@ and the '<BLANKLINE>' marker:
a a
<BLANKLINE> <BLANKLINE>
b b
(1, 1) TestResults(failed=1, attempted=1)
The NORMALIZE_WHITESPACE flag causes all sequences of whitespace to be The NORMALIZE_WHITESPACE flag causes all sequences of whitespace to be
treated as equal: treated as equal:
@ -987,13 +987,13 @@ treated as equal:
3 3
Got: Got:
1 2 3 1 2 3
(1, 1) TestResults(failed=1, attempted=1)
>>> # With the flag: >>> # With the flag:
>>> test = doctest.DocTestFinder().find(f)[0] >>> test = doctest.DocTestFinder().find(f)[0]
>>> flags = doctest.NORMALIZE_WHITESPACE >>> flags = doctest.NORMALIZE_WHITESPACE
>>> doctest.DocTestRunner(verbose=False, optionflags=flags).run(test) >>> doctest.DocTestRunner(verbose=False, optionflags=flags).run(test)
(0, 1) TestResults(failed=0, attempted=1)
An example from the docs: An example from the docs:
>>> print(list(range(20))) #doctest: +NORMALIZE_WHITESPACE >>> print(list(range(20))) #doctest: +NORMALIZE_WHITESPACE
@ -1018,13 +1018,13 @@ output to match any substring in the actual output:
[0, 1, 2, ..., 14] [0, 1, 2, ..., 14]
Got: Got:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
(1, 1) TestResults(failed=1, attempted=1)
>>> # With the flag: >>> # With the flag:
>>> test = doctest.DocTestFinder().find(f)[0] >>> test = doctest.DocTestFinder().find(f)[0]
>>> flags = doctest.ELLIPSIS >>> flags = doctest.ELLIPSIS
>>> doctest.DocTestRunner(verbose=False, optionflags=flags).run(test) >>> doctest.DocTestRunner(verbose=False, optionflags=flags).run(test)
(0, 1) TestResults(failed=0, attempted=1)
... also matches nothing: ... also matches nothing:
@ -1109,7 +1109,7 @@ and actual outputs to be displayed using a unified diff:
e e
f f
g g
(1, 1) TestResults(failed=1, attempted=1)
>>> # With the flag: >>> # With the flag:
>>> test = doctest.DocTestFinder().find(f)[0] >>> test = doctest.DocTestFinder().find(f)[0]
@ -1131,7 +1131,7 @@ and actual outputs to be displayed using a unified diff:
f f
g g
-h -h
(1, 1) TestResults(failed=1, attempted=1)
The REPORT_CDIFF flag causes failures that involve multi-line expected The REPORT_CDIFF flag causes failures that involve multi-line expected
and actual outputs to be displayed using a context diff: and actual outputs to be displayed using a context diff:
@ -1163,7 +1163,7 @@ and actual outputs to be displayed using a context diff:
+ e + e
f f
g g
(1, 1) TestResults(failed=1, attempted=1)
The REPORT_NDIFF flag causes failures to use the difflib.Differ algorithm The REPORT_NDIFF flag causes failures to use the difflib.Differ algorithm
@ -1188,7 +1188,7 @@ marking, as well as interline differences.
? ^ ? ^
+ a b c d e f g h i j k l m + a b c d e f g h i j k l m
? + ++ ^ ? + ++ ^
(1, 1) TestResults(failed=1, attempted=1)
The REPORT_ONLY_FIRST_FAILURE supresses result output after the first The REPORT_ONLY_FIRST_FAILURE supresses result output after the first
failing example: failing example:
@ -1218,7 +1218,7 @@ failing example:
200 200
Got: Got:
2 2
(3, 5) TestResults(failed=3, attempted=5)
However, output from `report_start` is not supressed: However, output from `report_start` is not supressed:
@ -1241,7 +1241,7 @@ However, output from `report_start` is not supressed:
200 200
Got: Got:
2 2
(3, 5) TestResults(failed=3, attempted=5)
For the purposes of REPORT_ONLY_FIRST_FAILURE, unexpected exceptions For the purposes of REPORT_ONLY_FIRST_FAILURE, unexpected exceptions
count as failures: count as failures:
@ -1270,7 +1270,7 @@ count as failures:
Exception raised: Exception raised:
... ...
ValueError: 2 ValueError: 2
(3, 5) TestResults(failed=3, attempted=5)
New option flags can also be registered, via register_optionflag(). Here New option flags can also be registered, via register_optionflag(). Here
we reach into doctest's internals a bit. we reach into doctest's internals a bit.
@ -1319,7 +1319,7 @@ example with a comment of the form ``# doctest: +OPTION``:
[0, 1, ..., 9] [0, 1, ..., 9]
Got: Got:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
(1, 2) TestResults(failed=1, attempted=2)
To turn an option off for an example, follow that example with a To turn an option off for an example, follow that example with a
comment of the form ``# doctest: -OPTION``: comment of the form ``# doctest: -OPTION``:
@ -1344,7 +1344,7 @@ comment of the form ``# doctest: -OPTION``:
[0, 1, ..., 9] [0, 1, ..., 9]
Got: Got:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
(1, 2) TestResults(failed=1, attempted=2)
Option directives affect only the example that they appear with; they Option directives affect only the example that they appear with; they
do not change the options for surrounding examples: do not change the options for surrounding examples:
@ -1378,7 +1378,7 @@ do not change the options for surrounding examples:
[0, 1, ..., 9] [0, 1, ..., 9]
Got: Got:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
(2, 3) TestResults(failed=2, attempted=3)
Multiple options may be modified by a single option directive. They Multiple options may be modified by a single option directive. They
may be separated by whitespace, commas, or both: may be separated by whitespace, commas, or both:
@ -1401,7 +1401,7 @@ may be separated by whitespace, commas, or both:
[0, 1, ..., 9] [0, 1, ..., 9]
Got: Got:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
(1, 2) TestResults(failed=1, attempted=2)
>>> def f(x): r''' >>> def f(x): r'''
... >>> print(list(range(10))) # Should fail ... >>> print(list(range(10))) # Should fail
@ -1421,7 +1421,7 @@ may be separated by whitespace, commas, or both:
[0, 1, ..., 9] [0, 1, ..., 9]
Got: Got:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
(1, 2) TestResults(failed=1, attempted=2)
>>> def f(x): r''' >>> def f(x): r'''
... >>> print(list(range(10))) # Should fail ... >>> print(list(range(10))) # Should fail
@ -1441,7 +1441,7 @@ may be separated by whitespace, commas, or both:
[0, 1, ..., 9] [0, 1, ..., 9]
Got: Got:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
(1, 2) TestResults(failed=1, attempted=2)
The option directive may be put on the line following the source, as The option directive may be put on the line following the source, as
long as a continuation prompt is used: long as a continuation prompt is used:
@ -1453,7 +1453,7 @@ long as a continuation prompt is used:
... ''' ... '''
>>> test = doctest.DocTestFinder().find(f)[0] >>> test = doctest.DocTestFinder().find(f)[0]
>>> doctest.DocTestRunner(verbose=False).run(test) >>> doctest.DocTestRunner(verbose=False).run(test)
(0, 1) TestResults(failed=0, attempted=1)
For examples with multi-line source, the option directive may appear For examples with multi-line source, the option directive may appear
at the end of any line: at the end of any line:
@ -1469,7 +1469,7 @@ at the end of any line:
... ''' ... '''
>>> test = doctest.DocTestFinder().find(f)[0] >>> test = doctest.DocTestFinder().find(f)[0]
>>> doctest.DocTestRunner(verbose=False).run(test) >>> doctest.DocTestRunner(verbose=False).run(test)
(0, 2) TestResults(failed=0, attempted=2)
If more than one line of an example with multi-line source has an If more than one line of an example with multi-line source has an
option directive, then they are combined: option directive, then they are combined:
@ -1482,7 +1482,7 @@ option directive, then they are combined:
... ''' ... '''
>>> test = doctest.DocTestFinder().find(f)[0] >>> test = doctest.DocTestFinder().find(f)[0]
>>> doctest.DocTestRunner(verbose=False).run(test) >>> doctest.DocTestRunner(verbose=False).run(test)
(0, 1) TestResults(failed=0, attempted=1)
It is an error to have a comment of the form ``# doctest:`` that is It is an error to have a comment of the form ``# doctest:`` that is
*not* followed by words of the form ``+OPTION`` or ``-OPTION``, where *not* followed by words of the form ``+OPTION`` or ``-OPTION``, where
@ -1616,7 +1616,7 @@ def test_pdb_set_trace():
(Pdb) print(x) (Pdb) print(x)
42 42
(Pdb) continue (Pdb) continue
(0, 2) TestResults(failed=0, attempted=2)
You can also put pdb.set_trace in a function called from a test: You can also put pdb.set_trace in a function called from a test:
@ -1652,7 +1652,7 @@ def test_pdb_set_trace():
(Pdb) print(x) (Pdb) print(x)
1 1
(Pdb) continue (Pdb) continue
(0, 2) TestResults(failed=0, attempted=2)
During interactive debugging, source code is shown, even for During interactive debugging, source code is shown, even for
doctest examples: doctest examples:
@ -1709,7 +1709,7 @@ def test_pdb_set_trace():
Expected nothing Expected nothing
Got: Got:
9 9
(1, 3) TestResults(failed=1, attempted=3)
""" """
def test_pdb_set_trace_nested(): def test_pdb_set_trace_nested():
@ -1795,7 +1795,7 @@ def test_pdb_set_trace_nested():
(Pdb) print(foo) (Pdb) print(foo)
*** NameError: NameError("name 'foo' is not defined",) *** NameError: NameError("name 'foo' is not defined",)
(Pdb) continue (Pdb) continue
(0, 2) TestResults(failed=0, attempted=2)
""" """
def test_DocTestSuite(): def test_DocTestSuite():
@ -2156,7 +2156,7 @@ calling module. The return value is (#failures, #tests).
1 items had failures: 1 items had failures:
1 of 2 in test_doctest.txt 1 of 2 in test_doctest.txt
***Test Failed*** 1 failures. ***Test Failed*** 1 failures.
(1, 2) TestResults(failed=1, attempted=2)
>>> doctest.master = None # Reset master. >>> doctest.master = None # Reset master.
(Note: we'll be clearing doctest.master after each call to (Note: we'll be clearing doctest.master after each call to
@ -2167,7 +2167,7 @@ Globals may be specified with the `globs` and `extraglobs` parameters:
>>> globs = {'favorite_color': 'blue'} >>> globs = {'favorite_color': 'blue'}
>>> doctest.testfile('test_doctest.txt', globs=globs) >>> doctest.testfile('test_doctest.txt', globs=globs)
(0, 2) TestResults(failed=0, attempted=2)
>>> doctest.master = None # Reset master. >>> doctest.master = None # Reset master.
>>> extraglobs = {'favorite_color': 'red'} >>> extraglobs = {'favorite_color': 'red'}
@ -2185,7 +2185,7 @@ Globals may be specified with the `globs` and `extraglobs` parameters:
1 items had failures: 1 items had failures:
1 of 2 in test_doctest.txt 1 of 2 in test_doctest.txt
***Test Failed*** 1 failures. ***Test Failed*** 1 failures.
(1, 2) TestResults(failed=1, attempted=2)
>>> doctest.master = None # Reset master. >>> doctest.master = None # Reset master.
The file may be made relative to a given module or package, using the The file may be made relative to a given module or package, using the
@ -2193,7 +2193,7 @@ optional `module_relative` parameter:
>>> doctest.testfile('test_doctest.txt', globs=globs, >>> doctest.testfile('test_doctest.txt', globs=globs,
... module_relative='test') ... module_relative='test')
(0, 2) TestResults(failed=0, attempted=2)
>>> doctest.master = None # Reset master. >>> doctest.master = None # Reset master.
Verbosity can be increased with the optional `verbose` paremter: Verbosity can be increased with the optional `verbose` paremter:
@ -2219,7 +2219,7 @@ Verbosity can be increased with the optional `verbose` paremter:
2 tests in 1 items. 2 tests in 1 items.
2 passed and 0 failed. 2 passed and 0 failed.
Test passed. Test passed.
(0, 2) TestResults(failed=0, attempted=2)
>>> doctest.master = None # Reset master. >>> doctest.master = None # Reset master.
The name of the test may be specified with the optional `name` The name of the test may be specified with the optional `name`
@ -2230,7 +2230,7 @@ parameter:
********************************************************************** **********************************************************************
File "...", line 6, in newname File "...", line 6, in newname
... ...
(1, 2) TestResults(failed=1, attempted=2)
>>> doctest.master = None # Reset master. >>> doctest.master = None # Reset master.
The summary report may be supressed with the optional `report` The summary report may be supressed with the optional `report`
@ -2245,7 +2245,7 @@ parameter:
Exception raised: Exception raised:
... ...
NameError: name 'favorite_color' is not defined NameError: name 'favorite_color' is not defined
(1, 2) TestResults(failed=1, attempted=2)
>>> doctest.master = None # Reset master. >>> doctest.master = None # Reset master.
The optional keyword argument `raise_on_error` can be used to raise an The optional keyword argument `raise_on_error` can be used to raise an
@ -2277,11 +2277,11 @@ using the optional keyword argument `encoding`:
1 items had failures: 1 items had failures:
2 of 2 in test_doctest4.txt 2 of 2 in test_doctest4.txt
***Test Failed*** 2 failures. ***Test Failed*** 2 failures.
(2, 2) TestResults(failed=2, attempted=2)
>>> doctest.master = None # Reset master. >>> doctest.master = None # Reset master.
>>> doctest.testfile('test_doctest4.txt', encoding='utf-8') >>> doctest.testfile('test_doctest4.txt', encoding='utf-8')
(0, 2) TestResults(failed=0, attempted=2)
>>> doctest.master = None # Reset master. >>> doctest.master = None # Reset master.
""" """
@ -2311,15 +2311,15 @@ Expected:
42 42
Got: Got:
84 84
(1, 2) TestResults(failed=1, attempted=2)
>>> t.runstring(">>> x = x * 2\n>>> print(x)\n84\n", 'example2') >>> t.runstring(">>> x = x * 2\n>>> print(x)\n84\n", 'example2')
(0, 2) TestResults(failed=0, attempted=2)
>>> t.summarize() >>> t.summarize()
********************************************************************** **********************************************************************
1 items had failures: 1 items had failures:
1 of 2 in XYZ 1 of 2 in XYZ
***Test Failed*** 1 failures. ***Test Failed*** 1 failures.
(1, 4) TestResults(failed=1, attempted=4)
>>> t.summarize(verbose=1) >>> t.summarize(verbose=1)
1 items passed all tests: 1 items passed all tests:
2 tests in example2 2 tests in example2
@ -2329,7 +2329,7 @@ Got:
4 tests in 2 items. 4 tests in 2 items.
3 passed and 1 failed. 3 passed and 1 failed.
***Test Failed*** 1 failures. ***Test Failed*** 1 failures.
(1, 4) TestResults(failed=1, attempted=4)
""" """
def old_test2(): r""" def old_test2(): r"""
@ -2353,7 +2353,7 @@ def old_test2(): r"""
3 3
ok ok
0 of 2 examples failed in string Example 0 of 2 examples failed in string Example
(0, 2) TestResults(failed=0, attempted=2)
""" """
def old_test3(): r""" def old_test3(): r"""
@ -2366,7 +2366,7 @@ def old_test3(): r"""
... return 32 ... return 32
... ...
>>> t.rundoc(_f) # expect 0 failures in 1 example >>> t.rundoc(_f) # expect 0 failures in 1 example
(0, 1) TestResults(failed=0, attempted=1)
""" """
def old_test4(): """ def old_test4(): """
@ -2396,19 +2396,19 @@ def old_test4(): """
>>> from doctest import Tester >>> from doctest import Tester
>>> t = Tester(globs={}, verbose=0) >>> t = Tester(globs={}, verbose=0)
>>> t.rundict(m1.__dict__, "rundict_test", m1) # f2 and g2 and h2 skipped >>> t.rundict(m1.__dict__, "rundict_test", m1) # f2 and g2 and h2 skipped
(0, 4) TestResults(failed=0, attempted=4)
Once more, not excluding stuff outside m1: Once more, not excluding stuff outside m1:
>>> t = Tester(globs={}, verbose=0) >>> t = Tester(globs={}, verbose=0)
>>> t.rundict(m1.__dict__, "rundict_test_pvt") # None are skipped. >>> t.rundict(m1.__dict__, "rundict_test_pvt") # None are skipped.
(0, 8) TestResults(failed=0, attempted=8)
The exclusion of objects from outside the designated module is The exclusion of objects from outside the designated module is
meant to be invoked automagically by testmod. meant to be invoked automagically by testmod.
>>> doctest.testmod(m1, verbose=False) >>> doctest.testmod(m1, verbose=False)
(0, 4) TestResults(failed=0, attempted=4)
""" """
###################################################################### ######################################################################

View file

@ -40,7 +40,7 @@ class PyclbrTest(TestCase):
if key in ignore: return if key in ignore: return
if key not in obj: if key not in obj:
print("***",key, file=sys.stderr) print("***",key, file=sys.stderr)
self.failUnless(key in obj) self.failUnless(key in obj, "%r in %r" % (key, obj))
def assertEqualsOrIgnored(self, a, b, ignore): def assertEqualsOrIgnored(self, a, b, ignore):
''' succeed iff a == b or a in ignore or b in ignore ''' ''' succeed iff a == b or a in ignore or b in ignore '''
@ -140,9 +140,9 @@ class PyclbrTest(TestCase):
def test_easy(self): def test_easy(self):
self.checkModule('pyclbr') self.checkModule('pyclbr')
self.checkModule('doctest') self.checkModule('doctest', ignore=("TestResults",))
self.checkModule('rfc822') self.checkModule('rfc822')
self.checkModule('difflib') self.checkModule('difflib', ignore=("Match",))
def test_decorators(self): def test_decorators(self):
# XXX: See comment in pyclbr_input.py for a test that would fail # XXX: See comment in pyclbr_input.py for a test that would fail

View file

@ -661,6 +661,18 @@ class ReTests(unittest.TestCase):
q = p.match(upper_char) q = p.match(upper_char)
self.assertNotEqual(q, None) self.assertNotEqual(q, None)
def test_dollar_matches_twice(self):
"$ matches the end of string, and just before the terminating \n"
pattern = re.compile('$')
self.assertEqual(pattern.sub('#', 'a\nb\n'), 'a\nb#\n#')
self.assertEqual(pattern.sub('#', 'a\nb\nc'), 'a\nb\nc#')
self.assertEqual(pattern.sub('#', '\n'), '#\n#')
pattern = re.compile('$', re.MULTILINE)
self.assertEqual(pattern.sub('#', 'a\nb\n' ), 'a#\nb#\n#' )
self.assertEqual(pattern.sub('#', 'a\nb\nc'), 'a#\nb#\nc#')
self.assertEqual(pattern.sub('#', '\n'), '#\n#')
def run_re_tests(): def run_re_tests():
from test.re_tests import benchmarks, tests, SUCCEED, FAIL, SYNTAX_ERROR from test.re_tests import benchmarks, tests, SUCCEED, FAIL, SYNTAX_ERROR

View file

@ -980,9 +980,11 @@ new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
#ifdef HAVE_FSTAT #ifdef HAVE_FSTAT
# ifdef __VMS # ifdef __VMS
/* on OpenVMS we must ensure that all bytes are written to the file */ /* on OpenVMS we must ensure that all bytes are written to the file */
fsync(fd); if (fd != -1) {
fsync(fd);
}
# endif # endif
if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) { if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
if (map_size == 0) { if (map_size == 0) {
map_size = st.st_size; map_size = st.st_size;
} else if ((size_t)offset + (size_t)map_size > st.st_size) { } else if ((size_t)offset + (size_t)map_size > st.st_size) {

View file

@ -4097,7 +4097,7 @@ See the socket module for documentation.");
PyMODINIT_FUNC PyMODINIT_FUNC
init_socket(void) init_socket(void)
{ {
PyObject *m, *has_ipv6, *tmp; PyObject *m, *has_ipv6;
if (!os_init()) if (!os_init())
return; return;
@ -4354,7 +4354,10 @@ init_socket(void)
/* for subscriptions */ /* for subscriptions */
PyModule_AddIntConstant(m, "TIPC_SUB_PORTS", TIPC_SUB_PORTS); PyModule_AddIntConstant(m, "TIPC_SUB_PORTS", TIPC_SUB_PORTS);
PyModule_AddIntConstant(m, "TIPC_SUB_SERVICE", TIPC_SUB_SERVICE); PyModule_AddIntConstant(m, "TIPC_SUB_SERVICE", TIPC_SUB_SERVICE);
#ifdef TIPC_SUB_CANCEL
/* doesn't seem to be available everywhere */
PyModule_AddIntConstant(m, "TIPC_SUB_CANCEL", TIPC_SUB_CANCEL); PyModule_AddIntConstant(m, "TIPC_SUB_CANCEL", TIPC_SUB_CANCEL);
#endif
PyModule_AddIntConstant(m, "TIPC_WAIT_FOREVER", TIPC_WAIT_FOREVER); PyModule_AddIntConstant(m, "TIPC_WAIT_FOREVER", TIPC_WAIT_FOREVER);
PyModule_AddIntConstant(m, "TIPC_PUBLISHED", TIPC_PUBLISHED); PyModule_AddIntConstant(m, "TIPC_PUBLISHED", TIPC_PUBLISHED);
PyModule_AddIntConstant(m, "TIPC_WITHDRAWN", TIPC_WITHDRAWN); PyModule_AddIntConstant(m, "TIPC_WITHDRAWN", TIPC_WITHDRAWN);

View file

@ -25,7 +25,7 @@ ROOT = os.path.abspath(os.path.join(here, par, par))
# Windows 2000 compatibility: WINVER 0x0500 # Windows 2000 compatibility: WINVER 0x0500
# http://msdn2.microsoft.com/en-us/library/aa383745.aspx # http://msdn2.microsoft.com/en-us/library/aa383745.aspx
NMAKE = ('nmake /nologo /f %s ' NMAKE = ('nmake /nologo /f %s '
'COMPILERFLAGS=\"-DWINVER=0x0500 -D_WIN32_WINNT=0x0500 -DNTDDI_VERSION=NTDDI_WIN2KSP4\"' 'COMPILERFLAGS=\"-DWINVER=0x0500 -D_WIN32_WINNT=0x0500 -DNTDDI_VERSION=NTDDI_WIN2KSP4\" '
'%s %s') '%s %s')
def nmake(makefile, command="", **kw): def nmake(makefile, command="", **kw):

View file

@ -117,7 +117,7 @@ _tkinter
Build with build_tkinter.py Build with build_tkinter.py
--------------------------- ---------------------------
The PCbuild directory contains a Python script which automates all The PCbuild directory contains a Python script which automates all
steps. Run the script in a Visual Studio 2009 command prompt with steps. Run the script in a Visual Studio 2008 command prompt with
python build_tkinter.py Win32 python build_tkinter.py Win32
@ -312,9 +312,11 @@ Edition.
Profile Guided Optimization Profile Guided Optimization
--------------------------- ---------------------------
The solution has two configurations for PGO. The PGInstrument configuration The solution has two configurations for PGO. The PGInstrument
must be build first. The PGInstrument binaries are lniked against a profiling configuration must be build first. The PGInstrument binaries are
library and contain extra debug information. The PGUpdate configuration takes the profiling data and generates optimized binaries. lniked against a profiling library and contain extra debug
information. The PGUpdate configuration takes the profiling data and
generates optimized binaries.
The build_pgo.bat script automates the creation of optimized binaries. It The build_pgo.bat script automates the creation of optimized binaries. It
creates the PGI files, runs the unit test suite or PyBench with the PGI creates the PGI files, runs the unit test suite or PyBench with the PGI