[Python-checkins] r72477 - in python/branches/py3k: Doc/c-api/init.rst Doc/howto/functional.rst Doc/howto/regex.rst Doc/library/2to3.rst Doc/library/collections.rst Doc/library/decimal.rst Doc/library/json.rst Doc/library/shelve.rst Doc/library/subprocess.rst Doc/library/traceback.rst Doc/library/unittest.rst Doc/whatsnew/2.7.rst Lib/collections.py Lib/logging/__init__.py Lib/test/regrtest.py Lib/test/test_aifc.py Lib/test/test_descr.py Lib/test/test_logging.py Lib/test/test_shutil.py Lib/test/test_unittest.py Lib/unittest.py Modules/_ctypes/libffi.diff

benjamin.peterson python-checkins at python.org
Fri May 8 22:42:27 CEST 2009


Author: benjamin.peterson
Date: Fri May 8 22:42:26 2009
New Revision: 72477
Log:
Merged revisions 70768,71657,71721,71729,71794,71976,72036-72037,72079,72085,72131-72134,72191,72197-72198,72219,72221,72225,72303,72434,72467,72476 via svnmerge from 
svn+ssh://pythondev@svn.python.org/python/trunk
........
 r70768 | andrew.kuchling | 2009年03月30日 17:29:15 -0500 (2009年3月30日) | 1 line
 
 Typo fixes
........
 r71657 | vinay.sajip | 2009年04月16日 14:07:37 -0500 (2009年4月16日) | 1 line
 
 Issue #5768: Change to Unicode output logic and test case for same.
........
 r71721 | benjamin.peterson | 2009年04月18日 14:26:19 -0500 (2009年4月18日) | 1 line
 
 fix a few nits in unittest.py #5771
........
 r71729 | benjamin.peterson | 2009年04月18日 16:03:10 -0500 (2009年4月18日) | 1 line
 
 move test to a more appropiate one
........
 r71794 | vinay.sajip | 2009年04月22日 07:10:47 -0500 (2009年4月22日) | 2 lines
 
 Issue #5170: Fixed regression caused when fixing #5768.
........
 r71976 | mark.dickinson | 2009年04月26日 14:54:55 -0500 (2009年4月26日) | 2 lines
 
 Fix typo in function name
........
 r72036 | georg.brandl | 2009年04月27日 12:04:23 -0500 (2009年4月27日) | 1 line
 
 #5848: small unittest doc patch.
........
 r72037 | georg.brandl | 2009年04月27日 12:09:53 -0500 (2009年4月27日) | 1 line
 
 #5840: dont claim we dont support TLS.
........
 r72079 | r.david.murray | 2009年04月28日 14:02:55 -0500 (2009年4月28日) | 2 lines
 
 Remove spurious 'u'.
........
 r72085 | georg.brandl | 2009年04月28日 16:48:35 -0500 (2009年4月28日) | 1 line
 
 Make the doctests in the docs pass, except for those in the turtle module.
........
 r72131 | benjamin.peterson | 2009年04月29日 17:43:35 -0500 (2009年4月29日) | 1 line
 
 fix test_shutil on ZFS #5676
........
 r72132 | georg.brandl | 2009年04月29日 17:44:07 -0500 (2009年4月29日) | 1 line
 
 #5878: fix repr of re object.
........
 r72133 | benjamin.peterson | 2009年04月29日 17:44:15 -0500 (2009年4月29日) | 1 line
 
 make sure mode is removable while cleaning up test droppings
........
 r72134 | benjamin.peterson | 2009年04月29日 19:06:33 -0500 (2009年4月29日) | 1 line
 
 make sure to close file
........
 r72191 | michael.foord | 2009年05月02日 06:43:06 -0500 (2009年5月02日) | 9 lines
 
 Adds an exit parameter to unittest.main(). If False main no longer
 calls sys.exit.
 
 Closes issue 3379.
 
 Michael Foord
 
........
 r72197 | benjamin.peterson | 2009年05月02日 11:24:37 -0500 (2009年5月02日) | 1 line
 
 don't let sys.argv be used in the tests
........
 r72198 | andrew.kuchling | 2009年05月02日 12:12:15 -0500 (2009年5月02日) | 1 line
 
 Add items
........
 r72219 | michael.foord | 2009年05月02日 15:15:05 -0500 (2009年5月02日) | 8 lines
 
 Add addCleanup and doCleanups to unittest.TestCase.
 
 Closes issue 5679.
 
 Michael Foord
........
 r72221 | benjamin.peterson | 2009年05月02日 15:26:53 -0500 (2009年5月02日) | 1 line
 
 add myself
........
 r72225 | michael.foord | 2009年05月02日 17:43:34 -0500 (2009年5月02日) | 1 line
........
 r72303 | benjamin.peterson | 2009年05月04日 19:55:24 -0500 (2009年5月04日) | 1 line
 
 using sys._getframe(x), where x > 0 doesnt' work on IronPython
........
 r72434 | r.david.murray | 2009年05月07日 13:09:58 -0500 (2009年5月07日) | 2 lines
 
 Pre-opened test file needs to be opened in binary mode.
........
 r72467 | georg.brandl | 2009年05月08日 07:17:34 -0500 (2009年5月08日) | 1 line
 
 Fix name.
........
 r72476 | thomas.heller | 2009年05月08日 15:09:40 -0500 (2009年5月08日) | 4 lines
 
 Add a file that contains diffs between offical libffi files and the
 files in this repository. Should make it easier to merge new libffi
 versions.
........
Added:
 python/branches/py3k/Modules/_ctypes/libffi.diff
 - copied unchanged from r72476, /python/trunk/Modules/_ctypes/libffi.diff
Modified:
 python/branches/py3k/ (props changed)
 python/branches/py3k/Doc/c-api/init.rst
 python/branches/py3k/Doc/howto/functional.rst
 python/branches/py3k/Doc/howto/regex.rst
 python/branches/py3k/Doc/library/2to3.rst
 python/branches/py3k/Doc/library/collections.rst
 python/branches/py3k/Doc/library/decimal.rst
 python/branches/py3k/Doc/library/json.rst
 python/branches/py3k/Doc/library/shelve.rst
 python/branches/py3k/Doc/library/subprocess.rst
 python/branches/py3k/Doc/library/traceback.rst
 python/branches/py3k/Doc/library/unittest.rst
 python/branches/py3k/Doc/whatsnew/2.7.rst
 python/branches/py3k/Lib/collections.py
 python/branches/py3k/Lib/logging/__init__.py
 python/branches/py3k/Lib/test/regrtest.py
 python/branches/py3k/Lib/test/test_aifc.py
 python/branches/py3k/Lib/test/test_descr.py
 python/branches/py3k/Lib/test/test_logging.py
 python/branches/py3k/Lib/test/test_shutil.py
 python/branches/py3k/Lib/test/test_unittest.py
 python/branches/py3k/Lib/unittest.py
Modified: python/branches/py3k/Doc/c-api/init.rst
==============================================================================
--- python/branches/py3k/Doc/c-api/init.rst	(original)
+++ python/branches/py3k/Doc/c-api/init.rst	Fri May 8 22:42:26 2009
@@ -416,10 +416,9 @@
 The Python interpreter needs to keep some bookkeeping information separate per
 thread --- for this it uses a data structure called :ctype:`PyThreadState`.
 There's one global variable, however: the pointer to the current
-:ctype:`PyThreadState` structure. While most thread packages have a way to
-store "per-thread global data," Python's internal platform independent thread
-abstraction doesn't support this yet. Therefore, the current thread state must
-be manipulated explicitly.
+:ctype:`PyThreadState` structure. Before the addition of :dfn:`thread-local
+storage` (:dfn:`TLS`) the current thread state had to be manipulated
+explicitly.
 
 This is easy enough in most cases. Most code manipulating the global
 interpreter lock has the following simple structure::
Modified: python/branches/py3k/Doc/howto/functional.rst
==============================================================================
--- python/branches/py3k/Doc/howto/functional.rst	(original)
+++ python/branches/py3k/Doc/howto/functional.rst	Fri May 8 22:42:26 2009
@@ -473,7 +473,7 @@
 
 >>> gen = generate_ints(3)
 >>> gen
- <generator object at ...>
+ <generator object generate_ints at ...>
 >>> next(gen)
 0
 >>> next(gen)
Modified: python/branches/py3k/Doc/howto/regex.rst
==============================================================================
--- python/branches/py3k/Doc/howto/regex.rst	(original)
+++ python/branches/py3k/Doc/howto/regex.rst	Fri May 8 22:42:26 2009
@@ -264,7 +264,7 @@
 >>> import re
 >>> p = re.compile('ab*')
 >>> p
- <re.RegexObject instance at 80b4150>
+ <_sre.SRE_Pattern object at 80b4150>
 
 :func:`re.compile` also accepts an optional *flags* argument, used to enable
 various special features and syntax variations. We'll go over the available
Modified: python/branches/py3k/Doc/library/2to3.rst
==============================================================================
--- python/branches/py3k/Doc/library/2to3.rst	(original)
+++ python/branches/py3k/Doc/library/2to3.rst	Fri May 8 22:42:26 2009
@@ -352,6 +352,7 @@
 :synopsis: the 2to3 library
 .. moduleauthor:: Guido van Rossum
 .. moduleauthor:: Collin Winter
+.. moduleauthor:: Benjamin Peterson <benjamin at python.org>
 
 
 .. note::
Modified: python/branches/py3k/Doc/library/collections.rst
==============================================================================
--- python/branches/py3k/Doc/library/collections.rst	(original)
+++ python/branches/py3k/Doc/library/collections.rst	Fri May 8 22:42:26 2009
@@ -169,7 +169,7 @@
 class is similar to bags or multisets in other languages.
 
 Elements are counted from an *iterable* or initialized from another
- *mapping* (or counter)::
+ *mapping* (or counter):
 
 >>> c = Counter() # a new, empty counter
 >>> c = Counter('gallahad') # a new counter from an iterable
@@ -177,7 +177,7 @@
 >>> c = Counter(cats=4, dogs=8) # a new counter from keyword args
 
 Counter objects have a dictionary interface except that they return a zero
- count for missing items instead of raising a :exc:`KeyError`::
+ count for missing items instead of raising a :exc:`KeyError`:
 
 >>> c = Counter(['eggs', 'ham'])
 >>> c['bacon'] # count of a missing element is zero
@@ -210,7 +210,7 @@
 Return a list of the *n* most common elements and their counts from the
 most common to the least. If *n* is not specified, :func:`most_common`
 returns *all* elements in the counter. Elements with equal counts are
- ordered arbitrarily::
+ ordered arbitrarily:
 
 >>> Counter('abracadabra').most_common(3)
 [('a', 5), ('r', 2), ('b', 2)]
Modified: python/branches/py3k/Doc/library/decimal.rst
==============================================================================
--- python/branches/py3k/Doc/library/decimal.rst	(original)
+++ python/branches/py3k/Doc/library/decimal.rst	Fri May 8 22:42:26 2009
@@ -1746,7 +1746,7 @@
 >>> Decimal('3.214').quantize(TWOPLACES, context=Context(traps=[Inexact]))
 Traceback (most recent call last):
 ...
- Inexact
+ Inexact: None
 
 Q. Once I have valid two place inputs, how do I maintain that invariant
 throughout an application?
Modified: python/branches/py3k/Doc/library/json.rst
==============================================================================
--- python/branches/py3k/Doc/library/json.rst	(original)
+++ python/branches/py3k/Doc/library/json.rst	Fri May 8 22:42:26 2009
@@ -165,12 +165,12 @@
 document) to a Python object.
 
 *object_hook* is an optional function that will be called with the result of
- any object literal decode (a :class:`dict`). The return value of
+ any object literal decoded (a :class:`dict`). The return value of
 *object_hook* will be used instead of the :class:`dict`. This feature can be used
 to implement custom decoders (e.g. JSON-RPC class hinting).
 
 *object_pairs_hook* is an optional function that will be called with the
- result of any object literal decode with an ordered list of pairs. The
+ result of any object literal decoded with an ordered list of pairs. The
 return value of *object_pairs_hook* will be used instead of the
 :class:`dict`. This feature can be used to implement custom decoders that
 rely on the order that the key and value pairs are decoded (for example,
Modified: python/branches/py3k/Doc/library/shelve.rst
==============================================================================
--- python/branches/py3k/Doc/library/shelve.rst	(original)
+++ python/branches/py3k/Doc/library/shelve.rst	Fri May 8 22:42:26 2009
@@ -1,4 +1,3 @@
-
 :mod:`shelve` --- Python object persistence
 ===========================================
 
@@ -35,7 +34,7 @@
 accessed entries are written back (there is no way to determine which accessed
 entries are mutable, nor which ones were actually mutated).
 
-Shelve objects support all methods supported by dictionaries. This eases the
+Shelf objects support all methods supported by dictionaries. This eases the
 transition from dictionary based scripts to those requiring persistent storage.
 
 One additional method is supported:
Modified: python/branches/py3k/Doc/library/subprocess.rst
==============================================================================
--- python/branches/py3k/Doc/library/subprocess.rst	(original)
+++ python/branches/py3k/Doc/library/subprocess.rst	Fri May 8 22:42:26 2009
@@ -174,13 +174,13 @@
 :attr:`returncode`
 attribute and output in the :attr:`output` attribute.
 
- The arguments are the same as for the :class:`Popen` constructor. Example:
+ The arguments are the same as for the :class:`Popen` constructor. Example::
 
 >>> subprocess.check_output(["ls", "-l", "/dev/null"])
 'crw-rw-rw- 1 root root 1, 3 Oct 18 2007 /dev/null\n'
 
 The stdout argument is not allowed as it is used internally.
- To capture standard error in the result, use stderr=subprocess.STDOUT.
+ To capture standard error in the result, use ``stderr=subprocess.STDOUT``::
 
 >>> subprocess.check_output(
 ["/bin/sh", "-c", "ls non_existent_file ; exit 0"],
Modified: python/branches/py3k/Doc/library/traceback.rst
==============================================================================
--- python/branches/py3k/Doc/library/traceback.rst	(original)
+++ python/branches/py3k/Doc/library/traceback.rst	Fri May 8 22:42:26 2009
@@ -228,7 +228,7 @@
 *** extract_tb:
 [('<doctest...>', 10, '<module>', 'lumberjack()'),
 ('<doctest...>', 4, 'lumberjack', 'bright_side_of_death()'),
- (u'<doctest...>', 7, 'bright_side_of_death', 'return tuple()[0]')]
+ ('<doctest...>', 7, 'bright_side_of_death', 'return tuple()[0]')]
 *** format_tb:
 [' File "<doctest...>", line 10, in <module>\n lumberjack()\n',
 ' File "<doctest...>", line 4, in lumberjack\n bright_side_of_death()\n',
Modified: python/branches/py3k/Doc/library/unittest.rst
==============================================================================
--- python/branches/py3k/Doc/library/unittest.rst	(original)
+++ python/branches/py3k/Doc/library/unittest.rst	Fri May 8 22:42:26 2009
@@ -954,7 +954,6 @@
 along with the method name.
 
 .. versionchanged:: 3.1
-
 In earlier versions this only returned the first line of the test
 method's docstring, if available or the :const:`None`. That led to
 undesirable behavior of not printing the test name when someone was
@@ -978,6 +977,36 @@
 .. versionadded:: 3.1
 
 
+ .. method:: addCleanup(function[, *args[, **kwargs]])
+
+ Add a function to be called after :meth:`tearDown` to cleanup resources
+ used during the test. Functions will be called in reverse order to the
+ order they are added (LIFO). They are called with any arguments and
+ keyword arguments passed into :meth:`addCleanup` when they are
+ added.
+
+ If :meth:`setUp` fails, meaning that :meth:`tearDown` is not called,
+ then any cleanup functions added will still be called.
+
+ .. versionadded:: 2.7
+
+
+ .. method:: doCleanups()
+
+ This method is called uncoditionally after :meth:`tearDown`, or
+ after :meth:`setUp` if :meth:`setUp` raises an exception.
+
+ It is responsible for calling all the cleanup functions added by
+ :meth:`addCleanup`. If you need cleanup functions to be called
+ *prior* to :meth:`tearDown` then you can call :meth:`doCleanups`
+ yourself.
+
+ :meth:`doCleanups` pops methods off the stack of cleanup
+ functions one at a time, so it can be called at any time.
+
+ .. versionadded:: 2.7
+
+
 .. class:: FunctionTestCase(testFunc[, setUp[, tearDown[, description]]])
 
 This class implements the portion of the :class:`TestCase` interface which
@@ -1046,6 +1075,20 @@
 Return the number of tests represented by this test object, including all
 individual tests and sub-suites.
 
+
+ .. method:: __iter__()
+
+ Tests grouped by a :class:`TestSuite` are always accessed by iteration.
+ Subclasses can lazily provide tests by overriding :meth:`__iter__`. Note
+ that this method maybe called several times on a single suite
+ (for example when counting tests or comparing for equality)
+ so the tests returned must be the same for repeated iterations.
+
+ .. versionchanged:: 2.7
+ In earlier versions the :class:`TestSuite` accessed tests directly rather
+ than through iteration, so overriding :meth:`__iter__` wasn't sufficient
+ for providing tests.
+
 In the typical usage of a :class:`TestSuite` object, the :meth:`run` method
 is invoked by a :class:`TestRunner` rather than by the end-user test harness.
 
@@ -1190,7 +1233,6 @@
 holding formatted tracebacks. Each tuple represents a test which raised an
 unexpected exception.
 
-
 .. attribute:: failures
 
 A list containing 2-tuples of :class:`TestCase` instances and strings
@@ -1266,6 +1308,20 @@
 The default implementation does nothing.
 
 
+ .. method:: startTestRun(test)
+
+ Called once before any tests are executed.
+
+ .. versionadded:: 2.7
+
+
+ .. method:: stopTestRun(test)
+
+ Called once before any tests are executed.
+
+ .. versionadded:: 2.7
+
+
 .. method:: addError(test, err)
 
 Called when the test case *test* raises an unexpected exception *err* is a
@@ -1335,8 +1391,14 @@
 has a few configurable parameters, but is essentially very simple. Graphical
 applications which run test suites should provide alternate implementations.
 
+ .. method:: _makeResult()
+
+ This method returns the instance of ``TestResult`` used by :meth:`run`.
+ It is not intended to be called directly, but can be overridden in
+ subclasses to provide a custom ``TestResult``.
 
-.. function:: main([module[, defaultTest[, argv[, testRunner[, testLoader]]]]])
+
+.. function:: main([module[, defaultTest[, argv[, testRunner[, testLoader[, exit]]]]]])
 
 A command-line program that runs a set of tests; this is primarily for making
 test modules conveniently executable. The simplest use for this function is to
@@ -1346,4 +1408,18 @@
 unittest.main()
 
 The *testRunner* argument can either be a test runner class or an already
- created instance of it.
+ created instance of it. By default ``main`` calls :func:`sys.exit` with
+ an exit code indicating success or failure of the tests run.
+
+ ``main`` supports being used from the interactive interpreter by passing in the
+ argument ``exit=False``. This displays the result on standard output without
+ calling :func:`sys.exit`::
+
+ >>> from unittest import main
+ >>> main(module='test_module', exit=False)
+
+ Calling ``main`` actually returns an instance of the ``TestProgram`` class.
+ This stores the result of the tests run as the ``result`` attribute.
+
+ .. versionchanged:: 2.7
+ The ``exit`` parameter was added.
Modified: python/branches/py3k/Doc/whatsnew/2.7.rst
==============================================================================
--- python/branches/py3k/Doc/whatsnew/2.7.rst	(original)
+++ python/branches/py3k/Doc/whatsnew/2.7.rst	Fri May 8 22:42:26 2009
@@ -121,6 +121,31 @@
 
 (Contributed by Fredrik Johansson and Victor Stinner; :issue:`3439`.)
 
+* Conversions from long integers and regular integers to floating
+ point now round differently, returning the floating-point number
+ closest to the number. This doesn't matter for small integers that
+ can be converted exactly, but for large numbers that will
+ unavoidably lose precision, Python 2.7 will now approximate more
+ closely. For example, Python 2.6 computed the following::
+
+ >>> n = 295147905179352891391
+ >>> float(n)
+ 2.9514790517935283e+20
+ >>> n - long(float(n))
+ 65535L
+
+ Python 2.7's floating-point result is larger, but much closer to the
+ true value::
+
+ >>> n = 295147905179352891391
+ >>> float(n)
+ 2.9514790517935289e+20
+ >>> n-long(float(n)
+ ... )
+ -1L
+
+ (Implemented by Mark Dickinson; :issue:`3166`.)
+
 * The :class:`bytearray` type's :meth:`translate` method will
 now accept ``None`` as its first argument. (Fixed by Georg Brandl;
 :issue:`4759`.)
@@ -220,21 +245,24 @@
 * New class: the :class:`Counter` class in the :mod:`collections` module is
 useful for tallying data. :class:`Counter` instances behave mostly
 like dictionaries but return zero for missing keys instead of
- raising a :exc:`KeyError`::
+ raising a :exc:`KeyError`:
 
- >>> from collections import Counter
- >>> c=Counter()
- >>> for letter in 'here is a sample of english text':
- ... c[letter] += 1
- ...
- >>> c
- Counter({' ': 6, 'e': 5, 's': 3, 'a': 2, 'i': 2, 'h': 2,
- 'l': 2, 't': 2, 'g': 1, 'f': 1, 'm': 1, 'o': 1, 'n': 1,
- 'p': 1, 'r': 1, 'x': 1})
- >>> c['e']
- 5
- >>> c['z']
- 0
+ .. doctest::
+ :options: +NORMALIZE_WHITESPACE
+
+ >>> from collections import Counter
+ >>> c = Counter()
+ >>> for letter in 'here is a sample of english text':
+ ... c[letter] += 1
+ ...
+ >>> c
+ Counter({' ': 6, 'e': 5, 's': 3, 'a': 2, 'i': 2, 'h': 2,
+ 'l': 2, 't': 2, 'g': 1, 'f': 1, 'm': 1, 'o': 1, 'n': 1,
+ 'p': 1, 'r': 1, 'x': 1})
+ >>> c['e']
+ 5
+ >>> c['z']
+ 0
 
 There are two additional :class:`Counter` methods: :meth:`most_common`
 returns the N most common elements and their counts, and :meth:`elements`
@@ -247,7 +275,7 @@
 'a', 'a', ' ', ' ', ' ', ' ', ' ', ' ',
 'e', 'e', 'e', 'e', 'e', 'g', 'f', 'i', 'i',
 'h', 'h', 'm', 'l', 'l', 'o', 'n', 'p', 's',
- 's', 's', 'r', 't', 't', 'x']
+ 's', 's', 'r', 't', 't', 'x'
 
 Contributed by Raymond Hettinger; :issue:`1696199`.
 
@@ -257,7 +285,8 @@
 renamed to legal names that are derived from the field's
 position within the list of fields:
 
- >>> T=namedtuple('T', ['field1', '$illegal', 'for', 'field2'], rename=True)
+ >>> from collections import namedtuple
+ >>> T = namedtuple('T', ['field1', '$illegal', 'for', 'field2'], rename=True)
 >>> T._fields
 ('field1', '_1', '_2', 'field2')
 
@@ -294,6 +323,10 @@
 ``Decimal('0.1000000000000000055511151231257827021181583404541015625')``.
 (Implemented by Raymond Hettinger; :issue:`4796`.)
 
+* The :class:`Fraction` class will now accept two rational numbers
+ as arguments to its constructor.
+ (Implemented by Mark Dickinson; :issue:`5812`.)
+
 * New function: the :mod:`gc` module's :func:`is_tracked` returns
 true if a given instance is tracked by the garbage collector, false
 otherwise. (Contributed by Antoine Pitrou; :issue:`4688`.)
@@ -419,6 +452,13 @@
 
 (Implemented by Antoine Pitrou; :issue:`4444`.)
 
+ The methods :meth:`addCleanup` and :meth:`doCleanups` were added.
+ :meth:`addCleanup` allows you to add cleanup functions that
+ will be called unconditionally (after :meth:`setUp` if
+ :meth:`setUp` fails, otherwise after :meth:`tearDown`). This allows
+ for much simpler resource allocation and deallocation during tests.
+ :issue:`5679`
+
 A number of new methods were added that provide more specialized
 tests. Many of these methods were written by Google engineers
 for use in their test suites; Gregory P. Smith, Michael Foord, and
@@ -473,6 +513,14 @@
 to provide additional information about why the two objects are
 matching, much as the new sequence comparison methods do.
 
+ :func:`unittest.main` now takes an optional ``exit`` argument.
+ If False ``main`` doesn't call :func:`sys.exit` allowing it to
+ be used from the interactive interpreter. :issue:`3379`.
+
+ :class:`TestResult` has new :meth:`startTestRun` and
+ :meth:`stopTestRun` methods; called immediately before
+ and after a test run. :issue:`5728` by Robert Collins.
+
 * The :func:`is_zipfile` function in the :mod:`zipfile` module will now
 accept a file object, in addition to the path names accepted in earlier
 versions. (Contributed by Gabriel Genellina; :issue:`4756`.)
@@ -553,6 +601,10 @@
 is particularly useful for asynchronous IO operations.
 (Contributed by Kristjan Valur Jonsson; :issue:`4293`.)
 
+* Global symbols defined by the :mod:`ctypes` module are now prefixed
+ with ``Py`, or with ``_ctypes``. (Implemented by Thomas
+ Heller; :issue:`3102`.)
+
 * The :program:`configure` script now checks for floating-point rounding bugs
 on certain 32-bit Intel chips and defines a :cmacro:`X87_DOUBLE_ROUNDING`
 preprocessor definition. No code currently uses this definition,
@@ -591,10 +643,10 @@
 
 * When importing a module from a :file:`.pyc` or :file:`.pyo` file
 with an existing :file:`.py` counterpart, the :attr:`co_filename`
- attributes of all code objects if the original filename is obsolete,
- which can happen if the file has been renamed, moved, or is accessed
- through different paths. (Patch by Ziga Seilnacht and Jean-Paul
- Calderone; :issue:`1180193`.)
+ attributes of the resulting code objects are overwritten when the
+ original filename is obsolete. This can happen if the file has been
+ renamed, moved, or is accessed through different paths. (Patch by
+ Ziga Seilnacht and Jean-Paul Calderone; :issue:`1180193`.)
 
 * The :file:`regrtest.py` script now takes a :option:`--randseed=`
 switch that takes an integer that will be used as the random seed
Modified: python/branches/py3k/Lib/collections.py
==============================================================================
--- python/branches/py3k/Lib/collections.py	(original)
+++ python/branches/py3k/Lib/collections.py	Fri May 8 22:42:26 2009
@@ -271,9 +271,12 @@
 
 # For pickling to work, the __module__ variable needs to be set to the frame
 # where the named tuple is created. Bypass this step in enviroments where
- # sys._getframe is not defined (Jython for example).
- if hasattr(_sys, '_getframe'):
+ # sys._getframe is not defined (Jython for example) or sys._getframe is not
+ # defined for arguments greater than 0 (IronPython).
+ try:
 result.__module__ = _sys._getframe(1).f_globals.get('__name__', '__main__')
+ except (AttributeError, ValueError):
+ pass
 
 return result
 
Modified: python/branches/py3k/Lib/logging/__init__.py
==============================================================================
--- python/branches/py3k/Lib/logging/__init__.py	(original)
+++ python/branches/py3k/Lib/logging/__init__.py	Fri May 8 22:42:26 2009
@@ -756,7 +756,7 @@
 The record is then written to the stream with a trailing newline. If
 exception information is present, it is formatted using
 traceback.print_exception and appended to the stream. If the stream
- has an 'encoding' attribute, it is used to encode the message before
+ has an 'encoding' attribute, it is used to determine how to do the
 output to the stream.
 """
 try:
@@ -767,11 +767,21 @@
 stream.write(fs % msg)
 else:
 try:
- if (isinstance(msg, unicode) or
- getattr(stream, 'encoding', None) is None):
- stream.write(fs % msg)
+ if (isinstance(msg, unicode) and
+ getattr(stream, 'encoding', None)):
+ fs = fs.decode(stream.encoding)
+ try:
+ stream.write(fs % msg)
+ except UnicodeEncodeError:
+ #Printing to terminals sometimes fails. For example,
+ #with an encoding of 'cp1251', the above write will
+ #work if written to a stream opened or wrapped by
+ #the codecs module, but fail when writing to a
+ #terminal even when the codepage is set to cp1251.
+ #An extra encoding step seems to be needed.
+ stream.write((fs % msg).encode(stream.encoding))
 else:
- stream.write(fs % msg.encode(stream.encoding))
+ stream.write(fs % msg)
 except UnicodeError:
 stream.write(fs % msg.encode("UTF-8"))
 self.flush()
Modified: python/branches/py3k/Lib/test/regrtest.py
==============================================================================
--- python/branches/py3k/Lib/test/regrtest.py	(original)
+++ python/branches/py3k/Lib/test/regrtest.py	Fri May 8 22:42:26 2009
@@ -663,6 +663,7 @@
 
 def cleanup_test_droppings(testname, verbose):
 import shutil
+ import stat
 
 # Try to clean up junk commonly left behind. While tests shouldn't leave
 # any files or directories behind, when a test fails that can be tedious
@@ -687,6 +688,10 @@
 if verbose:
 print("%r left behind %s %r" % (testname, kind, name))
 try:
+ # if we have chmod, fix possible permissions problems
+ # that might prevent cleanup
+ if (hasattr(os, 'chmod')):
+ os.chmod(name, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
 nuker(name)
 except Exception as msg:
 print(("%r left behind %s %r and it couldn't be "
Modified: python/branches/py3k/Lib/test/test_aifc.py
==============================================================================
--- python/branches/py3k/Lib/test/test_aifc.py	(original)
+++ python/branches/py3k/Lib/test/test_aifc.py	Fri May 8 22:42:26 2009
@@ -27,7 +27,7 @@
 def test_skipunknown(self):
 #Issue 2245
 #This file contains chunk types aifc doesn't recognize.
- f = aifc.open(self.sndfilepath)
+ self.f = aifc.open(self.sndfilepath)
 
 def test_params(self):
 f = self.f = aifc.open(self.sndfilepath)
Modified: python/branches/py3k/Lib/test/test_descr.py
==============================================================================
--- python/branches/py3k/Lib/test/test_descr.py	(original)
+++ python/branches/py3k/Lib/test/test_descr.py	Fri May 8 22:42:26 2009
@@ -3585,31 +3585,6 @@
 self.assertEqual(e.a, 2)
 self.assertEqual(C2.__subclasses__(), [D])
 
- # stuff that shouldn't:
- class L(list):
- pass
-
- try:
- L.__bases__ = (dict,)
- except TypeError:
- pass
- else:
- self.fail("shouldn't turn list subclass into dict subclass")
-
- try:
- list.__bases__ = (dict,)
- except TypeError:
- pass
- else:
- self.fail("shouldn't be able to assign to list.__bases__")
-
- try:
- D.__bases__ = (C2, list)
- except TypeError:
- pass
- else:
- assert 0, "best_base calculation found wanting"
-
 try:
 del D.__bases__
 except (TypeError, AttributeError):
@@ -3657,6 +3632,36 @@
 if tp is not object:
 self.assertEqual(len(tp.__bases__), 1, tp)
 
+ class L(list):
+ pass
+
+ class C(object):
+ pass
+
+ class D(C):
+ pass
+
+ try:
+ L.__bases__ = (dict,)
+ except TypeError:
+ pass
+ else:
+ self.fail("shouldn't turn list subclass into dict subclass")
+
+ try:
+ list.__bases__ = (dict,)
+ except TypeError:
+ pass
+ else:
+ self.fail("shouldn't be able to assign to list.__bases__")
+
+ try:
+ D.__bases__ = (C, list)
+ except TypeError:
+ pass
+ else:
+ assert 0, "best_base calculation found wanting"
+
 
 def test_mutable_bases_with_failing_mro(self):
 # Testing mutable bases with failing mro...
Modified: python/branches/py3k/Lib/test/test_logging.py
==============================================================================
--- python/branches/py3k/Lib/test/test_logging.py	(original)
+++ python/branches/py3k/Lib/test/test_logging.py	Fri May 8 22:42:26 2009
@@ -894,6 +894,7 @@
 message = '\u0434\u043e \u0441\u0432\u0438\u0434\u0430\u043d\u0438\u044f'
 #Ensure it's written in a Cyrillic encoding
 writer_class = codecs.getwriter('cp1251')
+ writer_class.encoding = 'cp1251'
 stream = io.BytesIO()
 writer = writer_class(stream, 'strict')
 handler = logging.StreamHandler(writer)
Modified: python/branches/py3k/Lib/test/test_shutil.py
==============================================================================
--- python/branches/py3k/Lib/test/test_shutil.py	(original)
+++ python/branches/py3k/Lib/test/test_shutil.py	Fri May 8 22:42:26 2009
@@ -46,9 +46,23 @@
 shutil.rmtree(TESTFN)
 
 def check_args_to_onerror(self, func, arg, exc):
+ # test_rmtree_errors deliberately runs rmtree
+ # on a directory that is chmod 400, which will fail.
+ # This function is run when shutil.rmtree fails.
+ # 99.9% of the time it initially fails to remove
+ # a file in the directory, so the first time through
+ # func is os.remove.
+ # However, some Linux machines running ZFS on
+ # FUSE experienced a failure earlier in the process
+ # at os.listdir. The first failure may legally
+ # be either.
 if self.errorState == 0:
- self.assertEqual(func, os.remove)
- self.assertEqual(arg, self.childpath)
+ if func is os.remove:
+ self.assertEqual(arg, self.childpath)
+ else:
+ self.assertIs(func, os.listdir,
+ "func must be either os.remove or os.listdir")
+ self.assertEqual(arg, TESTFN)
 self.failUnless(issubclass(exc[0], OSError))
 self.errorState = 1
 else:
Modified: python/branches/py3k/Lib/test/test_unittest.py
==============================================================================
--- python/branches/py3k/Lib/test/test_unittest.py	(original)
+++ python/branches/py3k/Lib/test/test_unittest.py	Fri May 8 22:42:26 2009
@@ -9,9 +9,10 @@
 import re
 from test import support
 import unittest
-from unittest import TestCase
+from unittest import TestCase, TestProgram
 import types
 from copy import deepcopy
+import io
 
 ### Support code
 ################################################################
@@ -25,10 +26,18 @@
 self._events.append('startTest')
 super().startTest(test)
 
+ def startTestRun(self):
+ self._events.append('startTestRun')
+ super(LoggingResult, self).startTestRun()
+
 def stopTest(self, test):
 self._events.append('stopTest')
 super().stopTest(test)
 
+ def stopTestRun(self):
+ self._events.append('stopTestRun')
+ super(LoggingResult, self).stopTestRun()
+
 def addFailure(self, *args):
 self._events.append('addFailure')
 super().addFailure(*args)
@@ -1826,6 +1835,12 @@
 self.assertEqual(result.testsRun, 1)
 self.assertEqual(result.shouldStop, False)
 
+ # "Called before and after tests are run. The default implementation does nothing."
+ def test_startTestRun_stopTestRun(self):
+ result = unittest.TestResult()
+ result.startTestRun()
+ result.stopTestRun()
+
 # "addSuccess(test)"
 # ...
 # "Called when the test case test succeeds"
@@ -1973,6 +1988,53 @@
 class Bar(Foo):
 def test2(self): pass
 
+class LoggingTestCase(unittest.TestCase):
+ """A test case which logs its calls."""
+
+ def __init__(self, events):
+ super(LoggingTestCase, self).__init__('test')
+ self.events = events
+
+ def setUp(self):
+ self.events.append('setUp')
+
+ def test(self):
+ self.events.append('test')
+
+ def tearDown(self):
+ self.events.append('tearDown')
+
+class ResultWithNoStartTestRunStopTestRun(object):
+ """An object honouring TestResult before startTestRun/stopTestRun."""
+
+ def __init__(self):
+ self.failures = []
+ self.errors = []
+ self.testsRun = 0
+ self.skipped = []
+ self.expectedFailures = []
+ self.unexpectedSuccesses = []
+ self.shouldStop = False
+
+ def startTest(self, test):
+ pass
+
+ def stopTest(self, test):
+ pass
+
+ def addError(self, test):
+ pass
+
+ def addFailure(self, test):
+ pass
+
+ def addSuccess(self, test):
+ pass
+
+ def wasSuccessful(self):
+ return True
+
+
 ################################################################
 ### /Support code for Test_TestCase
 
@@ -2067,19 +2129,30 @@
 events = []
 result = LoggingResult(events)
 
- class Foo(unittest.TestCase):
+ class Foo(LoggingTestCase):
 def setUp(self):
- events.append('setUp')
+ super(Foo, self).setUp()
 raise RuntimeError('raised by Foo.setUp')
 
- def test(self):
- events.append('test')
+ Foo(events).run(result)
+ expected = ['startTest', 'setUp', 'addError', 'stopTest']
+ self.assertEqual(events, expected)
 
- def tearDown(self):
- events.append('tearDown')
+ # "With a temporary result stopTestRun is called when setUp errors.
+ def test_run_call_order__error_in_setUp_default_result(self):
+ events = []
 
- Foo('test').run(result)
- expected = ['startTest', 'setUp', 'addError', 'stopTest']
+ class Foo(LoggingTestCase):
+ def defaultTestResult(self):
+ return LoggingResult(self.events)
+
+ def setUp(self):
+ super(Foo, self).setUp()
+ raise RuntimeError('raised by Foo.setUp')
+
+ Foo(events).run()
+ expected = ['startTestRun', 'startTest', 'setUp', 'addError',
+ 'stopTest', 'stopTestRun']
 self.assertEqual(events, expected)
 
 # "When a setUp() method is defined, the test runner will run that method
@@ -2093,20 +2166,32 @@
 events = []
 result = LoggingResult(events)
 
- class Foo(unittest.TestCase):
- def setUp(self):
- events.append('setUp')
-
+ class Foo(LoggingTestCase):
 def test(self):
- events.append('test')
+ super(Foo, self).test()
 raise RuntimeError('raised by Foo.test')
 
- def tearDown(self):
- events.append('tearDown')
-
 expected = ['startTest', 'setUp', 'test', 'addError', 'tearDown',
 'stopTest']
- Foo('test').run(result)
+ Foo(events).run(result)
+ self.assertEqual(events, expected)
+
+ # "With a default result, an error in the test still results in stopTestRun
+ # being called."
+ def test_run_call_order__error_in_test_default_result(self):
+ events = []
+
+ class Foo(LoggingTestCase):
+ def defaultTestResult(self):
+ return LoggingResult(self.events)
+
+ def test(self):
+ super(Foo, self).test()
+ raise RuntimeError('raised by Foo.test')
+
+ expected = ['startTestRun', 'startTest', 'setUp', 'test', 'addError',
+ 'tearDown', 'stopTest', 'stopTestRun']
+ Foo(events).run()
 self.assertEqual(events, expected)
 
 # "When a setUp() method is defined, the test runner will run that method
@@ -2120,20 +2205,30 @@
 events = []
 result = LoggingResult(events)
 
- class Foo(unittest.TestCase):
- def setUp(self):
- events.append('setUp')
-
+ class Foo(LoggingTestCase):
 def test(self):
- events.append('test')
+ super(Foo, self).test()
 self.fail('raised by Foo.test')
 
- def tearDown(self):
- events.append('tearDown')
-
 expected = ['startTest', 'setUp', 'test', 'addFailure', 'tearDown',
 'stopTest']
- Foo('test').run(result)
+ Foo(events).run(result)
+ self.assertEqual(events, expected)
+
+ # "When a test fails with a default result stopTestRun is still called."
+ def test_run_call_order__failure_in_test_default_result(self):
+
+ class Foo(LoggingTestCase):
+ def defaultTestResult(self):
+ return LoggingResult(self.events)
+ def test(self):
+ super(Foo, self).test()
+ self.fail('raised by Foo.test')
+
+ expected = ['startTestRun', 'startTest', 'setUp', 'test', 'addFailure',
+ 'tearDown', 'stopTest', 'stopTestRun']
+ events = []
+ Foo(events).run()
 self.assertEqual(events, expected)
 
 # "When a setUp() method is defined, the test runner will run that method
@@ -2147,22 +2242,44 @@
 events = []
 result = LoggingResult(events)
 
- class Foo(unittest.TestCase):
- def setUp(self):
- events.append('setUp')
-
- def test(self):
- events.append('test')
-
+ class Foo(LoggingTestCase):
 def tearDown(self):
- events.append('tearDown')
+ super(Foo, self).tearDown()
 raise RuntimeError('raised by Foo.tearDown')
 
- Foo('test').run(result)
+ Foo(events).run(result)
 expected = ['startTest', 'setUp', 'test', 'tearDown', 'addError',
 'stopTest']
 self.assertEqual(events, expected)
 
+ # "When tearDown errors with a default result stopTestRun is still called."
+ def test_run_call_order__error_in_tearDown_default_result(self):
+
+ class Foo(LoggingTestCase):
+ def defaultTestResult(self):
+ return LoggingResult(self.events)
+ def tearDown(self):
+ super(Foo, self).tearDown()
+ raise RuntimeError('raised by Foo.tearDown')
+
+ events = []
+ Foo(events).run()
+ expected = ['startTestRun', 'startTest', 'setUp', 'test', 'tearDown',
+ 'addError', 'stopTest', 'stopTestRun']
+ self.assertEqual(events, expected)
+
+ # "TestCase.run() still works when the defaultTestResult is a TestResult
+ # that does not support startTestRun and stopTestRun.
+ def test_run_call_order_default_result(self):
+
+ class Foo(unittest.TestCase):
+ def defaultTestResult(self):
+ return ResultWithNoStartTestRunStopTestRun()
+ def test(self):
+ pass
+
+ Foo('test').run()
+
 # "This class attribute gives the exception raised by the test() method.
 # If a test framework needs to use a specialized exception, possibly to
 # carry additional information, it must subclass this exception in
@@ -2253,7 +2370,9 @@
 self.failUnless(isinstance(Foo().id(), str))
 
 # "If result is omitted or None, a temporary result object is created
- # and used, but is not made available to the caller"
+ # and used, but is not made available to the caller. As TestCase owns the
+ # temporary result startTestRun and stopTestRun are called.
+
 def test_run__uses_defaultTestResult(self):
 events = []
 
@@ -2267,7 +2386,8 @@
 # Make run() find a result object on its own
 Foo('test').run()
 
- expected = ['startTest', 'test', 'addSuccess', 'stopTest']
+ expected = ['startTestRun', 'startTest', 'test', 'addSuccess',
+ 'stopTest', 'stopTestRun']
 self.assertEqual(events, expected)
 
 def testShortDescriptionWithoutDocstring(self):
@@ -3012,6 +3132,220 @@
 "^unexpectedly identical: None : oops$"])
 
 
+class TestCleanUp(TestCase):
+
+ def testCleanUp(self):
+ class TestableTest(TestCase):
+ def testNothing(self):
+ pass
+
+ test = TestableTest('testNothing')
+ self.assertEqual(test._cleanups, [])
+
+ cleanups = []
+
+ def cleanup1(*args, **kwargs):
+ cleanups.append((1, args, kwargs))
+
+ def cleanup2(*args, **kwargs):
+ cleanups.append((2, args, kwargs))
+
+ test.addCleanup(cleanup1, 1, 2, 3, four='hello', five='goodbye')
+ test.addCleanup(cleanup2)
+
+ self.assertEqual(test._cleanups,
+ [(cleanup1, (1, 2, 3), dict(four='hello', five='goodbye')),
+ (cleanup2, (), {})])
+
+ result = test.doCleanups()
+ self.assertTrue(result)
+
+ self.assertEqual(cleanups, [(2, (), {}), (1, (1, 2, 3), dict(four='hello', five='goodbye'))])
+
+ def testCleanUpWithErrors(self):
+ class TestableTest(TestCase):
+ def testNothing(self):
+ pass
+
+ class MockResult(object):
+ errors = []
+ def addError(self, test, exc_info):
+ self.errors.append((test, exc_info))
+
+ result = MockResult()
+ test = TestableTest('testNothing')
+ test._result = result
+
+ exc1 = Exception('foo')
+ exc2 = Exception('bar')
+ def cleanup1():
+ raise exc1
+
+ def cleanup2():
+ raise exc2
+
+ test.addCleanup(cleanup1)
+ test.addCleanup(cleanup2)
+
+ self.assertFalse(test.doCleanups())
+
+ (test1, (Type1, instance1, _)), (test2, (Type2, instance2, _)) = reversed(MockResult.errors)
+ self.assertEqual((test1, Type1, instance1), (test, Exception, exc1))
+ self.assertEqual((test2, Type2, instance2), (test, Exception, exc2))
+
+ def testCleanupInRun(self):
+ blowUp = False
+ ordering = []
+
+ class TestableTest(TestCase):
+ def setUp(self):
+ ordering.append('setUp')
+ if blowUp:
+ raise Exception('foo')
+
+ def testNothing(self):
+ ordering.append('test')
+
+ def tearDown(self):
+ ordering.append('tearDown')
+
+ test = TestableTest('testNothing')
+
+ def cleanup1():
+ ordering.append('cleanup1')
+ def cleanup2():
+ ordering.append('cleanup2')
+ test.addCleanup(cleanup1)
+ test.addCleanup(cleanup2)
+
+ def success(some_test):
+ self.assertEqual(some_test, test)
+ ordering.append('success')
+
+ result = unittest.TestResult()
+ result.addSuccess = success
+
+ test.run(result)
+ self.assertEqual(ordering, ['setUp', 'test', 'tearDown',
+ 'cleanup2', 'cleanup1', 'success'])
+
+ blowUp = True
+ ordering = []
+ test = TestableTest('testNothing')
+ test.addCleanup(cleanup1)
+ test.run(result)
+ self.assertEqual(ordering, ['setUp', 'cleanup1'])
+
+
+class Test_TestProgram(TestCase):
+
+ # Horrible white box test
+ def testNoExit(self):
+ result = object()
+ test = object()
+
+ class FakeRunner(object):
+ def run(self, test):
+ self.test = test
+ return result
+
+ runner = FakeRunner()
+
+ try:
+ oldParseArgs = TestProgram.parseArgs
+ TestProgram.parseArgs = lambda *args: None
+ TestProgram.test = test
+
+ program = TestProgram(testRunner=runner, exit=False)
+
+ self.assertEqual(program.result, result)
+ self.assertEqual(runner.test, test)
+
+ finally:
+ TestProgram.parseArgs = oldParseArgs
+ del TestProgram.test
+
+
+ class FooBar(unittest.TestCase):
+ def testPass(self):
+ assert True
+ def testFail(self):
+ assert False
+
+ class FooBarLoader(unittest.TestLoader):
+ """Test loader that returns a suite containing FooBar."""
+ def loadTestsFromModule(self, module):
+ return self.suiteClass(
+ [self.loadTestsFromTestCase(Test_TestProgram.FooBar)])
+
+
+ def test_NonExit(self):
+ program = unittest.main(exit=False,
+ argv=["foobar"],
+ testRunner=unittest.TextTestRunner(stream=io.StringIO()),
+ testLoader=self.FooBarLoader())
+ self.assertTrue(hasattr(program, 'result'))
+
+
+ def test_Exit(self):
+ self.assertRaises(
+ SystemExit,
+ unittest.main,
+ argv=["foobar"],
+ testRunner=unittest.TextTestRunner(stream=io.StringIO()),
+ exit=True,
+ testLoader=self.FooBarLoader())
+
+
+ def test_ExitAsDefault(self):
+ self.assertRaises(
+ SystemExit,
+ unittest.main,
+ argv=["foobar"],
+ testRunner=unittest.TextTestRunner(stream=io.StringIO()),
+ testLoader=self.FooBarLoader())
+
+
+class Test_TextTestRunner(TestCase):
+ """Tests for TextTestRunner."""
+
+ def test_works_with_result_without_startTestRun_stopTestRun(self):
+ class OldTextResult(ResultWithNoStartTestRunStopTestRun):
+ separator2 = ''
+ def printErrors(self):
+ pass
+
+ class Runner(unittest.TextTestRunner):
+ def __init__(self):
+ super(Runner, self).__init__(io.StringIO())
+
+ def _makeResult(self):
+ return OldTextResult()
+
+ runner = Runner()
+ runner.run(unittest.TestSuite())
+
+ def test_startTestRun_stopTestRun_called(self):
+ class LoggingTextResult(LoggingResult):
+ separator2 = ''
+ def printErrors(self):
+ pass
+
+ class LoggingRunner(unittest.TextTestRunner):
+ def __init__(self, events):
+ super(LoggingRunner, self).__init__(io.StringIO())
+ self._events = events
+
+ def _makeResult(self):
+ return LoggingTextResult(self._events)
+
+ events = []
+ runner = LoggingRunner(events)
+ runner.run(unittest.TestSuite())
+ expected = ['startTestRun', 'stopTestRun']
+ self.assertEqual(events, expected)
+
+
 ######################################################################
 ## Main
 ######################################################################
@@ -3019,7 +3353,8 @@
 def test_main():
 support.run_unittest(Test_TestCase, Test_TestLoader,
 Test_TestSuite, Test_TestResult, Test_FunctionTestCase,
- Test_TestSkipping, Test_Assertions, TestLongMessage)
+ Test_TestSkipping, Test_Assertions, TestLongMessage,
+ Test_TestProgram, TestCleanUp)
 
 if __name__ == "__main__":
 test_main()
Modified: python/branches/py3k/Lib/unittest.py
==============================================================================
--- python/branches/py3k/Lib/unittest.py	(original)
+++ python/branches/py3k/Lib/unittest.py	Fri May 8 22:42:26 2009
@@ -173,10 +173,22 @@
 "Called when the given test is about to be run"
 self.testsRun = self.testsRun + 1
 
+ def startTestRun(self):
+ """Called once before any tests are executed.
+
+ See startTest for a method called before each test.
+ """
+
 def stopTest(self, test):
 "Called when the given test has been run"
 pass
 
+ def stopTestRun(self):
+ """Called once after all tests are executed.
+
+ See stopTest for a method called after each test.
+ """
+
 def addError(self, test, err):
 """Called when an error has occurred. 'err' is a tuple of values as
 returned by sys.exc_info().
@@ -262,7 +274,7 @@
 def __enter__(self):
 pass
 
- def __exit__(self, exc_type, exc_value, traceback):
+ def __exit__(self, exc_type, exc_value, tb):
 if exc_type is None:
 try:
 exc_name = self.expected.__name__
@@ -341,12 +353,14 @@
 not have a method with the specified name.
 """
 self._testMethodName = methodName
+ self._result = None
 try:
 testMethod = getattr(self, methodName)
 except AttributeError:
 raise ValueError("no such test method in %s: %s" % \
 (self.__class__, methodName))
 self._testMethodDoc = testMethod.__doc__
+ self._cleanups = []
 
 # Map types to custom assertEqual functions that will compare
 # instances of said type in more detail to generate a more useful
@@ -373,6 +387,14 @@
 """
 self._type_equality_funcs[typeobj] = _AssertWrapper(function)
 
+ def addCleanup(self, function, *args, **kwargs):
+ """Add a function, with arguments, to be called when the test is
+ completed. Functions added are called on a LIFO basis and are
+ called after tearDown on test failure or success.
+
+ Cleanup items are called even if setUp fails (unlike tearDown)."""
+ self._cleanups.append((function, args, kwargs))
+
 def setUp(self):
 "Hook method for setting up the test fixture before exercising it."
 pass
@@ -428,45 +450,70 @@
 (_strclass(self.__class__), self._testMethodName)
 
 def run(self, result=None):
+ orig_result = result
 if result is None:
 result = self.defaultTestResult()
+ startTestRun = getattr(result, 'startTestRun', None)
+ if startTestRun is not None:
+ startTestRun()
+
+ self._result = result
 result.startTest(self)
 testMethod = getattr(self, self._testMethodName)
 try:
- try:
- self.setUp()
- except SkipTest as e:
- result.addSkip(self, str(e))
- return
- except Exception:
- result.addError(self, sys.exc_info())
- return
-
 success = False
 try:
- testMethod()
- except self.failureException:
- result.addFailure(self, sys.exc_info())
- except _ExpectedFailure as e:
- result.addExpectedFailure(self, e.exc_info)
- except _UnexpectedSuccess:
- result.addUnexpectedSuccess(self)
+ self.setUp()
 except SkipTest as e:
 result.addSkip(self, str(e))
 except Exception:
 result.addError(self, sys.exc_info())
 else:
- success = True
+ try:
+ testMethod()
+ except self.failureException:
+ result.addFailure(self, sys.exc_info())
+ except _ExpectedFailure as e:
+ result.addExpectedFailure(self, e.exc_info)
+ except _UnexpectedSuccess:
+ result.addUnexpectedSuccess(self)
+ except SkipTest as e:
+ result.addSkip(self, str(e))
+ except Exception:
+ result.addError(self, sys.exc_info())
+ else:
+ success = True
 
- try:
- self.tearDown()
- except Exception:
- result.addError(self, sys.exc_info())
- success = False
+ try:
+ self.tearDown()
+ except Exception:
+ result.addError(self, sys.exc_info())
+ success = False
+
+ cleanUpSuccess = self.doCleanups()
+ success = success and cleanUpSuccess
 if success:
 result.addSuccess(self)
 finally:
 result.stopTest(self)
+ if orig_result is None:
+ stopTestRun = getattr(result, 'stopTestRun', None)
+ if stopTestRun is not None:
+ stopTestRun()
+
+ def doCleanups(self):
+ """Execute all cleanup functions. Normally called for you after
+ tearDown."""
+ result = self._result
+ ok = True
+ while self._cleanups:
+ function, args, kwargs = self._cleanups.pop(-1)
+ try:
+ function(*args, **kwargs)
+ except Exception:
+ ok = False
+ result.addError(self, sys.exc_info())
+ return ok
 
 def __call__(self, *args, **kwds):
 return self.run(*args, **kwds)
@@ -1037,7 +1084,7 @@
 def __eq__(self, other):
 if not isinstance(other, self.__class__):
 return NotImplemented
- return self._tests == other._tests
+ return list(self) == list(other)
 
 def __ne__(self, other):
 return not self == other
@@ -1160,8 +1207,7 @@
 self._testFunc, self._description))
 
 def __str__(self):
- return "%s (%s)" % (_strclass(self.__class__),
- self.__testFunc.__name__)
+ return "%s (%s)" % (_strclass(self.__class__), self._testFunc.__name__)
 
 def __repr__(self):
 return "<%s testFunc=%s>" % (_strclass(self.__class__), self._testFunc)
@@ -1449,7 +1495,15 @@
 "Run the given test case or test suite."
 result = self._makeResult()
 startTime = time.time()
- test(result)
+ startTestRun = getattr(result, 'startTestRun', None)
+ if startTestRun is not None:
+ startTestRun()
+ try:
+ test(result)
+ finally:
+ stopTestRun = getattr(result, 'stopTestRun', None)
+ if stopTestRun is not None:
+ stopTestRun()
 stopTime = time.time()
 timeTaken = stopTime - startTime
 result.printErrors()
@@ -1511,7 +1565,7 @@
 """
 def __init__(self, module='__main__', defaultTest=None,
 argv=None, testRunner=TextTestRunner,
- testLoader=defaultTestLoader):
+ testLoader=defaultTestLoader, exit=True):
 if isinstance(module, str):
 self.module = __import__(module)
 for part in module.split('.')[1:]:
@@ -1520,6 +1574,8 @@
 self.module = module
 if argv is None:
 argv = sys.argv
+
+ self.exit = exit
 self.verbosity = 1
 self.defaultTest = defaultTest
 self.testRunner = testRunner
@@ -1571,8 +1627,9 @@
 else:
 # it is assumed to be a TestRunner instance
 testRunner = self.testRunner
- result = testRunner.run(self.test)
- sys.exit(not result.wasSuccessful())
+ self.result = testRunner.run(self.test)
+ if self.exit:
+ sys.exit(not self.result.wasSuccessful())
 
 main = TestProgram
 


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /