From 25c95f12987c08f446f355db6b9a807f3dea76a0 Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Fri, 8 May 2009 20:42:26 +0000 Subject: [PATCH] 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 (Mon, 30 Mar 2009) | 1 line Typo fixes ........ r71657 | vinay.sajip | 2009-04-16 14:07:37 -0500 (Thu, 16 Apr 2009) | 1 line Issue #5768: Change to Unicode output logic and test case for same. ........ r71721 | benjamin.peterson | 2009-04-18 14:26:19 -0500 (Sat, 18 Apr 2009) | 1 line fix a few nits in unittest.py #5771 ........ r71729 | benjamin.peterson | 2009-04-18 16:03:10 -0500 (Sat, 18 Apr 2009) | 1 line move test to a more appropiate one ........ r71794 | vinay.sajip | 2009-04-22 07:10:47 -0500 (Wed, 22 Apr 2009) | 2 lines Issue #5170: Fixed regression caused when fixing #5768. ........ r71976 | mark.dickinson | 2009-04-26 14:54:55 -0500 (Sun, 26 Apr 2009) | 2 lines Fix typo in function name ........ r72036 | georg.brandl | 2009-04-27 12:04:23 -0500 (Mon, 27 Apr 2009) | 1 line #5848: small unittest doc patch. ........ r72037 | georg.brandl | 2009-04-27 12:09:53 -0500 (Mon, 27 Apr 2009) | 1 line #5840: dont claim we dont support TLS. ........ r72079 | r.david.murray | 2009-04-28 14:02:55 -0500 (Tue, 28 Apr 2009) | 2 lines Remove spurious 'u'. ........ r72085 | georg.brandl | 2009-04-28 16:48:35 -0500 (Tue, 28 Apr 2009) | 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 (Wed, 29 Apr 2009) | 1 line fix test_shutil on ZFS #5676 ........ r72132 | georg.brandl | 2009-04-29 17:44:07 -0500 (Wed, 29 Apr 2009) | 1 line #5878: fix repr of re object. ........ r72133 | benjamin.peterson | 2009-04-29 17:44:15 -0500 (Wed, 29 Apr 2009) | 1 line make sure mode is removable while cleaning up test droppings ........ r72134 | benjamin.peterson | 2009-04-29 19:06:33 -0500 (Wed, 29 Apr 2009) | 1 line make sure to close file ........ r72191 | michael.foord | 2009-05-02 06:43:06 -0500 (Sat, 02 May 2009) | 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 (Sat, 02 May 2009) | 1 line don't let sys.argv be used in the tests ........ r72198 | andrew.kuchling | 2009-05-02 12:12:15 -0500 (Sat, 02 May 2009) | 1 line Add items ........ r72219 | michael.foord | 2009-05-02 15:15:05 -0500 (Sat, 02 May 2009) | 8 lines Add addCleanup and doCleanups to unittest.TestCase. Closes issue 5679. Michael Foord ........ r72221 | benjamin.peterson | 2009-05-02 15:26:53 -0500 (Sat, 02 May 2009) | 1 line add myself ........ r72225 | michael.foord | 2009-05-02 17:43:34 -0500 (Sat, 02 May 2009) | 1 line ........ r72303 | benjamin.peterson | 2009-05-04 19:55:24 -0500 (Mon, 04 May 2009) | 1 line using sys._getframe(x), where x > 0 doesnt' work on IronPython ........ r72434 | r.david.murray | 2009-05-07 13:09:58 -0500 (Thu, 07 May 2009) | 2 lines Pre-opened test file needs to be opened in binary mode. ........ r72467 | georg.brandl | 2009-05-08 07:17:34 -0500 (Fri, 08 May 2009) | 1 line Fix name. ........ r72476 | thomas.heller | 2009-05-08 15:09:40 -0500 (Fri, 08 May 2009) | 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. ........ --- Doc/c-api/init.rst | 7 +- Doc/howto/functional.rst | 2 +- Doc/howto/regex.rst | 2 +- Doc/library/2to3.rst | 1 + Doc/library/collections.rst | 6 +- Doc/library/decimal.rst | 2 +- Doc/library/json.rst | 4 +- Doc/library/shelve.rst | 3 +- Doc/library/subprocess.rst | 4 +- Doc/library/traceback.rst | 2 +- Doc/library/unittest.rst | 84 +++++++- Doc/whatsnew/2.7.rst | 92 ++++++-- Lib/collections.py | 7 +- Lib/logging/__init__.py | 20 +- Lib/test/regrtest.py | 5 + Lib/test/test_aifc.py | 2 +- Lib/test/test_descr.py | 55 ++--- Lib/test/test_logging.py | 1 + Lib/test/test_shutil.py | 18 +- Lib/test/test_unittest.py | 415 ++++++++++++++++++++++++++++++++---- Lib/unittest.py | 117 +++++++--- Modules/_ctypes/libffi.diff | 207 ++++++++++++++++++ 22 files changed, 910 insertions(+), 146 deletions(-) create mode 100644 Modules/_ctypes/libffi.diff diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index 299af7f338a..6e185faffa2 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 9aa0aed8f9e..920dc2dd58a 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 - + >>> next(gen) 0 >>> next(gen) diff --git a/Doc/howto/regex.rst b/Doc/howto/regex.rst index 262386781d2..714429834dd 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 - + <_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 90284afa1c6..9b2b4e41fbd 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 .. note:: diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst index c334dc78246..fca84bd48fa 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 2b4d1567a5d..a27fbf450d2 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 819c3392942..955c25bbcdf 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 8121004f56d..8c1f08b3540 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 3b6c8ccda9a..7952f6837ee 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 6929c1d6f81..5c427404003 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: [('', 10, '', 'lumberjack()'), ('', 4, 'lumberjack', 'bright_side_of_death()'), - (u'', 7, 'bright_side_of_death', 'return tuple()[0]')] + ('', 7, 'bright_side_of_death', 'return tuple()[0]')] *** format_tb: [' File "", line 10, in \n lumberjack()\n', ' File "", line 4, in lumberjack\n bright_side_of_death()\n', diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst index 675114a11f8..abeb8a0ad4b 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() -.. function:: main([module[, defaultTest[, argv[, testRunner[, testLoader]]]]]) + 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[, 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 f7dab797809..9182c45349d 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`:: + 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 @@ 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 a90915a50ea..6e2fe297d0c 100644 --- a/Lib/collections.py +++ b/Lib/collections.py @@ -271,9 +271,12 @@ def __getnewargs__(self): # 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 c95cea01d24..517a7a94f09 100644 --- a/Lib/logging/__init__.py +++ b/Lib/logging/__init__.py @@ -756,7 +756,7 @@ def emit(self, record): 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 @@ def emit(self, record): 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 0408a02c8e4..673f11fdd34 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 0248615c6ec..4869bf3cc4b 100644 --- a/Lib/test/test_aifc.py +++ b/Lib/test/test_aifc.py @@ -27,7 +27,7 @@ def tearDown(self): 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 ba0e0b8193f..37cab01f888 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -3585,31 +3585,6 @@ class E(D): 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 @@ def test_builtin_bases(self): 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 1463cf7a994..69ec49124d6 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -894,6 +894,7 @@ def test_encoding_cyrillic_unicode(self): 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 cdb039d4d07..5a546ecd87a 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -46,9 +46,23 @@ def test_on_error(self): 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 d0d20490602..e7097cc71ca 100644 --- a/Lib/test/test_unittest.py +++ b/Lib/test/test_unittest.py @@ -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 @@ def startTest(self, test): 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 @@ def test_1(self): 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 @@ def test1(self): pass 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,21 +2129,32 @@ def test_run_call_order__error_in_setUp(self): 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') - - def tearDown(self): - events.append('tearDown') - - Foo('test').run(result) + Foo(events).run(result) expected = ['startTest', 'setUp', 'addError', 'stopTest'] self.assertEqual(events, expected) + # "With a temporary result stopTestRun is called when setUp errors. + def test_run_call_order__error_in_setUp_default_result(self): + events = [] + + 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 # prior to each test. Likewise, if a tearDown() method is defined, the # test runner will invoke that method after each test. In the example, @@ -2093,20 +2166,32 @@ def test_run_call_order__error_in_test(self): 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 @@ def test_run_call_order__failure_in_test(self): 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 @@ def test_run_call_order__error_in_tearDown(self): 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 @@ def runTest(self): 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 @@ def defaultTestResult(self): # 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 @@ def testAssertIsNot(self): "^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 testAssertIsNot(self): 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 0b7cea4d5be..c6d893ea3a7 100644 --- a/Lib/unittest.py +++ b/Lib/unittest.py @@ -173,10 +173,22 @@ def startTest(self, test): "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 __init__(self, expected, test_case, callable_obj=None, 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 @@ def __init__(self, methodName='runTest'): 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 @@ def addTypeEqualityFunc(self, typeobj, function): """ 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 @@ def __repr__(self): (_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 __repr__(self): 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 @@ def __hash__(self): 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 @@ def run(self, test): "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 @@ class TestProgram(object): """ 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 @@ def __init__(self, module='__main__', defaultTest=None, 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 @@ def runTests(self): 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 00000000000..6765902ed00 --- /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). */