diff options
| -rw-r--r-- | Doc/library/sys.rst | 23 | ||||
| -rw-r--r-- | Lib/getpass.py | 2 | ||||
| -rw-r--r-- | Lib/test/test_bytes.py | 16 | ||||
| -rw-r--r-- | Lib/test/test_unicode.py | 11 | ||||
| -rw-r--r-- | Lib/test/test_unittest.py | 35 | ||||
| -rw-r--r-- | Lib/unittest.py | 7 | ||||
| -rw-r--r-- | Misc/ACKS | 2 | ||||
| -rw-r--r-- | Misc/NEWS | 8 | ||||
| -rw-r--r-- | Objects/bytearrayobject.c | 16 | ||||
| -rw-r--r-- | Objects/bytesobject.c | 12 | ||||
| -rw-r--r-- | Objects/unicodeobject.c | 21 | ||||
| -rwxr-xr-x | Tools/pybench/pybench.py | 2 |
12 files changed, 140 insertions, 15 deletions
diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index acf5763..c61fedb 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -450,6 +450,29 @@ always available. struct sequence :data:`sys.version_info` may be used for a more human-friendly encoding of the same information. + The ``hexversion`` is a 32-bit number with the following layout + + +-------------------------+------------------------------------------------+ + | bits (big endian order) | meaning | + +=========================+================================================+ + | :const:`1-8` | ``PY_MAJOR_VERSION`` (the ``2`` in | + | | ``2.1.0a3``) | + +-------------------------+------------------------------------------------+ + | :const:`9-16` | ``PY_MINOR_VERSION`` (the ``1`` in | + | | ``2.1.0a3``) | + +-------------------------+------------------------------------------------+ + | :const:`17-24` | ``PY_MICRO_VERSION`` (the ``0`` in | + | | ``2.1.0a3``) | + +-------------------------+------------------------------------------------+ + | :const:`25-28` | ``PY_RELEASE_LEVEL`` (``0xA`` for alpha, | + | | ``0xB`` for beta, ``0xC`` for gamma and | + | | ``0xF`` for final) | + +-------------------------+------------------------------------------------+ + | :const:`29-32` | ``PY_RELEASE_SERIAL`` (the ``3`` in | + | | ``2.1.0a3``) | + +-------------------------+------------------------------------------------+ + + thus ``2.1.0a3`` is hexversion ``0x020100a3`` .. data:: int_info diff --git a/Lib/getpass.py b/Lib/getpass.py index ce04566..dc02bd1 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/test/test_bytes.py b/Lib/test/test_bytes.py index a607bef..a1e08cc 100644 --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -290,6 +290,14 @@ class BaseBytesTest(unittest.TestCase): self.assertTrue(b.startswith(b"h")) self.assertFalse(b.startswith(b"hellow")) self.assertFalse(b.startswith(b"ha")) + try: + b.startswith([b'h']) + except TypeError as err: + exc = str(err) + else: + self.fail('startswith unexpectedly succeeded') + self.assertIn('bytes', exc) + self.assertIn('tuple', exc) def test_endswith(self): b = self.type2test(b'hello') @@ -299,6 +307,14 @@ class BaseBytesTest(unittest.TestCase): self.assertTrue(b.endswith(b"o")) self.assertFalse(b.endswith(b"whello")) self.assertFalse(b.endswith(b"no")) + try: + b.endswith([b'o']) + except TypeError as err: + exc = str(err) + else: + self.fail('endswith unexpectedly succeeded') + self.assertIn('bytes', exc) + self.assertIn('tuple', exc) def test_find(self): b = self.type2test(b'mississippi') diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py index 4793707..772ea35 100644 --- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -789,6 +789,17 @@ class UnicodeTest( self.assertEqual('%f' % INF, 'inf') self.assertEqual('%F' % INF, 'INF') + def test_startswith_endswith_errors(self): + for meth in ('foo'.startswith, 'foo'.endswith): + try: + meth(['f']) + except TypeError as err: + exc = str(err) + else: + self.fail('starts/endswith unexpectedly succeeded') + self.assertIn('str', exc) + self.assertIn('tuple', exc) + @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_unittest.py b/Lib/test/test_unittest.py index 21e0806..c4cad83 100644 --- a/Lib/test/test_unittest.py +++ b/Lib/test/test_unittest.py @@ -2719,6 +2719,41 @@ test case # no fair testing ourself with ourself, use assertEqual.. self.assertEqual(sample_text_error, str(e)) + 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 = 'x' * (2**7) + try: + self.assertMultiLineEqual(s + 'a', s + 'b') + except self.failureException as exc: + err_msg = str(exc) + else: + self.fail('assertEqual unexpectedly succeeded') + self.assertIn('^', err_msg) + self.assertMultiLineEqual(s + 'a', s + 'a') + + # over the threshold: diff not used and marker (^) not in error message + s = 'x' * (2**9) + s1, s2 = s + 'a', s + 'b' + try: + self.assertMultiLineEqual(s1, s2) + except self.failureException as exc: + err_msg = str(exc) + else: + self.fail('assertEqual unexpectedly succeeded') + self.assertNotIn('^', err_msg) + self.assertEqual(err_msg, '%r != %r' % (s1, s2)) + self.assertMultiLineEqual(s + 'a', s + 'a') + def testAssertIsNone(self): self.assertIsNone(None) self.assertRaises(self.failureException, self.assertIsNone, False) diff --git a/Lib/unittest.py b/Lib/unittest.py index 03a11b7..cabd857 100644 --- a/Lib/unittest.py +++ b/Lib/unittest.py @@ -346,6 +346,9 @@ class TestCase(object): longMessage = False + # If a string is longer than _diffThreshold, use normal comparison instead + # of difflib. See #11763. + _diffThreshold = 2**16 def __init__(self, methodName='runTest'): """Create an instance of the class that will use the named test @@ -955,6 +958,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) standardMsg = '\n' + ''.join(difflib.ndiff(first.splitlines(True), second.splitlines(True))) self.fail(self._formatMessage(msg, standardMsg)) @@ -411,6 +411,7 @@ Irmen de Jong Lucas de Jonge John Jorgensen Jens B. Jorgensen +Sijin Joseph Andreas Jung Tattoo Mabonzo K. Bob Kahn @@ -794,6 +795,7 @@ Christian Tanzer Steven Taschuk Monty Taylor Amy Taylor +Mikhail Terekhov Tobias Thelen James Thomas Robin Thomas @@ -10,6 +10,9 @@ What's New in Python 3.1.4? Core and Builtins ----------------- +- Issue #6780: fix starts/endswith error message to mention that tuples are + accepted too. + - Issue #5057: fix a bug in the peepholer that led to non-portable pyc files between narrow and wide builds while optimizing BINARY_SUBSCR on non-BMP chars (e.g. "\U00012345"[0]). @@ -58,6 +61,11 @@ Core and Builtins Library ------- +- Issue #11763: don't use difflib in TestCase.assertMultiLineEqual if the + strings are too long. + +- Issue #11236: getpass.getpass responds to ctrl-c or ctrl-z on terminal. + - Issue #11768: The signal handler of the signal module only calls Py_AddPendingCall() for the first signal to fix a deadlock on reentrant or parallel calls. PyErr_SetInterrupt() writes also into the wake up file. diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c index 6fc229d..27affb5 100644 --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -1281,7 +1281,7 @@ PyDoc_STRVAR(startswith__doc__, Return True if B starts with the specified prefix, False otherwise.\n\ With optional start, test B beginning at that position.\n\ With optional end, stop comparing B at that position.\n\ -prefix can also be a tuple of strings to try."); +prefix can also be a tuple of bytes to try."); static PyObject * bytearray_startswith(PyByteArrayObject *self, PyObject *args) @@ -1308,8 +1308,12 @@ bytearray_startswith(PyByteArrayObject *self, PyObject *args) Py_RETURN_FALSE; } result = _bytearray_tailmatch(self, subobj, start, end, -1); - if (result == -1) + if (result == -1) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_Format(PyExc_TypeError, "startswith first arg must be bytes " + "or a tuple of bytes, not %s", Py_TYPE(subobj)->tp_name); return NULL; + } else return PyBool_FromLong(result); } @@ -1320,7 +1324,7 @@ PyDoc_STRVAR(endswith__doc__, Return True if B ends with the specified suffix, False otherwise.\n\ With optional start, test B beginning at that position.\n\ With optional end, stop comparing B at that position.\n\ -suffix can also be a tuple of strings to try."); +suffix can also be a tuple of bytes to try."); static PyObject * bytearray_endswith(PyByteArrayObject *self, PyObject *args) @@ -1347,8 +1351,12 @@ bytearray_endswith(PyByteArrayObject *self, PyObject *args) Py_RETURN_FALSE; } result = _bytearray_tailmatch(self, subobj, start, end, +1); - if (result == -1) + if (result == -1) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_Format(PyExc_TypeError, "endswith first arg must be bytes or " + "a tuple of bytes, not %s", Py_TYPE(subobj)->tp_name); return NULL; + } else return PyBool_FromLong(result); } diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 616f390..f2ee131 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -2654,8 +2654,12 @@ bytes_startswith(PyBytesObject *self, PyObject *args) Py_RETURN_FALSE; } result = _bytes_tailmatch(self, subobj, start, end, -1); - if (result == -1) + if (result == -1) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_Format(PyExc_TypeError, "startswith first arg must be bytes " + "or a tuple of bytes, not %s", Py_TYPE(subobj)->tp_name); return NULL; + } else return PyBool_FromLong(result); } @@ -2694,8 +2698,12 @@ bytes_endswith(PyBytesObject *self, PyObject *args) Py_RETURN_FALSE; } result = _bytes_tailmatch(self, subobj, start, end, +1); - if (result == -1) + if (result == -1) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_Format(PyExc_TypeError, "endswith first arg must be bytes or " + "a tuple of bytes, not %s", Py_TYPE(subobj)->tp_name); return NULL; + } else return PyBool_FromLong(result); } diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 877640d..2cdbc0e 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -1554,7 +1554,7 @@ PyUnicode_FSConverter(PyObject* arg, void* addr) arg = PyUnicode_FromObject(arg); if (!arg) return 0; - output = PyUnicode_AsEncodedObject(arg, + output = PyUnicode_AsEncodedObject(arg, Py_FileSystemDefaultEncoding, "surrogateescape"); Py_DECREF(arg); @@ -1569,7 +1569,7 @@ PyUnicode_FSConverter(PyObject* arg, void* addr) if (PyBytes_Check(output)) { size = PyBytes_GET_SIZE(output); data = PyBytes_AS_STRING(output); - } + } else { size = PyByteArray_GET_SIZE(output); data = PyByteArray_AS_STRING(output); @@ -2148,7 +2148,7 @@ char utf8_code_length[256] = { illegal prefix. See RFC 3629 for details */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00-0F */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -2631,7 +2631,7 @@ PyUnicode_DecodeUTF32Stateful(const char *s, #endif PyObject *errorHandler = NULL; PyObject *exc = NULL; - + q = (unsigned char *)s; e = q + size; @@ -8743,8 +8743,12 @@ unicode_startswith(PyUnicodeObject *self, Py_RETURN_FALSE; } substring = (PyUnicodeObject *)PyUnicode_FromObject(subobj); - if (substring == NULL) + if (substring == NULL) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_Format(PyExc_TypeError, "startswith first arg must be str or " + "a tuple of str, not %s", Py_TYPE(subobj)->tp_name); return NULL; + } result = tailmatch(self, substring, start, end, -1); Py_DECREF(substring); return PyBool_FromLong(result); @@ -8787,9 +8791,12 @@ unicode_endswith(PyUnicodeObject *self, Py_RETURN_FALSE; } substring = (PyUnicodeObject *)PyUnicode_FromObject(subobj); - if (substring == NULL) + if (substring == NULL) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_Format(PyExc_TypeError, "endswith first arg must be str or " + "a tuple of str, not %s", Py_TYPE(subobj)->tp_name); return NULL; - + } result = tailmatch(self, substring, start, end, +1); Py_DECREF(substring); return PyBool_FromLong(result); diff --git a/Tools/pybench/pybench.py b/Tools/pybench/pybench.py index bee0e56..9f1e2e4 100755 --- a/Tools/pybench/pybench.py +++ b/Tools/pybench/pybench.py @@ -276,7 +276,7 @@ class Test: for i in calibration_loops: pass t = timer() - t - prep_times.append(t) + prep_times.append(t / CALIBRATION_LOOPS) min_prep_time = min(prep_times) if _debug: print() |
