summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/c-api/init.rst7
-rw-r--r--Doc/howto/functional.rst2
-rw-r--r--Doc/howto/regex.rst2
-rw-r--r--Doc/library/2to3.rst1
-rw-r--r--Doc/library/collections.rst6
-rw-r--r--Doc/library/decimal.rst2
-rw-r--r--Doc/library/json.rst4
-rw-r--r--Doc/library/shelve.rst3
-rw-r--r--Doc/library/subprocess.rst4
-rw-r--r--Doc/library/traceback.rst2
-rw-r--r--Doc/library/unittest.rst84
-rw-r--r--Doc/whatsnew/2.7.rst94
-rw-r--r--Lib/collections.py7
-rw-r--r--Lib/logging/__init__.py20
-rwxr-xr-xLib/test/regrtest.py5
-rw-r--r--Lib/test/test_aifc.py2
-rw-r--r--Lib/test/test_descr.py55
-rw-r--r--Lib/test/test_logging.py1
-rw-r--r--Lib/test/test_shutil.py18
-rw-r--r--Lib/test/test_unittest.py413
-rw-r--r--Lib/unittest.py117
-rw-r--r--Modules/_ctypes/libffi.diff207
22 files changed, 910 insertions, 146 deletions
diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst
index 299af7f..6e185fa 100644
--- a/Doc/c-api/init.rst
+++ b/Doc/c-api/init.rst
@@ -416,10 +416,9 @@ the I/O is waiting for the I/O operation to complete.
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::
diff --git a/Doc/howto/functional.rst b/Doc/howto/functional.rst
index 9aa0aed..920dc2d 100644
--- a/Doc/howto/functional.rst
+++ b/Doc/howto/functional.rst
@@ -473,7 +473,7 @@ Here's a sample usage of the ``generate_ints()`` generator:
>>> gen = generate_ints(3)
>>> gen
- <generator object at ...>
+ <generator object generate_ints at ...>
>>> next(gen)
0
>>> next(gen)
diff --git a/Doc/howto/regex.rst b/Doc/howto/regex.rst
index 2623867..7144298 100644
--- a/Doc/howto/regex.rst
+++ b/Doc/howto/regex.rst
@@ -264,7 +264,7 @@ performing string substitutions. ::
>>> 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
diff --git a/Doc/library/2to3.rst b/Doc/library/2to3.rst
index 90284af..9b2b4e4 100644
--- a/Doc/library/2to3.rst
+++ b/Doc/library/2to3.rst
@@ -352,6 +352,7 @@ and off individually. They are described here in more detail.
:synopsis: the 2to3 library
.. moduleauthor:: Guido van Rossum
.. moduleauthor:: Collin Winter
+.. moduleauthor:: Benjamin Peterson <benjamin@python.org>
.. note::
diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst
index c334dc7..fca84bd 100644
--- a/Doc/library/collections.rst
+++ b/Doc/library/collections.rst
@@ -169,7 +169,7 @@ For example::
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 @@ For example::
>>> 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 @@ For example::
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)]
diff --git a/Doc/library/decimal.rst b/Doc/library/decimal.rst
index 2b4d156..a27fbf4 100644
--- a/Doc/library/decimal.rst
+++ b/Doc/library/decimal.rst
@@ -1746,7 +1746,7 @@ the :const:`Inexact` trap is set, it is also useful for validation:
>>> 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?
diff --git a/Doc/library/json.rst b/Doc/library/json.rst
index 819c339..955c25b 100644
--- a/Doc/library/json.rst
+++ b/Doc/library/json.rst
@@ -165,12 +165,12 @@ Basic Usage
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,
diff --git a/Doc/library/shelve.rst b/Doc/library/shelve.rst
index 8121004..8c1f08b 100644
--- a/Doc/library/shelve.rst
+++ b/Doc/library/shelve.rst
@@ -1,4 +1,3 @@
-
:mod:`shelve` --- Python object persistence
===========================================
@@ -35,7 +34,7 @@ lots of shared sub-objects. The keys are ordinary strings.
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:
diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst
index 3b6c8cc..7952f68 100644
--- a/Doc/library/subprocess.rst
+++ b/Doc/library/subprocess.rst
@@ -174,13 +174,13 @@ This module also defines four shortcut functions:
: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"],
diff --git a/Doc/library/traceback.rst b/Doc/library/traceback.rst
index 6929c1d..5c42740 100644
--- a/Doc/library/traceback.rst
+++ b/Doc/library/traceback.rst
@@ -228,7 +228,7 @@ The output for the example would look similar to this:
*** 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',
diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst
index 675114a..abeb8a0 100644
--- a/Doc/library/unittest.rst
+++ b/Doc/library/unittest.rst
@@ -954,7 +954,6 @@ Test cases
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 @@ Test cases
.. 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 @@ Grouping tests
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 @@ Loading and running tests
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 @@ Loading and running tests
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 @@ Loading and running tests
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 @@ Loading and running tests
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.
diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst
index f7dab79..9182c453 100644
--- a/Doc/whatsnew/2.7.rst
+++ b/Doc/whatsnew/2.7.rst
@@ -121,6 +121,31 @@ Some smaller changes made to the core Python language are:
(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 @@ changes, or look through the Subversion logs for all the details.
* 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`::
-
- >>> 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
+ raising a :exc:`KeyError`:
+
+ .. 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 @@ changes, or look through the Subversion logs for all the details.
'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 @@ changes, or look through the Subversion logs for all the details.
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 @@ changes, or look through the Subversion logs for all the details.
``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 @@ changes, or look through the Subversion logs for all the details.
(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 @@ changes, or look through the Subversion logs for all the details.
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 @@ Changes to Python's build process and to the C API include:
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 @@ Other Changes and Fixes
* 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
diff --git a/Lib/collections.py b/Lib/collections.py
index a90915a..6e2fe29 100644
--- a/Lib/collections.py
+++ b/Lib/collections.py
@@ -271,9 +271,12 @@ def namedtuple(typename, field_names, verbose=False, rename=False):
# 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
diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py
index c95cea0..517a7a9 100644
--- a/Lib/logging/__init__.py
+++ b/Lib/logging/__init__.py
@@ -756,7 +756,7 @@ class StreamHandler(Handler):
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 @@ class StreamHandler(Handler):
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()
diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py
index 0408a02..673f11f 100755
--- a/Lib/test/regrtest.py
+++ b/Lib/test/regrtest.py
@@ -663,6 +663,7 @@ def runtest_inner(test, generate, verbose, quiet, test_times,
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 @@ def cleanup_test_droppings(testname, verbose):
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 "
diff --git a/Lib/test/test_aifc.py b/Lib/test/test_aifc.py
index 0248615..4869bf3 100644
--- a/Lib/test/test_aifc.py
+++ b/Lib/test/test_aifc.py
@@ -27,7 +27,7 @@ class AIFCTest(unittest.TestCase):
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)
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
index ba0e0b8..37cab01 100644
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -3585,31 +3585,6 @@ order (MRO) for bases """
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 @@ order (MRO) for bases """
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...
diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py
index 1463cf7..69ec491 100644
--- a/Lib/test/test_logging.py
+++ b/Lib/test/test_logging.py
@@ -894,6 +894,7 @@ class EncodingTest(BaseTest):
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)
diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py
index cdb039d..5a546ec 100644
--- a/Lib/test/test_shutil.py
+++ b/Lib/test/test_shutil.py
@@ -46,9 +46,23 @@ class TestShutil(unittest.TestCase):
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:
diff --git a/Lib/test/test_unittest.py b/Lib/test/test_unittest.py
index d0d2049..e7097cc 100644
--- a/Lib/test/test_unittest.py
+++ b/Lib/test/test_unittest.py
@@ -9,9 +9,10 @@ Still need testing:
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 @@ class LoggingResult(unittest.TestResult):
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 @@ class Test_TestResult(TestCase):
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 Foo(unittest.TestCase):
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 @@ class Test_TestCase(TestCase, TestEquality, TestHashing):
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 @@ class Test_TestCase(TestCase, TestEquality, TestHashing):
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 @@ class Test_TestCase(TestCase, TestEquality, TestHashing):
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 @@ class Test_TestCase(TestCase, TestEquality, TestHashing):
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 @@ class Test_TestCase(TestCase, TestEquality, TestHashing):
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 @@ class Test_TestCase(TestCase, TestEquality, TestHashing):
# 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 @@ class TestLongMessage(TestCase):
"^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 @@ class TestLongMessage(TestCase):
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()
diff --git a/Lib/unittest.py b/Lib/unittest.py
index 0b7cea4..c6d893e 100644
--- a/Lib/unittest.py
+++ b/Lib/unittest.py
@@ -173,10 +173,22 @@ class TestResult(object):
"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 @@ class _AssertRaisesContext(object):
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 @@ class TestCase(object):
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 @@ class TestCase(object):
"""
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 @@ class TestCase(object):
(_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 @@ class TestSuite(object):
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 @@ class FunctionTestCase(TestCase):
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 @@ class TextTestRunner(object):
"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 @@ Examples:
"""
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 @@ Examples:
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 @@ Examples:
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
diff --git a/Modules/_ctypes/libffi.diff b/Modules/_ctypes/libffi.diff
new file mode 100644
index 0000000..6765902
--- /dev/null
+++ b/Modules/_ctypes/libffi.diff
@@ -0,0 +1,207 @@
+This file contains the diffs between the files in the libffi
+subdirectory and the 'official' source files from
+ftp://sourceware.org/pub/libffi/libffi-3.0.5.tar.gz
+
+Index: libffi/aclocal.m4
+===================================================================
+--- libffi/aclocal.m4 (working copy)
++++ libffi/aclocal.m4 (revision 72475)
+@@ -1155,7 +1155,7 @@
+ test -n "$_LT_AC_TAGVAR(runpath_var, $1)" || \
+ test "X$_LT_AC_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then
+
+- # We can hardcode non-existant directories.
++ # We can hardcode non-existent directories.
+ if test "$_LT_AC_TAGVAR(hardcode_direct, $1)" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+Index: libffi/configure.ac
+===================================================================
+--- libffi/configure.ac (working copy)
++++ libffi/configure.ac (revision 72475)
+@@ -1,4 +1,7 @@
+ dnl Process this with autoconf to create configure
++#
++# file from libffi - slightly patched for ctypes
++#
+
+ AC_PREREQ(2.59)
+
+@@ -83,6 +86,9 @@
+ i?86-*-solaris2.1[[0-9]]*)
+ TARGET=X86_64; TARGETDIR=x86
+ ;;
++ i*86-*-nto-qnx*)
++ TARGET=X86; TARGETDIR=x86
++ ;;
+ i?86-*-*)
+ TARGET=X86; TARGETDIR=x86
+ ;;
+@@ -100,10 +106,10 @@
+ ;;
+
+ mips-sgi-irix5.* | mips-sgi-irix6.*)
+- TARGET=MIPS; TARGETDIR=mips
++ TARGET=MIPS_IRIX; TARGETDIR=mips
+ ;;
+ mips*-*-linux*)
+- TARGET=MIPS; TARGETDIR=mips
++ TARGET=MIPS_LINUX; TARGETDIR=mips
+ ;;
+
+ powerpc*-*-linux* | powerpc-*-sysv*)
+@@ -156,7 +162,7 @@
+ AC_MSG_ERROR(["libffi has not been ported to $host."])
+ fi
+
+-AM_CONDITIONAL(MIPS, test x$TARGET = xMIPS)
++AM_CONDITIONAL(MIPS,[expr x$TARGET : 'xMIPS' > /dev/null])
+ AM_CONDITIONAL(SPARC, test x$TARGET = xSPARC)
+ AM_CONDITIONAL(X86, test x$TARGET = xX86)
+ AM_CONDITIONAL(X86_FREEBSD, test x$TARGET = xX86_FREEBSD)
+@@ -360,6 +366,10 @@
+
+ AC_CONFIG_LINKS(include/ffitarget.h:src/$TARGETDIR/ffitarget.h)
+
+-AC_CONFIG_FILES(include/Makefile include/ffi.h Makefile testsuite/Makefile man/Makefile libffi.pc)
++AC_CONFIG_FILES(include/ffi.h)
+
++AC_CONFIG_LINKS(include/ffi_common.h:include/ffi_common.h)
++
++AC_CONFIG_FILES(fficonfig.py)
++
+ AC_OUTPUT
+Index: libffi/configure
+===================================================================
+--- libffi/configure (working copy)
++++ libffi/configure (revision 72475)
+@@ -9546,7 +9546,7 @@
+ test -n "$runpath_var" || \
+ test "X$hardcode_automatic" = "Xyes" ; then
+
+- # We can hardcode non-existant directories.
++ # We can hardcode non-existent directories.
+ if test "$hardcode_direct" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+@@ -13514,7 +13514,7 @@
+ test -n "$runpath_var_CXX" || \
+ test "X$hardcode_automatic_CXX" = "Xyes" ; then
+
+- # We can hardcode non-existant directories.
++ # We can hardcode non-existent directories.
+ if test "$hardcode_direct_CXX" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+@@ -16117,7 +16117,7 @@
+ test -n "$runpath_var_F77" || \
+ test "X$hardcode_automatic_F77" = "Xyes" ; then
+
+- # We can hardcode non-existant directories.
++ # We can hardcode non-existent directories.
+ if test "$hardcode_direct_F77" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+@@ -18720,7 +18720,7 @@
+ test -n "$runpath_var_GCJ" || \
+ test "X$hardcode_automatic_GCJ" = "Xyes" ; then
+
+- # We can hardcode non-existant directories.
++ # We can hardcode non-existent directories.
+ if test "$hardcode_direct_GCJ" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+@@ -20406,6 +20406,9 @@
+ i?86-*-solaris2.1[0-9]*)
+ TARGET=X86_64; TARGETDIR=x86
+ ;;
++ i*86-*-nto-qnx*)
++ TARGET=X86; TARGETDIR=x86
++ ;;
+ i?86-*-*)
+ TARGET=X86; TARGETDIR=x86
+ ;;
+@@ -20423,10 +20426,10 @@
+ ;;
+
+ mips-sgi-irix5.* | mips-sgi-irix6.*)
+- TARGET=MIPS; TARGETDIR=mips
++ TARGET=MIPS_IRIX; TARGETDIR=mips
+ ;;
+ mips*-*-linux*)
+- TARGET=MIPS; TARGETDIR=mips
++ TARGET=MIPS_LINUX; TARGETDIR=mips
+ ;;
+
+ powerpc*-*-linux* | powerpc-*-sysv*)
+@@ -20481,7 +20484,7 @@
+ { (exit 1); exit 1; }; }
+ fi
+
+- if test x$TARGET = xMIPS; then
++ if expr x$TARGET : 'xMIPS' > /dev/null; then
+ MIPS_TRUE=
+ MIPS_FALSE='#'
+ else
+@@ -22712,9 +22715,15 @@
+ ac_config_links="$ac_config_links include/ffitarget.h:src/$TARGETDIR/ffitarget.h"
+
+
+-ac_config_files="$ac_config_files include/Makefile include/ffi.h Makefile testsuite/Makefile man/Makefile libffi.pc"
++ac_config_files="$ac_config_files include/ffi.h"
+
+
++ac_config_links="$ac_config_links include/ffi_common.h:include/ffi_common.h"
++
++
++ac_config_files="$ac_config_files fficonfig.py"
++
++
+ cat >confcache <<\_ACEOF
+ # This file is a shell script that caches the results of configure
+ # tests run on this system so they can be shared between configure
+@@ -23498,12 +23507,9 @@
+ "include") CONFIG_COMMANDS="$CONFIG_COMMANDS include" ;;
+ "src") CONFIG_COMMANDS="$CONFIG_COMMANDS src" ;;
+ "include/ffitarget.h") CONFIG_LINKS="$CONFIG_LINKS include/ffitarget.h:src/$TARGETDIR/ffitarget.h" ;;
+- "include/Makefile") CONFIG_FILES="$CONFIG_FILES include/Makefile" ;;
+ "include/ffi.h") CONFIG_FILES="$CONFIG_FILES include/ffi.h" ;;
+- "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+- "testsuite/Makefile") CONFIG_FILES="$CONFIG_FILES testsuite/Makefile" ;;
+- "man/Makefile") CONFIG_FILES="$CONFIG_FILES man/Makefile" ;;
+- "libffi.pc") CONFIG_FILES="$CONFIG_FILES libffi.pc" ;;
++ "include/ffi_common.h") CONFIG_LINKS="$CONFIG_LINKS include/ffi_common.h:include/ffi_common.h" ;;
++ "fficonfig.py") CONFIG_FILES="$CONFIG_FILES fficonfig.py" ;;
+
+ *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
+ echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+Index: libffi/src/x86/ffi.c
+===================================================================
+--- libffi/src/x86/ffi.c (working copy)
++++ libffi/src/x86/ffi.c (revision 72475)
+@@ -388,10 +388,10 @@
+ return FFI_BAD_ABI;
+ }
+
+- // we currently don't support certain kinds of arguments for raw
++ /* we currently don't support certain kinds of arguments for raw
+ // closures. This should be implemented by a separate assembly language
+ // routine, since it would require argument processing, something we
+- // don't do now for performance.
++ // don't do now for performance. */
+
+ for (i = cif->nargs-1; i >= 0; i--)
+ {
+Index: libffi/src/x86/ffi64.c
+===================================================================
+--- libffi/src/x86/ffi64.c (working copy)
++++ libffi/src/x86/ffi64.c (revision 72475)
+@@ -52,7 +52,7 @@
+ /* Register class used for passing given 64bit part of the argument.
+ These represent classes as documented by the PS ABI, with the exception
+ of SSESF, SSEDF classes, that are basically SSE class, just gcc will
+- use SF or DFmode move instead of DImode to avoid reformating penalties.
++ use SF or DFmode move instead of DImode to avoid reformatting penalties.
+
+ Similary we play games with INTEGERSI_CLASS to use cheaper SImode moves
+ whenever possible (upper half does contain padding). */