From fc095202afe7f81eeba2794e9ac12cd6252d55de Mon Sep 17 00:00:00 2001 From: R David Murray Date: Mon, 16 Jul 2012 22:31:32 -0400 Subject: [PATCH 01/14] #15375: remove duplicated word 'child' --- Doc/library/subprocess.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst index 5e4bcd91769..3aae1377622 100644 --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -289,7 +289,7 @@ functions. Popen(['/bin/sh', '-c', args[0], args[1], ...]) - On Windows: the :class:`Popen` class uses CreateProcess() to execute the child + On Windows: the :class:`Popen` class uses CreateProcess() to execute the child program, which operates on strings. If *args* is a sequence, it will be converted to a string in a manner described in :ref:`converting-argument-sequence`. From 6642d1f97d7b89509159214253900eb3d970e223 Mon Sep 17 00:00:00 2001 From: Meador Inge Date: Wed, 18 Jul 2012 14:09:04 -0500 Subject: [PATCH 02/14] Issue #15368: make bytecode generation deterministic. --- Misc/NEWS | 5 ++++- Python/compile.c | 24 ++++++++++++++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS index 4b05aa36dcc..6a2abb5d56c 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -1,4 +1,4 @@ -Python News +,Python News +++++++++++ What's New in Python 2.7.4 @@ -9,6 +9,9 @@ What's New in Python 2.7.4 Core and Builtins ----------------- +- Issue #15368: An issue that caused bytecode generation to be + non-deterministic when using randomized hashing (-R) has been fixed. + - Issue #15033: Fix the exit status bug when modules invoked using -m swith, return the proper failure return value (1). Patch contributed by Jeff Knupp. diff --git a/Python/compile.c b/Python/compile.c index 119c60f9b23..d50344cf614 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -359,14 +359,31 @@ each key. static PyObject * dictbytype(PyObject *src, int scope_type, int flag, int offset) { - Py_ssize_t pos = 0, i = offset, scope; + Py_ssize_t pos = 0, i = offset, scope, num_keys, key_i; PyObject *k, *v, *dest = PyDict_New(); + PyObject *sorted_keys; assert(offset >= 0); if (dest == NULL) return NULL; - while (PyDict_Next(src, &pos, &k, &v)) { + /* Sort the keys so that we have a deterministic order on the indexes + saved in the returned dictionary. These indexes are used as indexes + into the free and cell var storage. Therefore if they aren't + deterministic, then the generated bytecode is not deterministic. + */ + sorted_keys = PyDict_Keys(src); + if (sorted_keys == NULL) + return NULL; + if (PyList_Sort(sorted_keys) != 0) { + Py_DECREF(sorted_keys); + return NULL; + } + num_keys = PyList_GET_SIZE(src); + + for (key_i = 0; key_i < num_keys; key_i++) { + k = PyList_GET_ITEM(sorted_keys, key_i); + v = PyDict_GetItem(src, k); /* XXX this should probably be a macro in symtable.h */ assert(PyInt_Check(v)); scope = (PyInt_AS_LONG(v) >> SCOPE_OFF) & SCOPE_MASK; @@ -374,12 +391,14 @@ dictbytype(PyObject *src, int scope_type, int flag, int offset) if (scope == scope_type || PyInt_AS_LONG(v) & flag) { PyObject *tuple, *item = PyInt_FromLong(i); if (item == NULL) { + Py_DECREF(sorted_keys); Py_DECREF(dest); return NULL; } i++; tuple = PyTuple_Pack(2, k, k->ob_type); if (!tuple || PyDict_SetItem(dest, tuple, item) < 0) { + Py_DECREF(sorted_keys); Py_DECREF(item); Py_DECREF(dest); Py_XDECREF(tuple); @@ -389,6 +408,7 @@ dictbytype(PyObject *src, int scope_type, int flag, int offset) Py_DECREF(tuple); } } + Py_DECREF(sorted_keys); return dest; } From b8a569065eb05b14a7aef1d837159e7135defbfb Mon Sep 17 00:00:00 2001 From: Meador Inge Date: Wed, 18 Jul 2012 16:32:37 -0500 Subject: [PATCH 03/14] Issue #15368: fixing variable typo. --- Python/compile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/compile.c b/Python/compile.c index d50344cf614..3cf8c6ef9c4 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -379,7 +379,7 @@ dictbytype(PyObject *src, int scope_type, int flag, int offset) Py_DECREF(sorted_keys); return NULL; } - num_keys = PyList_GET_SIZE(src); + num_keys = PyList_GET_SIZE(sorted_keys); for (key_i = 0; key_i < num_keys; key_i++) { k = PyList_GET_ITEM(sorted_keys, key_i); From 0e3755e58a0495f835fc2eb89c7a72e87366346c Mon Sep 17 00:00:00 2001 From: Meador Inge Date: Wed, 18 Jul 2012 17:48:34 -0500 Subject: [PATCH 04/14] remove unused variable --- Python/compile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/compile.c b/Python/compile.c index 3cf8c6ef9c4..531bed43c48 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -359,7 +359,7 @@ each key. static PyObject * dictbytype(PyObject *src, int scope_type, int flag, int offset) { - Py_ssize_t pos = 0, i = offset, scope, num_keys, key_i; + Py_ssize_t i = offset, scope, num_keys, key_i; PyObject *k, *v, *dest = PyDict_New(); PyObject *sorted_keys; From 59488d233bb663af24492759fd0316ab499200d0 Mon Sep 17 00:00:00 2001 From: R David Murray Date: Wed, 18 Jul 2012 19:44:08 -0400 Subject: [PATCH 05/14] Closes #9254: backport __import__ docstring/doc mentions of importlib. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Patch by Éric Araujo. --- Doc/library/functions.rst | 11 ++--------- Python/bltinmodule.c | 8 ++++++-- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index a324e51317a..dc8ee9a454d 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -1558,7 +1558,7 @@ available. They are listed here in alphabetical order. .. note:: This is an advanced function that is not needed in everyday Python - programming. + programming, unlike :func:`importlib.import_module`. This function is invoked by the :keyword:`import` statement. It can be replaced (by importing the :mod:`__builtin__` module and assigning to @@ -1609,15 +1609,8 @@ available. They are listed here in alphabetical order. names. If you simply want to import a module (potentially within a package) by name, - you can call :func:`__import__` and then look it up in :data:`sys.modules`:: + use :func:`importlib.import_module`. - >>> import sys - >>> name = 'foo.bar.baz' - >>> __import__(name) - - >>> baz = sys.modules[name] - >>> baz - .. versionchanged:: 2.5 The level parameter was added. diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 373f8706245..3def0800aaa 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -53,8 +53,12 @@ builtin___import__(PyObject *self, PyObject *args, PyObject *kwds) PyDoc_STRVAR(import_doc, "__import__(name, globals={}, locals={}, fromlist=[], level=-1) -> module\n\ \n\ -Import a module. The globals are only used to determine the context;\n\ -they are not modified. The locals are currently unused. The fromlist\n\ +Import a module. Because this function is meant for use by the Python\n\ +interpreter and not for general use it is better to use\n\ +importlib.import_module() to programmatically import a module.\n\ +\n\ +The globals argument is only used to determine the context;\n\ +they are not modified. The locals argument is unused. The fromlist\n\ should be a list of names to emulate ``from name import ...'', or an\n\ empty list to emulate ``import name''.\n\ When importing a module from a package, note that __import__('A.B', ...)\n\ From 25be3f68e02b06c43dfa9eb831fddd69fa33fc64 Mon Sep 17 00:00:00 2001 From: Meador Inge Date: Wed, 18 Jul 2012 23:51:05 -0500 Subject: [PATCH 06/14] Issue #6493: Fix handling of c_uint32 bitfields with width of 32 on Windows. --- Lib/ctypes/test/test_bitfields.py | 20 ++++++++++++ Misc/NEWS | 3 ++ Modules/_ctypes/cfield.c | 51 ++++++++++++++----------------- 3 files changed, 46 insertions(+), 28 deletions(-) diff --git a/Lib/ctypes/test/test_bitfields.py b/Lib/ctypes/test/test_bitfields.py index e9c46c2c203..090fb4dfc5e 100644 --- a/Lib/ctypes/test/test_bitfields.py +++ b/Lib/ctypes/test/test_bitfields.py @@ -240,5 +240,25 @@ class BitFieldTest(unittest.TestCase): _anonymous_ = ["_"] _fields_ = [("_", X)] + @unittest.skipUnless(hasattr(ctypes, "c_uint32"), "c_int32 is required") + def test_uint32(self): + class X(Structure): + _fields_ = [("a", c_uint32, 32)] + x = X() + x.a = 10 + self.assertEquals(x.a, 10) + x.a = 0xFDCBA987 + self.assertEquals(x.a, 0xFDCBA987) + + @unittest.skipUnless(hasattr(ctypes, "c_uint64"), "c_int64 is required") + def test_uint64(self): + class X(Structure): + _fields_ = [("a", c_uint64, 64)] + x = X() + x.a = 10 + self.assertEquals(x.a, 10) + x.a = 0xFEDCBA9876543211 + self.assertEquals(x.a, 0xFEDCBA9876543211) + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS index 6a2abb5d56c..c5fc1bd33e7 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -87,6 +87,9 @@ Core and Builtins Library ------- +- Issue #6493: An issue in ctypes on Windows that caused structure bitfields + of type ctypes.c_uint32 and width 32 to incorrectly be set has been fixed. + - Issue #14635: telnetlib will use poll() rather than select() when possible to avoid failing due to the select() file descriptor limit. diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c index 1aab202d685..5e0fc759ff1 100644 --- a/Modules/_ctypes/cfield.c +++ b/Modules/_ctypes/cfield.c @@ -431,12 +431,8 @@ get_ulonglong(PyObject *v, unsigned PY_LONG_LONG *p) #define LOW_BIT(x) ((x) & 0xFFFF) #define NUM_BITS(x) ((x) >> 16) -/* This seems nore a compiler issue than a Windows/non-Windows one */ -#ifdef MS_WIN32 -# define BIT_MASK(size) ((1 << NUM_BITS(size))-1) -#else -# define BIT_MASK(size) ((1LL << NUM_BITS(size))-1) -#endif +/* Doesn't work if NUM_BITS(size) == 0, but it never happens in SET() call. */ +#define BIT_MASK(type, size) (((((type)1 << (NUM_BITS(size) - 1)) - 1) << 1) + 1) /* This macro CHANGES the first parameter IN PLACE. For proper sign handling, we must first shift left, then right. @@ -448,10 +444,10 @@ get_ulonglong(PyObject *v, unsigned PY_LONG_LONG *p) } /* This macro RETURNS the first parameter with the bit field CHANGED. */ -#define SET(x, v, size) \ +#define SET(type, x, v, size) \ (NUM_BITS(size) ? \ - ( ( x & ~(BIT_MASK(size) << LOW_BIT(size)) ) | ( (v & BIT_MASK(size)) << LOW_BIT(size) ) ) \ - : v) + ( ( (type)x & ~(BIT_MASK(type, size) << LOW_BIT(size)) ) | ( ((type)v & BIT_MASK(type, size)) << LOW_BIT(size) ) ) \ + : (type)v) /* byte swapping macros */ #define SWAP_2(v) \ @@ -523,7 +519,7 @@ b_set(void *ptr, PyObject *value, Py_ssize_t size) long val; if (get_long(value, &val) < 0) return NULL; - *(signed char *)ptr = (signed char)SET(*(signed char *)ptr, (signed char)val, size); + *(signed char *)ptr = SET(signed char, *(signed char *)ptr, val, size); _RET(value); } @@ -542,8 +538,7 @@ B_set(void *ptr, PyObject *value, Py_ssize_t size) unsigned long val; if (get_ulong(value, &val) < 0) return NULL; - *(unsigned char *)ptr = (unsigned char)SET(*(unsigned char*)ptr, - (unsigned short)val, size); + *(unsigned char *)ptr = SET(unsigned char, *(unsigned char*)ptr, val, size); _RET(value); } @@ -564,7 +559,7 @@ h_set(void *ptr, PyObject *value, Py_ssize_t size) if (get_long(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, (short)val, size); + x = SET(short, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -579,7 +574,7 @@ h_set_sw(void *ptr, PyObject *value, Py_ssize_t size) return NULL; memcpy(&field, ptr, sizeof(field)); field = SWAP_2(field); - field = SET(field, (short)val, size); + field = SET(short, field, val, size); field = SWAP_2(field); memcpy(ptr, &field, sizeof(field)); _RET(value); @@ -612,7 +607,7 @@ H_set(void *ptr, PyObject *value, Py_ssize_t size) if (get_ulong(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, (unsigned short)val, size); + x = SET(unsigned short, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -626,7 +621,7 @@ H_set_sw(void *ptr, PyObject *value, Py_ssize_t size) return NULL; memcpy(&field, ptr, sizeof(field)); field = SWAP_2(field); - field = SET(field, (unsigned short)val, size); + field = SET(unsigned short, field, val, size); field = SWAP_2(field); memcpy(ptr, &field, sizeof(field)); _RET(value); @@ -660,7 +655,7 @@ i_set(void *ptr, PyObject *value, Py_ssize_t size) if (get_long(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, (int)val, size); + x = SET(int, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -674,7 +669,7 @@ i_set_sw(void *ptr, PyObject *value, Py_ssize_t size) return NULL; memcpy(&field, ptr, sizeof(field)); field = SWAP_INT(field); - field = SET(field, (int)val, size); + field = SET(int, field, val, size); field = SWAP_INT(field); memcpy(ptr, &field, sizeof(field)); _RET(value); @@ -761,7 +756,7 @@ I_set(void *ptr, PyObject *value, Py_ssize_t size) if (get_ulong(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, (unsigned int)val, size); + x = SET(unsigned int, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -774,7 +769,7 @@ I_set_sw(void *ptr, PyObject *value, Py_ssize_t size) if (get_ulong(value, &val) < 0) return NULL; memcpy(&field, ptr, sizeof(field)); - field = (unsigned int)SET(field, (unsigned int)val, size); + field = SET(unsigned int, field, (unsigned int)val, size); field = SWAP_INT(field); memcpy(ptr, &field, sizeof(field)); _RET(value); @@ -808,7 +803,7 @@ l_set(void *ptr, PyObject *value, Py_ssize_t size) if (get_long(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, val, size); + x = SET(long, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -822,7 +817,7 @@ l_set_sw(void *ptr, PyObject *value, Py_ssize_t size) return NULL; memcpy(&field, ptr, sizeof(field)); field = SWAP_LONG(field); - field = (long)SET(field, val, size); + field = SET(long, field, val, size); field = SWAP_LONG(field); memcpy(ptr, &field, sizeof(field)); _RET(value); @@ -856,7 +851,7 @@ L_set(void *ptr, PyObject *value, Py_ssize_t size) if (get_ulong(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, val, size); + x = SET(unsigned long, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -870,7 +865,7 @@ L_set_sw(void *ptr, PyObject *value, Py_ssize_t size) return NULL; memcpy(&field, ptr, sizeof(field)); field = SWAP_LONG(field); - field = (unsigned long)SET(field, val, size); + field = SET(unsigned long, field, val, size); field = SWAP_LONG(field); memcpy(ptr, &field, sizeof(field)); _RET(value); @@ -905,7 +900,7 @@ q_set(void *ptr, PyObject *value, Py_ssize_t size) if (get_longlong(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, val, size); + x = SET(PY_LONG_LONG, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -919,7 +914,7 @@ q_set_sw(void *ptr, PyObject *value, Py_ssize_t size) return NULL; memcpy(&field, ptr, sizeof(field)); field = SWAP_8(field); - field = (PY_LONG_LONG)SET(field, val, size); + field = SET(PY_LONG_LONG, field, val, size); field = SWAP_8(field); memcpy(ptr, &field, sizeof(field)); _RET(value); @@ -952,7 +947,7 @@ Q_set(void *ptr, PyObject *value, Py_ssize_t size) if (get_ulonglong(value, &val) < 0) return NULL; memcpy(&x, ptr, sizeof(x)); - x = SET(x, val, size); + x = SET(PY_LONG_LONG, x, val, size); memcpy(ptr, &x, sizeof(x)); _RET(value); } @@ -966,7 +961,7 @@ Q_set_sw(void *ptr, PyObject *value, Py_ssize_t size) return NULL; memcpy(&field, ptr, sizeof(field)); field = SWAP_8(field); - field = (unsigned PY_LONG_LONG)SET(field, val, size); + field = SET(unsigned PY_LONG_LONG, field, val, size); field = SWAP_8(field); memcpy(ptr, &field, sizeof(field)); _RET(value); From bee739baa771b7c54169e799fbfe1a55c5fce3d6 Mon Sep 17 00:00:00 2001 From: Vinay Sajip Date: Fri, 20 Jul 2012 09:48:46 +0100 Subject: [PATCH 07/14] Issue #15399: Added versionchanged for processName. --- Doc/library/logging.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Doc/library/logging.rst b/Doc/library/logging.rst index b77fd3697b9..7ed1f1ab13f 100644 --- a/Doc/library/logging.rst +++ b/Doc/library/logging.rst @@ -629,6 +629,9 @@ format string. .. versionchanged:: 2.5 *funcName* was added. +.. versionchanged:: 2.6 + *processName* was added. + .. _logger-adapter: LoggerAdapter Objects From 715a63b78349952ccc0fb3dd3139e2d822006d35 Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Sat, 21 Jul 2012 00:52:06 +0200 Subject: [PATCH 08/14] Issue #14579: Fix error handling bug in the utf-16 decoder. Patch by Serhiy Storchaka. --- Lib/test/test_codecs.py | 28 ++++++++++++++++++++++++++-- Misc/NEWS | 3 +++ Objects/unicodeobject.c | 2 +- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py index d434f837544..57669f82a83 100644 --- a/Lib/test/test_codecs.py +++ b/Lib/test/test_codecs.py @@ -495,7 +495,19 @@ class UTF16LETest(ReadTest): ) def test_errors(self): - self.assertRaises(UnicodeDecodeError, codecs.utf_16_le_decode, "\xff", "strict", True) + tests = [ + (b'\xff', u'\ufffd'), + (b'A\x00Z', u'A\ufffd'), + (b'A\x00B\x00C\x00D\x00Z', u'ABCD\ufffd'), + (b'\x00\xd8', u'\ufffd'), + (b'\x00\xd8A', u'\ufffd'), + (b'\x00\xd8A\x00', u'\ufffdA'), + (b'\x00\xdcA\x00', u'\ufffdA'), + ] + for raw, expected in tests: + self.assertRaises(UnicodeDecodeError, codecs.utf_16_le_decode, + raw, 'strict', True) + self.assertEqual(raw.decode('utf-16le', 'replace'), expected) class UTF16BETest(ReadTest): encoding = "utf-16-be" @@ -516,7 +528,19 @@ class UTF16BETest(ReadTest): ) def test_errors(self): - self.assertRaises(UnicodeDecodeError, codecs.utf_16_be_decode, "\xff", "strict", True) + tests = [ + (b'\xff', u'\ufffd'), + (b'\x00A\xff', u'A\ufffd'), + (b'\x00A\x00B\x00C\x00DZ', u'ABCD\ufffd'), + (b'\xd8\x00', u'\ufffd'), + (b'\xd8\x00\xdc', u'\ufffd'), + (b'\xd8\x00\x00A', u'\ufffdA'), + (b'\xdc\x00\x00A', u'\ufffdA'), + ] + for raw, expected in tests: + self.assertRaises(UnicodeDecodeError, codecs.utf_16_be_decode, + raw, 'strict', True) + self.assertEqual(raw.decode('utf-16be', 'replace'), expected) class UTF8Test(ReadTest): encoding = "utf-8" diff --git a/Misc/NEWS b/Misc/NEWS index c5fc1bd33e7..3766a33bc4c 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -9,6 +9,9 @@ What's New in Python 2.7.4 Core and Builtins ----------------- +- Issue #14579: Fix error handling bug in the utf-16 decoder. Patch by + Serhiy Storchaka. + - Issue #15368: An issue that caused bytecode generation to be non-deterministic when using randomized hashing (-R) has been fixed. diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 7af7b50a946..59b138a21fa 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -2564,7 +2564,7 @@ PyUnicode_DecodeUTF16Stateful(const char *s, } /* UTF-16 code pair: */ - if (q >= e) { + if (e - q < 2) { errmsg = "unexpected end of data"; startinpos = (((const char *)q)-2)-starts; endinpos = ((const char *)e)-starts; From dee8af225b04c28b2ed7e9dfcef6d93b7ae1c827 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Fri, 20 Jul 2012 17:47:59 -0700 Subject: [PATCH 09/14] Fix whitespace --- Python/peephole.c | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/Python/peephole.c b/Python/peephole.c index 7521b9ce218..ae84efa996e 100644 --- a/Python/peephole.c +++ b/Python/peephole.c @@ -347,7 +347,7 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names, codestr = (unsigned char *)memcpy(codestr, PyString_AS_STRING(code), codelen); - /* Verify that RETURN_VALUE terminates the codestring. This allows + /* Verify that RETURN_VALUE terminates the codestring. This allows the various transformation patterns to look ahead several instructions without additional checks to make sure they are not looking beyond the end of the code string. @@ -445,8 +445,8 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names, case BUILD_LIST: j = GETARG(codestr, i); h = i - 3 * j; - if (h >= 0 && - j <= lastlc && + if (h >= 0 && + j <= lastlc && ((opcode == BUILD_TUPLE && ISBASICBLOCK(blocks, h, 3*(j+1))) || (opcode == BUILD_LIST && @@ -490,8 +490,8 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names, case BINARY_AND: case BINARY_XOR: case BINARY_OR: - if (lastlc >= 2 && - ISBASICBLOCK(blocks, i-6, 7) && + if (lastlc >= 2 && + ISBASICBLOCK(blocks, i-6, 7) && fold_binops_on_constants(&codestr[i-6], consts)) { i -= 2; assert(codestr[i] == LOAD_CONST); @@ -500,13 +500,13 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names, break; /* Fold unary ops on constants. - LOAD_CONST c1 UNARY_OP --> LOAD_CONST unary_op(c) */ + LOAD_CONST c1 UNARY_OP --> LOAD_CONST unary_op(c) */ case UNARY_NEGATIVE: case UNARY_CONVERT: case UNARY_INVERT: - if (lastlc >= 1 && - ISBASICBLOCK(blocks, i-3, 4) && - fold_unaryops_on_constants(&codestr[i-3], consts)) { + if (lastlc >= 1 && + ISBASICBLOCK(blocks, i-3, 4) && + fold_unaryops_on_constants(&codestr[i-3], consts)) { i -= 2; assert(codestr[i] == LOAD_CONST); cumlc = 1; @@ -532,8 +532,7 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names, tgt = GETJUMPTGT(codestr, i); j = codestr[tgt]; if (CONDITIONAL_JUMP(j)) { - /* NOTE: all possible jumps here are - absolute! */ + /* NOTE: all possible jumps here are absolute! */ if (JUMPS_ON_TRUE(j) == JUMPS_ON_TRUE(opcode)) { /* The second jump will be taken iff the first is. */ @@ -544,13 +543,10 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names, SETARG(codestr, i, tgttgt); goto reoptimize_current; } else { - /* The second jump is not taken - if the first is (so jump past - it), and all conditional - jumps pop their argument when - they're not taken (so change - the first jump to pop its - argument when it's taken). */ + /* The second jump is not taken if the first is (so + jump past it), and all conditional jumps pop their + argument when they're not taken (so change the + first jump to pop its argument when it's taken). */ if (JUMPS_ON_TRUE(opcode)) codestr[i] = POP_JUMP_IF_TRUE; else @@ -586,8 +582,8 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names, if (opcode == JUMP_FORWARD) /* JMP_ABS can go backwards */ opcode = JUMP_ABSOLUTE; if (!ABSOLUTE_JUMP(opcode)) - tgttgt -= i + 3; /* Calc relative jump addr */ - if (tgttgt < 0) /* No backward relative jumps */ + tgttgt -= i + 3; /* Calc relative jump addr */ + if (tgttgt < 0) /* No backward relative jumps */ continue; codestr[i] = opcode; SETARG(codestr, i, tgttgt); From d33a9beb8d9de33b86d305ed4733b3e5acacd37e Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Sat, 21 Jul 2012 16:48:16 +0200 Subject: [PATCH 10/14] Fix typo introduced in 79d54fba49b3. --- Misc/NEWS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS b/Misc/NEWS index 3766a33bc4c..16ab20224c6 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -1,4 +1,4 @@ -,Python News +Python News +++++++++++ What's New in Python 2.7.4 From ac9b5c67d35ee100ff1d80f4d55c307aab4ca4e7 Mon Sep 17 00:00:00 2001 From: R David Murray Date: Sat, 21 Jul 2012 14:37:29 -0400 Subject: [PATCH 11/14] #15342: Add clarifying sentence to posixpath.join docstring. This sentence appears as a clarifying note in the HTML docs, and seems worth having in the docstring since it covers a very common use case that isn't otherwise obvious. Thanks to Yongzhi Pan for the suggestion. --- Lib/posixpath.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/posixpath.py b/Lib/posixpath.py index 690c70da374..5ddf25b1067 100644 --- a/Lib/posixpath.py +++ b/Lib/posixpath.py @@ -68,7 +68,8 @@ def isabs(s): def join(a, *p): """Join two or more pathname components, inserting '/' as needed. If any component is an absolute path, all previous path components - will be discarded.""" + will be discarded. An empty last part will result in a path that + ends with a separator.""" path = a for b in p: if b.startswith('/'): From 1a2c1fbfd2208407e1af365b161276b6f103c1ad Mon Sep 17 00:00:00 2001 From: R David Murray Date: Sat, 21 Jul 2012 17:06:28 -0400 Subject: [PATCH 12/14] #14391: clarify docstring discussion of Action's 'type' argument's value. --- Lib/argparse.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/argparse.py b/Lib/argparse.py index a9129de470a..d8676118388 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -740,10 +740,10 @@ class Action(_AttributeHolder): - default -- The value to be produced if the option is not specified. - - type -- The type which the command-line arguments should be converted - to, should be one of 'string', 'int', 'float', 'complex' or a - callable object that accepts a single string argument. If None, - 'string' is assumed. + - type -- A callable that accepts a single string argument, and + returns the converted value. The standard Python types str, int, + float, and complex are useful examples of such callables. If None, + str is used. - choices -- A container of values that should be allowed. If not None, after a command-line argument has been converted to the appropriate From 056c31f9cc10a8697a40c817eae42f7e38a1cf80 Mon Sep 17 00:00:00 2001 From: R David Murray Date: Sat, 21 Jul 2012 22:35:00 -0400 Subject: [PATCH 13/14] #12353: argparse now correctly handles null argument values. Patch by Torsten Landschoff. --- Lib/argparse.py | 2 +- Lib/test/test_argparse.py | 1 + Misc/NEWS | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Lib/argparse.py b/Lib/argparse.py index d8676118388..f365385a573 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -1967,7 +1967,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): for arg_string in arg_strings: # for regular arguments, just add them back into the list - if arg_string[0] not in self.fromfile_prefix_chars: + if not arg_string or arg_string[0] not in self.fromfile_prefix_chars: new_arg_strings.append(arg_string) # replace arguments referencing files with the file content diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 1a5f05e30b9..a7a4b005b00 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -1374,6 +1374,7 @@ class TestArgumentsFromFile(TempDirMixin, ParserTestCase): ('X @hello', NS(a=None, x='X', y=['hello world!'])), ('-a B @recursive Y Z', NS(a='A', x='hello world!', y=['Y', 'Z'])), ('X @recursive Z -a B', NS(a='B', x='X', y=['hello world!', 'Z'])), + (["-a", "", "X", "Y"], NS(a='', x='X', y=['Y'])), ] diff --git a/Misc/NEWS b/Misc/NEWS index 16ab20224c6..7a2eb5bb528 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -90,6 +90,8 @@ Core and Builtins Library ------- +- Issue #12353: argparse now correctly handles null argument values. + - Issue #6493: An issue in ctypes on Windows that caused structure bitfields of type ctypes.c_uint32 and width 32 to incorrectly be set has been fixed. From 68f555c03ad32671a76c5762313bbf33c0ae4842 Mon Sep 17 00:00:00 2001 From: R David Murray Date: Sat, 21 Jul 2012 22:54:34 -0400 Subject: [PATCH 14/14] #13922: argparse no longer incorrectly strips '--' after the first one. Patch by Jeff Knupp. --- Lib/argparse.py | 7 +++++-- Lib/test/test_argparse.py | 37 +++++++++++++++++++++++++------------ Misc/ACKS | 1 + Misc/NEWS | 3 +++ 4 files changed, 34 insertions(+), 14 deletions(-) diff --git a/Lib/argparse.py b/Lib/argparse.py index f365385a573..80df97b4f0b 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -2174,9 +2174,12 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): # Value conversion methods # ======================== def _get_values(self, action, arg_strings): - # for everything but PARSER args, strip out '--' + # for everything but PARSER, REMAINDER args, strip out first '--' if action.nargs not in [PARSER, REMAINDER]: - arg_strings = [s for s in arg_strings if s != '--'] + try: + arg_strings.remove('--') + except ValueError: + pass # optional argument produces a default when not present if not arg_strings and action.nargs == OPTIONAL: diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index a7a4b005b00..80dbc225be8 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -1764,6 +1764,14 @@ class TestAddSubparsers(TestCase): parser2.add_argument('-y', choices='123', help='y help') parser2.add_argument('z', type=complex, nargs='*', help='z help') + # add third sub-parser + parser3_kwargs = dict(description='3 description') + if subparser_help: + parser3_kwargs['help'] = '3 help' + parser3 = subparsers.add_parser('3', **parser3_kwargs) + parser3.add_argument('t', type=int, help='t help') + parser3.add_argument('u', nargs='...', help='u help') + # return the main parser return parser @@ -1793,6 +1801,10 @@ class TestAddSubparsers(TestCase): self.parser.parse_args('--foo 0.125 1 c'.split()), NS(foo=True, bar=0.125, w=None, x='c'), ) + self.assertEqual( + self.parser.parse_args('-1.5 3 11 -- a --foo 7 -- b'.split()), + NS(foo=False, bar=-1.5, t=11, u=['a', '--foo', '7', '--', 'b']), + ) def test_parse_known_args(self): self.assertEqual( @@ -1827,15 +1839,15 @@ class TestAddSubparsers(TestCase): def test_help(self): self.assertEqual(self.parser.format_usage(), - 'usage: PROG [-h] [--foo] bar {1,2} ...\n') + 'usage: PROG [-h] [--foo] bar {1,2,3} ...\n') self.assertEqual(self.parser.format_help(), textwrap.dedent('''\ - usage: PROG [-h] [--foo] bar {1,2} ... + usage: PROG [-h] [--foo] bar {1,2,3} ... main description positional arguments: bar bar help - {1,2} command help + {1,2,3} command help optional arguments: -h, --help show this help message and exit @@ -1846,15 +1858,15 @@ class TestAddSubparsers(TestCase): # Make sure - is still used for help if it is a non-first prefix char parser = self._get_parser(prefix_chars='+:-') self.assertEqual(parser.format_usage(), - 'usage: PROG [-h] [++foo] bar {1,2} ...\n') + 'usage: PROG [-h] [++foo] bar {1,2,3} ...\n') self.assertEqual(parser.format_help(), textwrap.dedent('''\ - usage: PROG [-h] [++foo] bar {1,2} ... + usage: PROG [-h] [++foo] bar {1,2,3} ... main description positional arguments: bar bar help - {1,2} command help + {1,2,3} command help optional arguments: -h, --help show this help message and exit @@ -1865,15 +1877,15 @@ class TestAddSubparsers(TestCase): def test_help_alternate_prefix_chars(self): parser = self._get_parser(prefix_chars='+:/') self.assertEqual(parser.format_usage(), - 'usage: PROG [+h] [++foo] bar {1,2} ...\n') + 'usage: PROG [+h] [++foo] bar {1,2,3} ...\n') self.assertEqual(parser.format_help(), textwrap.dedent('''\ - usage: PROG [+h] [++foo] bar {1,2} ... + usage: PROG [+h] [++foo] bar {1,2,3} ... main description positional arguments: bar bar help - {1,2} command help + {1,2,3} command help optional arguments: +h, ++help show this help message and exit @@ -1882,18 +1894,19 @@ class TestAddSubparsers(TestCase): def test_parser_command_help(self): self.assertEqual(self.command_help_parser.format_usage(), - 'usage: PROG [-h] [--foo] bar {1,2} ...\n') + 'usage: PROG [-h] [--foo] bar {1,2,3} ...\n') self.assertEqual(self.command_help_parser.format_help(), textwrap.dedent('''\ - usage: PROG [-h] [--foo] bar {1,2} ... + usage: PROG [-h] [--foo] bar {1,2,3} ... main description positional arguments: bar bar help - {1,2} command help + {1,2,3} command help 1 1 help 2 2 help + 3 3 help optional arguments: -h, --help show this help message and exit diff --git a/Misc/ACKS b/Misc/ACKS index 471e6a98a4c..75659f03249 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -462,6 +462,7 @@ Thomas Kluyver Kim Knapp Lenny Kneler Pat Knight +Jeff Knupp Greg Kochanski Damon Kohler Marko Kohtala diff --git a/Misc/NEWS b/Misc/NEWS index 7a2eb5bb528..b73bf0a5236 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -90,6 +90,9 @@ Core and Builtins Library ------- +- Issue #13922: argparse no longer incorrectly strips '--'s that appear + after the first one. + - Issue #12353: argparse now correctly handles null argument values. - Issue #6493: An issue in ctypes on Windows that caused structure bitfields