diff options
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/anydbm.py | 24 | ||||
-rw-r--r-- | Lib/collections.py | 230 | ||||
-rw-r--r-- | Lib/distutils/command/sdist.py | 25 | ||||
-rw-r--r-- | Lib/getpass.py | 2 | ||||
-rw-r--r-- | Lib/subprocess.py | 11 | ||||
-rw-r--r-- | Lib/tarfile.py | 2 | ||||
-rw-r--r-- | Lib/test/string_tests.py | 57 | ||||
-rw-r--r-- | Lib/test/test_bytes.py | 62 | ||||
-rw-r--r-- | Lib/test/test_collections.py | 9 | ||||
-rw-r--r-- | Lib/test/test_pydoc.py | 10 | ||||
-rw-r--r-- | Lib/test/test_startfile.py | 6 | ||||
-rw-r--r-- | Lib/test/test_str.py | 13 | ||||
-rw-r--r-- | Lib/test/test_tarfile.py | 28 | ||||
-rw-r--r-- | Lib/test/test_unicode.py | 11 | ||||
-rw-r--r-- | Lib/test/test_zipfile.py | 222 | ||||
-rw-r--r-- | Lib/unittest/case.py | 8 | ||||
-rw-r--r-- | Lib/unittest/test/test_case.py | 36 |
17 files changed, 512 insertions, 244 deletions
diff --git a/Lib/anydbm.py b/Lib/anydbm.py index 8b01ef3ea4..ba7e90510a 100644 --- a/Lib/anydbm.py +++ b/Lib/anydbm.py @@ -29,17 +29,8 @@ It has the following interface (key and data are strings): list = d.keys() # return a list of all existing keys (slow!) Future versions may change the order in which implementations are -tested for existence, add interfaces to other dbm-like +tested for existence, and add interfaces to other dbm-like implementations. - -The open function has an optional second argument. This can be 'r', -for read-only access, 'w', for read-write access of an existing -database, 'c' for read-write access to a new or existing database, and -'n' for read-write access to a new database. The default is 'r'. - -Note: 'r' and 'w' fail if the database doesn't exist; 'c' creates it -only if it doesn't exist; and 'n' always creates a new database. - """ class error(Exception): @@ -63,7 +54,18 @@ if not _defaultmod: error = tuple(_errors) -def open(file, flag = 'r', mode = 0666): +def open(file, flag='r', mode=0666): + """Open or create database at path given by *file*. + + Optional argument *flag* can be 'r' (default) for read-only access, 'w' + for read-write access of an existing database, 'c' for read-write access + to a new or existing database, and 'n' for read-write access to a new + database. + + Note: 'r' and 'w' fail if the database doesn't exist; 'c' creates it + only if it doesn't exist; and 'n' always creates a new database. + """ + # guess the type of an existing database from whichdb import whichdb result=whichdb(file) diff --git a/Lib/collections.py b/Lib/collections.py index bb6b15dbcc..d87c55d36b 100644 --- a/Lib/collections.py +++ b/Lib/collections.py @@ -6,37 +6,16 @@ import _abcoll __all__ += _abcoll.__all__ from _collections import deque, defaultdict -from operator import itemgetter as _itemgetter, eq as _eq +from operator import itemgetter as _itemgetter from keyword import iskeyword as _iskeyword import sys as _sys import heapq as _heapq -from itertools import repeat as _repeat, chain as _chain, starmap as _starmap, \ - ifilter as _ifilter, imap as _imap +from itertools import repeat as _repeat, chain as _chain, starmap as _starmap + try: - from thread import get_ident + from thread import get_ident as _get_ident except ImportError: - from dummy_thread import get_ident - -def _recursive_repr(user_function): - 'Decorator to make a repr function return "..." for a recursive call' - repr_running = set() - - def wrapper(self): - key = id(self), get_ident() - if key in repr_running: - return '...' - repr_running.add(key) - try: - result = user_function(self) - finally: - repr_running.discard(key) - return result - - # Can't use functools.wraps() here because of bootstrap issues - wrapper.__module__ = getattr(user_function, '__module__') - wrapper.__doc__ = getattr(user_function, '__doc__') - wrapper.__name__ = getattr(user_function, '__name__') - return wrapper + from dummy_thread import get_ident as _get_ident ################################################################################ @@ -48,17 +27,17 @@ class OrderedDict(dict): # An inherited dict maps keys to values. # The inherited dict provides __getitem__, __len__, __contains__, and get. # The remaining methods are order-aware. - # Big-O running times for all methods are the same as for regular dictionaries. + # Big-O running times for all methods are the same as regular dictionaries. - # The internal self.__map dictionary maps keys to links in a doubly linked list. + # The internal self.__map dict maps keys to links in a doubly linked list. # The circular doubly linked list starts and ends with a sentinel element. # The sentinel element never gets deleted (this simplifies the algorithm). # Each link is stored as a list of length three: [PREV, NEXT, KEY]. def __init__(self, *args, **kwds): - '''Initialize an ordered dictionary. Signature is the same as for - regular dictionaries, but keyword arguments are not recommended - because their insertion order is arbitrary. + '''Initialize an ordered dictionary. The signature is the same as + regular dictionaries, but keyword arguments are not recommended because + their insertion order is arbitrary. ''' if len(args) > 1: @@ -66,17 +45,15 @@ class OrderedDict(dict): try: self.__root except AttributeError: - self.__root = root = [None, None, None] # sentinel node - PREV = 0 - NEXT = 1 - root[PREV] = root[NEXT] = root + self.__root = root = [] # sentinel node + root[:] = [root, root, None] self.__map = {} self.__update(*args, **kwds) def __setitem__(self, key, value, PREV=0, NEXT=1, dict_setitem=dict.__setitem__): 'od.__setitem__(i, y) <==> od[i]=y' - # Setting a new item creates a new link which goes at the end of the linked - # list, and the inherited dictionary is updated with the new key/value pair. + # Setting a new item creates a new link at the end of the linked list, + # and the inherited dictionary is updated with the new key/value pair. if key not in self: root = self.__root last = root[PREV] @@ -85,79 +62,82 @@ class OrderedDict(dict): def __delitem__(self, key, PREV=0, NEXT=1, dict_delitem=dict.__delitem__): 'od.__delitem__(y) <==> del od[y]' - # Deleting an existing item uses self.__map to find the link which is - # then removed by updating the links in the predecessor and successor nodes. + # Deleting an existing item uses self.__map to find the link which gets + # removed by updating the links in the predecessor and successor nodes. dict_delitem(self, key) - link = self.__map.pop(key) - link_prev = link[PREV] - link_next = link[NEXT] + link_prev, link_next, key = self.__map.pop(key) link_prev[NEXT] = link_next link_next[PREV] = link_prev - def __iter__(self, NEXT=1, KEY=2): + def __iter__(self): 'od.__iter__() <==> iter(od)' # Traverse the linked list in order. + NEXT, KEY = 1, 2 root = self.__root curr = root[NEXT] while curr is not root: yield curr[KEY] curr = curr[NEXT] - def __reversed__(self, PREV=0, KEY=2): + def __reversed__(self): 'od.__reversed__() <==> reversed(od)' # Traverse the linked list in reverse order. + PREV, KEY = 0, 2 root = self.__root curr = root[PREV] while curr is not root: yield curr[KEY] curr = curr[PREV] - def __reduce__(self): - 'Return state information for pickling' - items = [[k, self[k]] for k in self] - tmp = self.__map, self.__root - del self.__map, self.__root - inst_dict = vars(self).copy() - self.__map, self.__root = tmp - if inst_dict: - return (self.__class__, (items,), inst_dict) - return self.__class__, (items,) - def clear(self): 'od.clear() -> None. Remove all items from od.' - try: - for node in self.__map.itervalues(): - del node[:] - self.__root[:] = [self.__root, self.__root, None] - self.__map.clear() - except AttributeError: - pass + for node in self.__map.itervalues(): + del node[:] + root = self.__root + root[:] = [root, root, None] + self.__map.clear() dict.clear(self) - update = __update = MutableMapping.update - keys = MutableMapping.keys - values = MutableMapping.values - items = MutableMapping.items - iterkeys = MutableMapping.iterkeys - itervalues = MutableMapping.itervalues - iteritems = MutableMapping.iteritems - __ne__ = MutableMapping.__ne__ + # -- the following methods do not depend on the internal structure -- - def viewkeys(self): - "od.viewkeys() -> a set-like object providing a view on od's keys" - return KeysView(self) + def keys(self): + 'od.keys() -> list of keys in od' + return list(self) - def viewvalues(self): - "od.viewvalues() -> an object providing a view on od's values" - return ValuesView(self) + def values(self): + 'od.values() -> list of values in od' + return [self[key] for key in self] - def viewitems(self): - "od.viewitems() -> a set-like object providing a view on od's items" - return ItemsView(self) + def items(self): + 'od.items() -> list of (key, value) pairs in od' + return [(key, self[key]) for key in self] + + def iterkeys(self): + 'od.iterkeys() -> an iterator over the keys in od' + return iter(self) + + def itervalues(self): + 'od.itervalues -> an iterator over the values in od' + for k in self: + yield self[k] + + def iteritems(self): + 'od.iteritems -> an iterator over the (key, value) pairs in od' + for k in self: + yield (k, self[k]) + + update = MutableMapping.update + + __update = update # let subclasses override update without breaking __init__ __marker = object() def pop(self, key, default=__marker): + '''od.pop(k[,d]) -> v, remove specified key and return the corresponding + value. If key is not found, d is returned if given, otherwise KeyError + is raised. + + ''' if key in self: result = self[key] del self[key] @@ -184,12 +164,28 @@ class OrderedDict(dict): value = self.pop(key) return key, value - @_recursive_repr - def __repr__(self): + def __repr__(self, _repr_running={}): 'od.__repr__() <==> repr(od)' - if not self: - return '%s()' % (self.__class__.__name__,) - return '%s(%r)' % (self.__class__.__name__, self.items()) + call_key = id(self), _get_ident() + if call_key in _repr_running: + return '...' + _repr_running[call_key] = 1 + try: + if not self: + return '%s()' % (self.__class__.__name__,) + return '%s(%r)' % (self.__class__.__name__, self.items()) + finally: + del _repr_running[call_key] + + def __reduce__(self): + 'Return state information for pickling' + items = [[k, self[k]] for k in self] + inst_dict = vars(self).copy() + for k in vars(OrderedDict()): + inst_dict.pop(k, None) + if inst_dict: + return (self.__class__, (items,), inst_dict) + return self.__class__, (items,) def copy(self): 'od.copy() -> a shallow copy of od' @@ -197,14 +193,14 @@ class OrderedDict(dict): @classmethod def fromkeys(cls, iterable, value=None): - '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S - and values equal to v (which defaults to None). + '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S. + If not specified, the value defaults to None. ''' - d = cls() + self = cls() for key in iterable: - d[key] = value - return d + self[key] = value + return self def __eq__(self, other): '''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive @@ -212,10 +208,27 @@ class OrderedDict(dict): ''' if isinstance(other, OrderedDict): - return len(self)==len(other) and \ - all(_imap(_eq, self.iteritems(), other.iteritems())) + return len(self)==len(other) and self.items() == other.items() return dict.__eq__(self, other) + def __ne__(self, other): + 'od.__ne__(y) <==> od!=y' + return not self == other + + # -- the following methods support python 3.x style dictionary views -- + + def viewkeys(self): + "od.viewkeys() -> a set-like object providing a view on od's keys" + return KeysView(self) + + def viewvalues(self): + "od.viewvalues() -> an object providing a view on od's values" + return ValuesView(self) + + def viewitems(self): + "od.viewitems() -> a set-like object providing a view on od's items" + return ItemsView(self) + ################################################################################ ### namedtuple @@ -516,8 +529,8 @@ class Counter(dict): self.subtract(kwds) def copy(self): - 'Like dict.copy() but returns a Counter instance instead of a dict.' - return Counter(self) + 'Return a shallow copy.' + return self.__class__(self) def __reduce__(self): return self.__class__, (dict(self),) @@ -552,10 +565,13 @@ class Counter(dict): if not isinstance(other, Counter): return NotImplemented result = Counter() - for elem in set(self) | set(other): - newcount = self[elem] + other[elem] + for elem, count in self.items(): + newcount = count + other[elem] if newcount > 0: result[elem] = newcount + for elem, count in other.items(): + if elem not in self and count > 0: + result[elem] = count return result def __sub__(self, other): @@ -568,10 +584,13 @@ class Counter(dict): if not isinstance(other, Counter): return NotImplemented result = Counter() - for elem in set(self) | set(other): - newcount = self[elem] - other[elem] + for elem, count in self.items(): + newcount = count - other[elem] if newcount > 0: result[elem] = newcount + for elem, count in other.items(): + if elem not in self and count < 0: + result[elem] = 0 - count return result def __or__(self, other): @@ -584,11 +603,14 @@ class Counter(dict): if not isinstance(other, Counter): return NotImplemented result = Counter() - for elem in set(self) | set(other): - p, q = self[elem], other[elem] - newcount = q if p < q else p + for elem, count in self.items(): + other_count = other[elem] + newcount = other_count if count < other_count else count if newcount > 0: result[elem] = newcount + for elem, count in other.items(): + if elem not in self and count > 0: + result[elem] = count return result def __and__(self, other): @@ -601,11 +623,9 @@ class Counter(dict): if not isinstance(other, Counter): return NotImplemented result = Counter() - if len(self) < len(other): - self, other = other, self - for elem in _ifilter(self.__contains__, other): - p, q = self[elem], other[elem] - newcount = p if p < q else q + for elem, count in self.items(): + other_count = other[elem] + newcount = count if count < other_count else other_count if newcount > 0: result[elem] = newcount return result diff --git a/Lib/distutils/command/sdist.py b/Lib/distutils/command/sdist.py index 0c3b0b55bf..cf8982bd9d 100644 --- a/Lib/distutils/command/sdist.py +++ b/Lib/distutils/command/sdist.py @@ -306,17 +306,20 @@ class sdist(Command): rstrip_ws=1, collapse_join=1) - while 1: - line = template.readline() - if line is None: # end of file - break - - try: - self.filelist.process_template_line(line) - except DistutilsTemplateError, msg: - self.warn("%s, line %d: %s" % (template.filename, - template.current_line, - msg)) + try: + while 1: + line = template.readline() + if line is None: # end of file + break + + try: + self.filelist.process_template_line(line) + except DistutilsTemplateError, msg: + self.warn("%s, line %d: %s" % (template.filename, + template.current_line, + msg)) + finally: + template.close() def prune_file_list(self): """Prune off branches that might slip into the file list as created diff --git a/Lib/getpass.py b/Lib/getpass.py index 4745ea944c..2ac6fd7f38 100644 --- a/Lib/getpass.py +++ b/Lib/getpass.py @@ -62,7 +62,7 @@ def unix_getpass(prompt='Password: ', stream=None): try: old = termios.tcgetattr(fd) # a copy to save new = old[:] - new[3] &= ~(termios.ECHO|termios.ISIG) # 3 == 'lflags' + new[3] &= ~termios.ECHO # 3 == 'lflags' tcsetattr_flags = termios.TCSAFLUSH if hasattr(termios, 'TCSASOFT'): tcsetattr_flags |= termios.TCSASOFT diff --git a/Lib/subprocess.py b/Lib/subprocess.py index 25248dc0d3..3734acde33 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -441,8 +441,15 @@ __all__ = ["Popen", "PIPE", "STDOUT", "call", "check_call", "check_output", "CalledProcessError"] if mswindows: - from _subprocess import CREATE_NEW_CONSOLE, CREATE_NEW_PROCESS_GROUP - __all__.extend(["CREATE_NEW_CONSOLE", "CREATE_NEW_PROCESS_GROUP"]) + from _subprocess import (CREATE_NEW_CONSOLE, CREATE_NEW_PROCESS_GROUP, + STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, + STD_ERROR_HANDLE, SW_HIDE, + STARTF_USESTDHANDLES, STARTF_USESHOWWINDOW) + + __all__.extend(["CREATE_NEW_CONSOLE", "CREATE_NEW_PROCESS_GROUP", + "STD_INPUT_HANDLE", "STD_OUTPUT_HANDLE", + "STD_ERROR_HANDLE", "SW_HIDE", + "STARTF_USESTDHANDLES", "STARTF_USESHOWWINDOW"]) try: MAXFD = os.sysconf("SC_OPEN_MAX") except: diff --git a/Lib/tarfile.py b/Lib/tarfile.py index 47be1d49df..105a75880d 100644 --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -2239,6 +2239,8 @@ class TarFile(object): if hasattr(os, "symlink") and hasattr(os, "link"): # For systems that support symbolic and hard links. if tarinfo.issym(): + if os.path.exists(targetpath): + os.unlink(targetpath) os.symlink(tarinfo.linkname, targetpath) else: # See extract(). diff --git a/Lib/test/string_tests.py b/Lib/test/string_tests.py index 546b486a84..5931f3d88b 100644 --- a/Lib/test/string_tests.py +++ b/Lib/test/string_tests.py @@ -1177,6 +1177,63 @@ class MixinStrUnicodeUserStringTest: # mixed use of str and unicode self.assertEqual('a/b/c'.rpartition(u'/'), ('a/b', '/', 'c')) + def test_none_arguments(self): + # issue 11828 + s = 'hello' + self.checkequal(2, s, 'find', 'l', None) + self.checkequal(3, s, 'find', 'l', -2, None) + self.checkequal(2, s, 'find', 'l', None, -2) + self.checkequal(0, s, 'find', 'h', None, None) + + self.checkequal(3, s, 'rfind', 'l', None) + self.checkequal(3, s, 'rfind', 'l', -2, None) + self.checkequal(2, s, 'rfind', 'l', None, -2) + self.checkequal(0, s, 'rfind', 'h', None, None) + + self.checkequal(2, s, 'index', 'l', None) + self.checkequal(3, s, 'index', 'l', -2, None) + self.checkequal(2, s, 'index', 'l', None, -2) + self.checkequal(0, s, 'index', 'h', None, None) + + self.checkequal(3, s, 'rindex', 'l', None) + self.checkequal(3, s, 'rindex', 'l', -2, None) + self.checkequal(2, s, 'rindex', 'l', None, -2) + self.checkequal(0, s, 'rindex', 'h', None, None) + + self.checkequal(2, s, 'count', 'l', None) + self.checkequal(1, s, 'count', 'l', -2, None) + self.checkequal(1, s, 'count', 'l', None, -2) + self.checkequal(0, s, 'count', 'x', None, None) + + self.checkequal(True, s, 'endswith', 'o', None) + self.checkequal(True, s, 'endswith', 'lo', -2, None) + self.checkequal(True, s, 'endswith', 'l', None, -2) + self.checkequal(False, s, 'endswith', 'x', None, None) + + self.checkequal(True, s, 'startswith', 'h', None) + self.checkequal(True, s, 'startswith', 'l', -2, None) + self.checkequal(True, s, 'startswith', 'h', None, -2) + self.checkequal(False, s, 'startswith', 'x', None, None) + + def test_find_etc_raise_correct_error_messages(self): + # issue 11828 + s = 'hello' + x = 'x' + self.assertRaisesRegexp(TypeError, r'\bfind\b', s.find, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'\brfind\b', s.rfind, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'\bindex\b', s.index, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'\brindex\b', s.rindex, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'^count\(', s.count, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'^startswith\(', s.startswith, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'^endswith\(', s.endswith, + x, None, None, None) + class MixinStrStringUserStringTest: # Additional tests for 8bit strings, i.e. str, UserString and # the string module diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py index 2026cdbde1..2ef1c8819f 100644 --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -456,6 +456,68 @@ class BaseBytesTest(unittest.TestCase): self.assertEqual([ord(b[i:i+1]) for i in range(len(b))], [0, 65, 127, 128, 255]) + def test_none_arguments(self): + # issue 11828 + b = self.type2test(b'hello') + l = self.type2test(b'l') + h = self.type2test(b'h') + x = self.type2test(b'x') + o = self.type2test(b'o') + + self.assertEqual(2, b.find(l, None)) + self.assertEqual(3, b.find(l, -2, None)) + self.assertEqual(2, b.find(l, None, -2)) + self.assertEqual(0, b.find(h, None, None)) + + self.assertEqual(3, b.rfind(l, None)) + self.assertEqual(3, b.rfind(l, -2, None)) + self.assertEqual(2, b.rfind(l, None, -2)) + self.assertEqual(0, b.rfind(h, None, None)) + + self.assertEqual(2, b.index(l, None)) + self.assertEqual(3, b.index(l, -2, None)) + self.assertEqual(2, b.index(l, None, -2)) + self.assertEqual(0, b.index(h, None, None)) + + self.assertEqual(3, b.rindex(l, None)) + self.assertEqual(3, b.rindex(l, -2, None)) + self.assertEqual(2, b.rindex(l, None, -2)) + self.assertEqual(0, b.rindex(h, None, None)) + + self.assertEqual(2, b.count(l, None)) + self.assertEqual(1, b.count(l, -2, None)) + self.assertEqual(1, b.count(l, None, -2)) + self.assertEqual(0, b.count(x, None, None)) + + self.assertEqual(True, b.endswith(o, None)) + self.assertEqual(True, b.endswith(o, -2, None)) + self.assertEqual(True, b.endswith(l, None, -2)) + self.assertEqual(False, b.endswith(x, None, None)) + + self.assertEqual(True, b.startswith(h, None)) + self.assertEqual(True, b.startswith(l, -2, None)) + self.assertEqual(True, b.startswith(h, None, -2)) + self.assertEqual(False, b.startswith(x, None, None)) + + def test_find_etc_raise_correct_error_messages(self): + # issue 11828 + b = self.type2test(b'hello') + x = self.type2test(b'x') + self.assertRaisesRegexp(TypeError, r'\bfind\b', b.find, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'\brfind\b', b.rfind, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'\bindex\b', b.index, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'\brindex\b', b.rindex, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'\bcount\b', b.count, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'\bstartswith\b', b.startswith, + x, None, None, None) + self.assertRaisesRegexp(TypeError, r'\bendswith\b', b.endswith, + x, None, None, None) + class ByteArrayTest(BaseBytesTest): type2test = bytearray diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py index f6a43fcb1f..8bdeb3d8f1 100644 --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -689,6 +689,15 @@ class TestCounter(unittest.TestCase): self.assertEqual(len(dup), len(words)) self.assertEqual(type(dup), type(words)) + def test_copy_subclass(self): + class MyCounter(Counter): + pass + c = MyCounter('slartibartfast') + d = c.copy() + self.assertEqual(d, c) + self.assertEqual(len(d), len(c)) + self.assertEqual(type(d), type(c)) + def test_conversions(self): # Convert to: set, list, dict s = 'she sells sea shells by the sea shore' diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py index 2e67290d00..8591693238 100644 --- a/Lib/test/test_pydoc.py +++ b/Lib/test/test_pydoc.py @@ -6,6 +6,7 @@ import subprocess import re import pydoc import inspect +import keyword import unittest import xml.etree import test.test_support @@ -351,9 +352,16 @@ class TestDescriptions(unittest.TestCase): self.assertIn('_asdict', helptext) +class TestHelper(unittest.TestCase): + def test_keywords(self): + self.assertEqual(sorted(pydoc.Helper.keywords), + sorted(keyword.kwlist)) + + def test_main(): test.test_support.run_unittest(PyDocDocTest, - TestDescriptions) + TestDescriptions, + TestHelper) if __name__ == "__main__": test_main() diff --git a/Lib/test/test_startfile.py b/Lib/test/test_startfile.py index 8eeae72eab..9dce8fd6ac 100644 --- a/Lib/test/test_startfile.py +++ b/Lib/test/test_startfile.py @@ -11,6 +11,7 @@ import unittest from test import test_support import os from os import path +from time import sleep startfile = test_support.get_attribute(os, 'startfile') @@ -26,11 +27,16 @@ class TestCase(unittest.TestCase): empty = path.join(path.dirname(__file__), "empty.vbs") startfile(empty) startfile(empty, "open") + # Give the child process some time to exit before we finish. + # Otherwise the cleanup code will not be able to delete the cwd, + # because it is still in use. + sleep(0.1) def test_empty_u(self): empty = path.join(path.dirname(__file__), "empty.vbs") startfile(unicode(empty, "mbcs")) startfile(unicode(empty, "mbcs"), "open") + sleep(0.1) def test_main(): test_support.run_unittest(TestCase) diff --git a/Lib/test/test_str.py b/Lib/test/test_str.py index 4f88b28848..2ecf3276b4 100644 --- a/Lib/test/test_str.py +++ b/Lib/test/test_str.py @@ -414,7 +414,18 @@ class StrTest( self.assertEqual('Andr\202 x'.decode('ascii', 'replace'), 'Andr\202 x'.decode(encoding='ascii', errors='replace')) - + def test_startswith_endswith_errors(self): + with self.assertRaises(UnicodeDecodeError): + '\xff'.startswith(u'x') + with self.assertRaises(UnicodeDecodeError): + '\xff'.endswith(u'x') + for meth in ('foo'.startswith, 'foo'.endswith): + with self.assertRaises(TypeError) as cm: + meth(['f']) + exc = str(cm.exception) + self.assertIn('unicode', exc) + self.assertIn('str', exc) + self.assertIn('tuple', exc) def test_main(): test_support.run_unittest(StrTest) diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py index cda5262acc..f78f9ce03f 100644 --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -843,6 +843,34 @@ class WriteTest(WriteTestBase): finally: os.chdir(cwd) + @unittest.skipUnless(hasattr(os, 'symlink'), "needs os.symlink") + def test_extractall_symlinks(self): + # Test if extractall works properly when tarfile contains symlinks + tempdir = os.path.join(TEMPDIR, "testsymlinks") + temparchive = os.path.join(TEMPDIR, "testsymlinks.tar") + os.mkdir(tempdir) + try: + source_file = os.path.join(tempdir,'source') + target_file = os.path.join(tempdir,'symlink') + with open(source_file,'w') as f: + f.write('something\n') + os.symlink(source_file, target_file) + tar = tarfile.open(temparchive,'w') + tar.add(source_file, arcname=os.path.basename(source_file)) + tar.add(target_file, arcname=os.path.basename(target_file)) + tar.close() + # Let's extract it to the location which contains the symlink + tar = tarfile.open(temparchive,'r') + # this should not raise OSError: [Errno 17] File exists + try: + tar.extractall(path=tempdir) + except OSError: + self.fail("extractall failed with symlinked files") + finally: + tar.close() + finally: + os.unlink(temparchive) + shutil.rmtree(tempdir) class StreamWriteTest(WriteTestBase): diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py index ae4c355f48..bd43dbc57b 100644 --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -442,6 +442,17 @@ class UnicodeTest( return u'\u1234' self.assertEqual('%s' % Wrapper(), u'\u1234') + def test_startswith_endswith_errors(self): + for meth in (u'foo'.startswith, u'foo'.endswith): + with self.assertRaises(UnicodeDecodeError): + meth('\xff') + with self.assertRaises(TypeError) as cm: + meth(['f']) + exc = str(cm.exception) + self.assertIn('unicode', exc) + self.assertIn('str', exc) + self.assertIn('tuple', exc) + @test_support.run_with_locale('LC_ALL', 'de_DE', 'fr_FR') def test_format_float(self): # should not format with a comma, but always with C locale diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py index 7c8c0c5542..c4a64a3b4b 100644 --- a/Lib/test/test_zipfile.py +++ b/Lib/test/test_zipfile.py @@ -115,20 +115,20 @@ class TestsWithSourceFile(unittest.TestCase): # Read the ZIP archive with zipfile.ZipFile(f, "r", compression) as zipfp: zipdata1 = [] - zipopen1 = zipfp.open(TESTFN) - while True: - read_data = zipopen1.read(256) - if not read_data: - break - zipdata1.append(read_data) + with zipfp.open(TESTFN) as zipopen1: + while True: + read_data = zipopen1.read(256) + if not read_data: + break + zipdata1.append(read_data) zipdata2 = [] - zipopen2 = zipfp.open("another.name") - while True: - read_data = zipopen2.read(256) - if not read_data: - break - zipdata2.append(read_data) + with zipfp.open("another.name") as zipopen2: + while True: + read_data = zipopen2.read(256) + if not read_data: + break + zipdata2.append(read_data) self.assertEqual(''.join(zipdata1), self.data) self.assertEqual(''.join(zipdata2), self.data) @@ -147,7 +147,8 @@ class TestsWithSourceFile(unittest.TestCase): infos = zipfp.infolist() data = "" for info in infos: - data += zipfp.open(info).read() + with zipfp.open(info) as f: + data += f.read() self.assertTrue(data == "foobar" or data == "barfoo") data = "" for info in infos: @@ -160,12 +161,12 @@ class TestsWithSourceFile(unittest.TestCase): # Read the ZIP archive with zipfile.ZipFile(f, "r", compression) as zipfp: zipdata1 = [] - zipopen1 = zipfp.open(TESTFN) - while True: - read_data = zipopen1.read(randint(1, 1024)) - if not read_data: - break - zipdata1.append(read_data) + with zipfp.open(TESTFN) as zipopen1: + while True: + read_data = zipopen1.read(randint(1, 1024)) + if not read_data: + break + zipdata1.append(read_data) self.assertEqual(''.join(zipdata1), self.data) @@ -177,16 +178,14 @@ class TestsWithSourceFile(unittest.TestCase): f = StringIO() data = 'a\r\n' * 16 * 1024 - zipfp = zipfile.ZipFile(f, 'w', zipfile.ZIP_STORED) - zipfp.writestr(TESTFN, data) - zipfp.close() + with zipfile.ZipFile(f, 'w', zipfile.ZIP_STORED) as zipfp: + zipfp.writestr(TESTFN, data) data2 = '' - zipfp = zipfile.ZipFile(f, 'r') - zipopen = zipfp.open(TESTFN, 'rU') - for line in zipopen: - data2 += line - zipfp.close() + with zipfile.ZipFile(f, 'r') as zipfp: + with zipfp.open(TESTFN, 'rU') as zipopen: + for line in zipopen: + data2 += line self.assertEqual(data, data2.replace('\n', '\r\n')) @@ -194,42 +193,41 @@ class TestsWithSourceFile(unittest.TestCase): self.make_test_archive(f, compression) # Read the ZIP archive - zipfp = zipfile.ZipFile(f, "r") - zipopen = zipfp.open(TESTFN) - - data = '' - while True: - read = zipopen.readline() - if not read: - break - data += read - - read = zipopen.read(100) - if not read: - break - data += read + with zipfile.ZipFile(f, "r") as zipfp: + with zipfp.open(TESTFN) as zipopen: + data = '' + while True: + read = zipopen.readline() + if not read: + break + data += read + + read = zipopen.read(100) + if not read: + break + data += read self.assertEqual(data, self.data) - zipfp.close() def zip_readline_test(self, f, compression): self.make_test_archive(f, compression) # Read the ZIP archive with zipfile.ZipFile(f, "r") as zipfp: - zipopen = zipfp.open(TESTFN) - for line in self.line_gen: - linedata = zipopen.readline() - self.assertEqual(linedata, line + '\n') + with zipfp.open(TESTFN) as zipopen: + for line in self.line_gen: + linedata = zipopen.readline() + self.assertEqual(linedata, line + '\n') def zip_readlines_test(self, f, compression): self.make_test_archive(f, compression) # Read the ZIP archive with zipfile.ZipFile(f, "r") as zipfp: - ziplines = zipfp.open(TESTFN).readlines() - for line, zipline in zip(self.line_gen, ziplines): - self.assertEqual(zipline, line + '\n') + with zipfp.open(TESTFN) as zo: + ziplines = zo.readlines() + for line, zipline in zip(self.line_gen, ziplines): + self.assertEqual(zipline, line + '\n') def zip_iterlines_test(self, f, compression): self.make_test_archive(f, compression) @@ -301,9 +299,9 @@ class TestsWithSourceFile(unittest.TestCase): # Get an open object for strfile with zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_DEFLATED) as zipfp: - openobj = zipfp.open("strfile") - self.assertEqual(openobj.read(1), '1') - self.assertEqual(openobj.read(1), '2') + with zipfp.open("strfile") as openobj: + self.assertEqual(openobj.read(1), '1') + self.assertEqual(openobj.read(1), '2') def test_absolute_arcnames(self): with zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) as zipfp: @@ -775,8 +773,8 @@ class OtherTests(unittest.TestCase): self.assertRaises(IOError, zipfile.ZipFile, TESTFN) def test_empty_file_raises_BadZipFile(self): - f = open(TESTFN, 'w') - f.close() + with open(TESTFN, 'w') as f: + pass self.assertRaises(zipfile.BadZipfile, zipfile.ZipFile, TESTFN) with open(TESTFN, 'w') as fp: @@ -820,11 +818,11 @@ class OtherTests(unittest.TestCase): with zipfile.ZipFile(TESTFN, mode="w") as zipf: zipf.writestr("foo.txt", "O, for a Muse of Fire!") # read the data to make sure the file is there - f = zipf.open("foo.txt") - for i in xrange(FIXEDTEST_SIZE): - self.assertEqual(f.read(0), '') + with zipf.open("foo.txt") as f: + for i in xrange(FIXEDTEST_SIZE): + self.assertEqual(f.read(0), '') - self.assertEqual(f.read(), "O, for a Muse of Fire!") + self.assertEqual(f.read(), "O, for a Muse of Fire!") def test_open_non_existent_item(self): """Check that attempting to call open() for an item that doesn't @@ -952,15 +950,15 @@ class OtherTests(unittest.TestCase): def test_empty_zipfile(self): # Check that creating a file in 'w' or 'a' mode and closing without # adding any files to the archives creates a valid empty ZIP file - zipf = zipfile.ZipFile(TESTFN, mode="w") - zipf.close() + with zipfile.ZipFile(TESTFN, mode="w") as zipf: + pass try: zipf = zipfile.ZipFile(TESTFN, mode="r") except zipfile.BadZipfile: self.fail("Unable to create empty ZIP file in 'w' mode") - zipf = zipfile.ZipFile(TESTFN, mode="a") - zipf.close() + with zipfile.ZipFile(TESTFN, mode="a") as zipf: + pass try: zipf = zipfile.ZipFile(TESTFN, mode="r") except: @@ -970,8 +968,8 @@ class OtherTests(unittest.TestCase): # Issue 1710703: Check that opening a file with less than 22 bytes # raises a BadZipfile exception (rather than the previously unhelpful # IOError) - f = open(TESTFN, 'w') - f.close() + with open(TESTFN, 'w') as f: + pass self.assertRaises(zipfile.BadZipfile, zipfile.ZipFile, TESTFN, 'r') def tearDown(self): @@ -1084,20 +1082,20 @@ class TestsWithRandomBinaryFiles(unittest.TestCase): # Read the ZIP archive with zipfile.ZipFile(f, "r", compression) as zipfp: zipdata1 = [] - zipopen1 = zipfp.open(TESTFN) - while True: - read_data = zipopen1.read(256) - if not read_data: - break - zipdata1.append(read_data) + with zipfp.open(TESTFN) as zipopen1: + while True: + read_data = zipopen1.read(256) + if not read_data: + break + zipdata1.append(read_data) zipdata2 = [] - zipopen2 = zipfp.open("another.name") - while True: - read_data = zipopen2.read(256) - if not read_data: - break - zipdata2.append(read_data) + with zipfp.open("another.name") as zipopen2: + while True: + read_data = zipopen2.read(256) + if not read_data: + break + zipdata2.append(read_data) testdata1 = ''.join(zipdata1) self.assertEqual(len(testdata1), len(self.data)) @@ -1122,12 +1120,12 @@ class TestsWithRandomBinaryFiles(unittest.TestCase): # Read the ZIP archive with zipfile.ZipFile(f, "r", compression) as zipfp: zipdata1 = [] - zipopen1 = zipfp.open(TESTFN) - while True: - read_data = zipopen1.read(randint(1, 1024)) - if not read_data: - break - zipdata1.append(read_data) + with zipfp.open(TESTFN) as zipopen1: + while True: + read_data = zipopen1.read(randint(1, 1024)) + if not read_data: + break + zipdata1.append(read_data) testdata = ''.join(zipdata1) self.assertEqual(len(testdata), len(self.data)) @@ -1167,12 +1165,11 @@ class TestsWithMultipleOpens(unittest.TestCase): # Verify that (when the ZipFile is in control of creating file objects) # multiple open() calls can be made without interfering with each other. with zipfile.ZipFile(TESTFN2, mode="r") as zipf: - zopen1 = zipf.open('ones') - zopen2 = zipf.open('twos') - data1 = zopen1.read(500) - data2 = zopen2.read(500) - data1 += zopen1.read(500) - data2 += zopen2.read(500) + with zipf.open('ones') as zopen1, zipf.open('twos') as zopen2: + data1 = zopen1.read(500) + data2 = zopen2.read(500) + data1 += zopen1.read(500) + data2 += zopen2.read(500) self.assertEqual(data1, '1'*FIXEDTEST_SIZE) self.assertEqual(data2, '2'*FIXEDTEST_SIZE) @@ -1180,12 +1177,11 @@ class TestsWithMultipleOpens(unittest.TestCase): # Verify that (when the ZipFile is in control of creating file objects) # multiple open() calls can be made without interfering with each other. with zipfile.ZipFile(TESTFN2, mode="r") as zipf: - zopen1 = zipf.open('ones') - data1 = zopen1.read(500) - zopen2 = zipf.open('twos') - data2 = zopen2.read(500) - data1 += zopen1.read(500) - data2 += zopen2.read(500) + with zipf.open('ones') as zopen1, zipf.open('twos') as zopen2: + data1 = zopen1.read(500) + data2 = zopen2.read(500) + data1 += zopen1.read(500) + data2 += zopen2.read(500) self.assertEqual(data1, '1'*FIXEDTEST_SIZE) self.assertEqual(data2, '2'*FIXEDTEST_SIZE) @@ -1244,7 +1240,8 @@ class UniversalNewlineTests(unittest.TestCase): # Read the ZIP archive with zipfile.ZipFile(f, "r") as zipfp: for sep, fn in self.arcfiles.items(): - zipdata = zipfp.open(fn, "rU").read() + with zipfp.open(fn, "rU") as fp: + zipdata = fp.read() self.assertEqual(self.arcdata[sep], zipdata) def readline_read_test(self, f, compression): @@ -1253,18 +1250,18 @@ class UniversalNewlineTests(unittest.TestCase): # Read the ZIP archive zipfp = zipfile.ZipFile(f, "r") for sep, fn in self.arcfiles.items(): - zipopen = zipfp.open(fn, "rU") - data = '' - while True: - read = zipopen.readline() - if not read: - break - data += read - - read = zipopen.read(5) - if not read: - break - data += read + with zipfp.open(fn, "rU") as zipopen: + data = '' + while True: + read = zipopen.readline() + if not read: + break + data += read + + read = zipopen.read(5) + if not read: + break + data += read self.assertEqual(data, self.arcdata['\n']) @@ -1276,10 +1273,10 @@ class UniversalNewlineTests(unittest.TestCase): # Read the ZIP archive with zipfile.ZipFile(f, "r") as zipfp: for sep, fn in self.arcfiles.items(): - zipopen = zipfp.open(fn, "rU") - for line in self.line_gen: - linedata = zipopen.readline() - self.assertEqual(linedata, line + '\n') + with zipfp.open(fn, "rU") as zipopen: + for line in self.line_gen: + linedata = zipopen.readline() + self.assertEqual(linedata, line + '\n') def readlines_test(self, f, compression): self.make_test_archive(f, compression) @@ -1287,7 +1284,8 @@ class UniversalNewlineTests(unittest.TestCase): # Read the ZIP archive with zipfile.ZipFile(f, "r") as zipfp: for sep, fn in self.arcfiles.items(): - ziplines = zipfp.open(fn, "rU").readlines() + with zipfp.open(fn, "rU") as fp: + ziplines = fp.readlines() for line, zipline in zip(self.line_gen, ziplines): self.assertEqual(zipline, line + '\n') diff --git a/Lib/unittest/case.py b/Lib/unittest/case.py index ecb6a3e419..dcaae93aed 100644 --- a/Lib/unittest/case.py +++ b/Lib/unittest/case.py @@ -169,6 +169,10 @@ class TestCase(object): maxDiff = 80*8 + # If a string is longer than _diffThreshold, use normal comparison instead + # of difflib. See #11763. + _diffThreshold = 2**16 + # Attribute used by TestSuite for classSetUp _classSetupFailed = False @@ -900,6 +904,10 @@ class TestCase(object): 'Second argument is not a string') if first != second: + # don't use difflib if the strings are too long + if (len(first) > self._diffThreshold or + len(second) > self._diffThreshold): + self._baseAssertEqual(first, second, msg) firstlines = first.splitlines(True) secondlines = second.splitlines(True) if len(firstlines) == 1 and first.strip('\r\n') == first: diff --git a/Lib/unittest/test/test_case.py b/Lib/unittest/test/test_case.py index 06eeda1503..2e449c5c2a 100644 --- a/Lib/unittest/test/test_case.py +++ b/Lib/unittest/test/test_case.py @@ -667,6 +667,42 @@ class Test_TestCase(unittest.TestCase, TestEquality, TestHashing): else: self.fail('assertMultiLineEqual did not fail') + def testAssertEqual_diffThreshold(self): + # check threshold value + self.assertEqual(self._diffThreshold, 2**16) + # disable madDiff to get diff markers + self.maxDiff = None + + # set a lower threshold value and add a cleanup to restore it + old_threshold = self._diffThreshold + self._diffThreshold = 2**8 + self.addCleanup(lambda: setattr(self, '_diffThreshold', old_threshold)) + + # under the threshold: diff marker (^) in error message + s = u'x' * (2**7) + with self.assertRaises(self.failureException) as cm: + self.assertEqual(s + 'a', s + 'b') + self.assertIn('^', str(cm.exception)) + self.assertEqual(s + 'a', s + 'a') + + # over the threshold: diff not used and marker (^) not in error message + s = u'x' * (2**9) + # if the path that uses difflib is taken, _truncateMessage will be + # called -- replace it with explodingTruncation to verify that this + # doesn't happen + def explodingTruncation(message, diff): + raise SystemError('this should not be raised') + old_truncate = self._truncateMessage + self._truncateMessage = explodingTruncation + self.addCleanup(lambda: setattr(self, '_truncateMessage', old_truncate)) + + s1, s2 = s + 'a', s + 'b' + with self.assertRaises(self.failureException) as cm: + self.assertEqual(s1, s2) + self.assertNotIn('^', str(cm.exception)) + self.assertEqual(str(cm.exception), '%r != %r' % (s1, s2)) + self.assertEqual(s + 'a', s + 'a') + def testAssertItemsEqual(self): a = object() self.assertItemsEqual([1, 2, 3], [3, 2, 1]) |