diff options
-rw-r--r-- | .hgtags | 2 | ||||
-rw-r--r-- | Doc/faq/design.rst | 10 | ||||
-rw-r--r-- | Doc/library/email.encoders.rst | 4 | ||||
-rw-r--r-- | Doc/library/json.rst | 8 | ||||
-rw-r--r-- | Doc/library/re.rst | 30 | ||||
-rw-r--r-- | Lib/test/test_queue.py | 8 | ||||
-rw-r--r-- | Mac/README | 10 | ||||
-rw-r--r-- | Misc/NEWS | 3 | ||||
-rw-r--r-- | Python/import.c | 126 |
9 files changed, 130 insertions, 71 deletions
@@ -137,6 +137,8 @@ fa4630916699046357a5ac16884f3fc47bd0eaa6 v2.6.5rc2 c1dc9e7986a2a8e1070ec7bee748520febef382e v2.6.6rc1 e189dc8fd66154ef46d9cd22584d56669b544ca3 v2.6.6rc2 9f8771e0905277f8b3c2799113a062fda4164995 v2.6.6 +caab08cd2b3eb5a6f78479b2513b65d36c754f41 v2.6.8rc1 +1d1b7b9fad48bd0dc60dc8a06cca4459ef273127 v2.6.8rc2 b4107eb00b4271fb73a9e1b736d4f23460950778 v2.7a1 adc85ebc7271cc22e24e816782bb2b8d7fa3a6b3 v2.7a2 4180557b7a9bb9dd5341a18af199f843f199e46e v2.7a3 diff --git a/Doc/faq/design.rst b/Doc/faq/design.rst index 962b4ef..25c72db 100644 --- a/Doc/faq/design.rst +++ b/Doc/faq/design.rst @@ -297,8 +297,9 @@ use the ``join()`` function from the string module, which allows you to write :: How fast are exceptions? ------------------------ -A try/except block is extremely efficient. Actually catching an exception is -expensive. In versions of Python prior to 2.0 it was common to use this idiom:: +A try/except block is extremely efficient if no exceptions are raised. Actually +catching an exception is expensive. In versions of Python prior to 2.0 it was +common to use this idiom:: try: value = mydict[key] @@ -309,11 +310,10 @@ expensive. In versions of Python prior to 2.0 it was common to use this idiom:: This only made sense when you expected the dict to have the key almost all the time. If that wasn't the case, you coded it like this:: - if mydict.has_key(key): + if key in mydict: value = mydict[key] else: - mydict[key] = getvalue(key) - value = mydict[key] + value = mydict[key] = getvalue(key) .. note:: diff --git a/Doc/library/email.encoders.rst b/Doc/library/email.encoders.rst index 5421b9f..81d3096 100644 --- a/Doc/library/email.encoders.rst +++ b/Doc/library/email.encoders.rst @@ -18,6 +18,10 @@ exactly one argument, the message object to encode. They usually extract the payload, encode it, and reset the payload to this newly encoded value. They should also set the :mailheader:`Content-Transfer-Encoding` header as appropriate. +Note that these functions are not meaningful for a multipart message. They +must be applied to individual subparts instead, and will raise a +:exc:`TypeError` if passed a message whose type is multipart. + Here are the encoding functions provided: diff --git a/Doc/library/json.rst b/Doc/library/json.rst index 546a09d..6d4497f 100644 --- a/Doc/library/json.rst +++ b/Doc/library/json.rst @@ -170,6 +170,14 @@ Basic Usage :class:`unicode` instance. The other arguments have the same meaning as in :func:`dump`. + .. note:: + + Keys in key/value pairs of JSON are always of the type :class:`str`. When + a dictionary is converted into JSON, all the keys of the dictionary are + coerced to strings. As a result of this, if a dictionary is convered + into JSON and then back into a dictionary, the dictionary may not equal + the original one. That is, ``loads(dumps(x)) != x`` if x has non-string + keys. .. function:: load(fp[, encoding[, cls[, object_hook[, parse_float[, parse_int[, parse_constant[, object_pairs_hook[, **kw]]]]]]]]) diff --git a/Doc/library/re.rst b/Doc/library/re.rst index e3bac50..d64604f 100644 --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -766,8 +766,8 @@ Regular Expression Objects .. attribute:: RegexObject.flags - The flags argument used when the RE object was compiled, or ``0`` if no flags - were provided. + The regex matching flags. This is a combination of the flags given to + :func:`.compile` and any ``(?...)`` inline flags in the pattern. .. attribute:: RegexObject.groups @@ -1077,28 +1077,6 @@ The equivalent regular expression would be :: (\S+) - (\d+) errors, (\d+) warnings -Avoiding recursion -^^^^^^^^^^^^^^^^^^ - -If you create regular expressions that require the engine to perform a lot of -recursion, you may encounter a :exc:`RuntimeError` exception with the message -``maximum recursion limit`` exceeded. For example, :: - - >>> s = 'Begin ' + 1000*'a very long string ' + 'end' - >>> re.match('Begin (\w| )*? end', s).end() - Traceback (most recent call last): - File "<stdin>", line 1, in ? - File "/usr/local/lib/python2.5/re.py", line 132, in match - return _compile(pattern, flags).match(string) - RuntimeError: maximum recursion limit exceeded - -You can often restructure your regular expression to avoid recursion. - -Starting with Python 2.3, simple uses of the ``*?`` pattern are special-cased to -avoid recursion. Thus, the above regular expression can avoid recursion by -being recast as ``Begin [a-zA-Z0-9_ ]*?end``. As a further benefit, such -regular expressions will run faster than their recursive equivalents. - .. _search-vs-match: search() vs. match() @@ -1145,7 +1123,7 @@ creates a phonebook. First, here is the input. Normally it may come from a file, here we are using triple-quoted string syntax: - >>> input = """Ross McFluff: 834.345.1254 155 Elm Street + >>> text = """Ross McFluff: 834.345.1254 155 Elm Street ... ... Ronald Heathmore: 892.345.3428 436 Finley Avenue ... Frank Burger: 925.541.7625 662 South Dogwood Way @@ -1159,7 +1137,7 @@ into a list with each nonempty line having its own entry: .. doctest:: :options: +NORMALIZE_WHITESPACE - >>> entries = re.split("\n+", input) + >>> entries = re.split("\n+", text) >>> entries ['Ross McFluff: 834.345.1254 155 Elm Street', 'Ronald Heathmore: 892.345.3428 436 Finley Avenue', diff --git a/Lib/test/test_queue.py b/Lib/test/test_queue.py index 0b38e7e..f821db6 100644 --- a/Lib/test/test_queue.py +++ b/Lib/test/test_queue.py @@ -79,7 +79,7 @@ class BlockingTestMixin: self.fail("trigger thread ended but event never set") -class BaseQueueTest(unittest.TestCase, BlockingTestMixin): +class BaseQueueTest(BlockingTestMixin): def setUp(self): self.cum = 0 self.cumlock = threading.Lock() @@ -191,13 +191,13 @@ class BaseQueueTest(unittest.TestCase, BlockingTestMixin): self.simple_queue_test(q) -class QueueTest(BaseQueueTest): +class QueueTest(BaseQueueTest, unittest.TestCase): type2test = Queue.Queue -class LifoQueueTest(BaseQueueTest): +class LifoQueueTest(BaseQueueTest, unittest.TestCase): type2test = Queue.LifoQueue -class PriorityQueueTest(BaseQueueTest): +class PriorityQueueTest(BaseQueueTest, unittest.TestCase): type2test = Queue.PriorityQueue @@ -70,7 +70,7 @@ flag to configure:: $ make $ make install -This flag can be used a framework build of python, but also with a classic +This flag can be used with a framework build of python, but also with a classic unix build. Either way you will have to build python on Mac OS X 10.4 (or later) with Xcode 2.1 (or later). You also have to install the 10.4u SDK when installing Xcode. @@ -221,8 +221,8 @@ How do I create a binary distribution? Go to the directory "Mac/OSX/BuildScript". There you'll find a script "build-installer.py" that does all the work. This will download and build -a number of 3th-party libaries, configures and builds a framework Python, -installs it, creates the installer pacakge files and then packs this in a +a number of 3rd-party libaries, configures and builds a framework Python, +installs it, creates the installer package files and then packs this in a DMG image. The script will build a universal binary, you'll therefore have to run this @@ -258,8 +258,8 @@ architectures. Temporarily move ``/usr/local`` aside to finish the build. Uninstalling a framework install, including the binary installer ================================================================ -Uninstalling a framework can be done by manually removing all bits that got installed, -that's true for both installations from source and installations using the binary installer. +Uninstalling a framework can be done by manually removing all bits that got installed. +That's true for both installations from source and installations using the binary installer. Sadly enough OSX does not have a central uninstaller. The main bit of a framework install is the framework itself, installed in @@ -9,6 +9,9 @@ What's New in Python 2.7.4 Core and Builtins ----------------- +- Issue #14331: Use significantly less stack space when importing modules by + allocating path buffers on the heap instead of the stack. + - Issue #14334: Prevent in a segfault in type.__getattribute__ when it was not passed strings. Also fix segfaults in the __getattribute__ and __setattr__ methods of old-style classes. diff --git a/Python/import.c b/Python/import.c index 127b807..4d8a610 100644 --- a/Python/import.c +++ b/Python/import.c @@ -996,7 +996,7 @@ load_source_module(char *name, char *pathname, FILE *fp) { struct stat st; FILE *fpc; - char buf[MAXPATHLEN+1]; + char *buf; char *cpathname; PyCodeObject *co; PyObject *m; @@ -1015,6 +1015,10 @@ load_source_module(char *name, char *pathname, FILE *fp) */ st.st_mtime &= 0xFFFFFFFF; } + buf = PyMem_MALLOC(MAXPATHLEN+1); + if (buf == NULL) { + return PyErr_NoMemory(); + } cpathname = make_compiled_pathname(pathname, buf, (size_t)MAXPATHLEN + 1); if (cpathname != NULL && @@ -1022,9 +1026,9 @@ load_source_module(char *name, char *pathname, FILE *fp) co = read_compiled_module(cpathname, fpc); fclose(fpc); if (co == NULL) - return NULL; + goto error_exit; if (update_compiled_module(co, pathname) < 0) - return NULL; + goto error_exit; if (Py_VerboseFlag) PySys_WriteStderr("import %s # precompiled from %s\n", name, cpathname); @@ -1033,7 +1037,7 @@ load_source_module(char *name, char *pathname, FILE *fp) else { co = parse_source_module(pathname, fp); if (co == NULL) - return NULL; + goto error_exit; if (Py_VerboseFlag) PySys_WriteStderr("import %s # from %s\n", name, pathname); @@ -1046,7 +1050,12 @@ load_source_module(char *name, char *pathname, FILE *fp) m = PyImport_ExecCodeModuleEx(name, (PyObject *)co, pathname); Py_DECREF(co); + PyMem_FREE(buf); return m; + +error_exit: + PyMem_FREE(buf); + return NULL; } @@ -1066,7 +1075,7 @@ load_package(char *name, char *pathname) PyObject *file = NULL; PyObject *path = NULL; int err; - char buf[MAXPATHLEN+1]; + char *buf = NULL; FILE *fp = NULL; struct filedescr *fdp; @@ -1088,8 +1097,13 @@ load_package(char *name, char *pathname) err = PyDict_SetItemString(d, "__path__", path); if (err != 0) goto error; + buf = PyMem_MALLOC(MAXPATHLEN+1); + if (buf == NULL) { + PyErr_NoMemory(); + goto error; + } buf[0] = '\0'; - fdp = find_module(name, "__init__", path, buf, sizeof(buf), &fp, NULL); + fdp = find_module(name, "__init__", path, buf, MAXPATHLEN+1, &fp, NULL); if (fdp == NULL) { if (PyErr_ExceptionMatches(PyExc_ImportError)) { PyErr_Clear(); @@ -1107,6 +1121,8 @@ load_package(char *name, char *pathname) error: m = NULL; cleanup: + if (buf) + PyMem_FREE(buf); Py_XDECREF(path); Py_XDECREF(file); return m; @@ -1235,7 +1251,7 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf, static struct filedescr fd_frozen = {"", "", PY_FROZEN}; static struct filedescr fd_builtin = {"", "", C_BUILTIN}; static struct filedescr fd_package = {"", "", PKG_DIRECTORY}; - char name[MAXPATHLEN+1]; + char *name; #if defined(PYOS_OS2) size_t saved_len; size_t saved_namelen; @@ -1249,6 +1265,10 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf, "module name is too long"); return NULL; } + name = PyMem_MALLOC(MAXPATHLEN+1); + if (name == NULL) { + return PyErr_NoMemory(); + } strcpy(name, subname); /* sys.meta_path import hook */ @@ -1260,7 +1280,7 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf, PyErr_SetString(PyExc_RuntimeError, "sys.meta_path must be a list of " "import hooks"); - return NULL; + goto error_exit; } Py_INCREF(meta_path); /* zap guard */ npath = PyList_Size(meta_path); @@ -1273,12 +1293,13 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf, path : Py_None); if (loader == NULL) { Py_DECREF(meta_path); - return NULL; /* true error */ + goto error_exit; /* true error */ } if (loader != Py_None) { /* a loader was found */ *p_loader = loader; Py_DECREF(meta_path); + PyMem_FREE(name); return &importhookdescr; } Py_DECREF(loader); @@ -1292,7 +1313,7 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf, if (PyString_Size(path) + 1 + strlen(name) >= (size_t)buflen) { PyErr_SetString(PyExc_ImportError, "full frozen module name too long"); - return NULL; + goto error_exit; } strcpy(buf, PyString_AsString(path)); strcat(buf, "."); @@ -1300,19 +1321,22 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf, strcpy(name, buf); if (find_frozen(name) != NULL) { strcpy(buf, name); + PyMem_FREE(name); return &fd_frozen; } PyErr_Format(PyExc_ImportError, "No frozen submodule named %.200s", name); - return NULL; + goto error_exit; } if (path == NULL) { if (is_builtin(name)) { strcpy(buf, name); + PyMem_FREE(name); return &fd_builtin; } if ((find_frozen(name)) != NULL) { strcpy(buf, name); + PyMem_FREE(name); return &fd_frozen; } @@ -1320,6 +1344,7 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf, fp = PyWin_FindRegisteredModule(name, &fdp, buf, buflen); if (fp != NULL) { *p_fp = fp; + PyMem_FREE(name); return fdp; } #endif @@ -1328,7 +1353,7 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf, if (path == NULL || !PyList_Check(path)) { PyErr_SetString(PyExc_RuntimeError, "sys.path must be a list of directory names"); - return NULL; + goto error_exit; } path_hooks = PySys_GetObject("path_hooks"); @@ -1336,14 +1361,14 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf, PyErr_SetString(PyExc_RuntimeError, "sys.path_hooks must be a list of " "import hooks"); - return NULL; + goto error_exit; } path_importer_cache = PySys_GetObject("path_importer_cache"); if (path_importer_cache == NULL || !PyDict_Check(path_importer_cache)) { PyErr_SetString(PyExc_RuntimeError, "sys.path_importer_cache must be a dict"); - return NULL; + goto error_exit; } npath = PyList_Size(path); @@ -1352,13 +1377,13 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf, PyObject *copy = NULL; PyObject *v = PyList_GetItem(path, i); if (!v) - return NULL; + goto error_exit; #ifdef Py_USING_UNICODE if (PyUnicode_Check(v)) { copy = PyUnicode_Encode(PyUnicode_AS_UNICODE(v), PyUnicode_GET_SIZE(v), Py_FileSystemDefaultEncoding, NULL); if (copy == NULL) - return NULL; + goto error_exit; v = copy; } else @@ -1384,7 +1409,7 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf, path_hooks, v); if (importer == NULL) { Py_XDECREF(copy); - return NULL; + goto error_exit; } /* Note: importer is a borrowed reference */ if (importer != Py_None) { @@ -1394,10 +1419,11 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf, "s", fullname); Py_XDECREF(copy); if (loader == NULL) - return NULL; /* error */ + goto error_exit; /* error */ if (loader != Py_None) { /* a loader was found */ *p_loader = loader; + PyMem_FREE(name); return &importhookdescr; } Py_DECREF(loader); @@ -1421,6 +1447,7 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf, case_ok(buf, len, namelen, name)) { /* case matches */ if (find_init_module(buf)) { /* and has __init__.py */ Py_XDECREF(copy); + PyMem_FREE(name); return &fd_package; } else { @@ -1431,7 +1458,7 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf, if (PyErr_Warn(PyExc_ImportWarning, warnstr)) { Py_XDECREF(copy); - return NULL; + goto error_exit; } } } @@ -1506,10 +1533,15 @@ find_module(char *fullname, char *subname, PyObject *path, char *buf, if (fp == NULL) { PyErr_Format(PyExc_ImportError, "No module named %.200s", name); - return NULL; + goto error_exit; } *p_fp = fp; + PyMem_FREE(name); return fdp; + +error_exit: + PyMem_FREE(name); + return NULL; } /* Helpers for main.c @@ -2116,7 +2148,7 @@ static PyObject * import_module_level(char *name, PyObject *globals, PyObject *locals, PyObject *fromlist, int level) { - char buf[MAXPATHLEN+1]; + char *buf; Py_ssize_t buflen = 0; PyObject *parent, *head, *next, *tail; @@ -2130,14 +2162,18 @@ import_module_level(char *name, PyObject *globals, PyObject *locals, return NULL; } + buf = PyMem_MALLOC(MAXPATHLEN+1); + if (buf == NULL) { + return PyErr_NoMemory(); + } parent = get_parent(globals, buf, &buflen, level); if (parent == NULL) - return NULL; + goto error_exit; head = load_next(parent, level < 0 ? Py_None : parent, &name, buf, &buflen); if (head == NULL) - return NULL; + goto error_exit; tail = head; Py_INCREF(tail); @@ -2146,7 +2182,7 @@ import_module_level(char *name, PyObject *globals, PyObject *locals, Py_DECREF(tail); if (next == NULL) { Py_DECREF(head); - return NULL; + goto error_exit; } tail = next; } @@ -2158,7 +2194,7 @@ import_module_level(char *name, PyObject *globals, PyObject *locals, Py_DECREF(head); PyErr_SetString(PyExc_ValueError, "Empty module name"); - return NULL; + goto error_exit; } if (fromlist != NULL) { @@ -2168,16 +2204,22 @@ import_module_level(char *name, PyObject *globals, PyObject *locals, if (fromlist == NULL) { Py_DECREF(tail); + PyMem_FREE(buf); return head; } Py_DECREF(head); if (!ensure_fromlist(tail, fromlist, buf, buflen, 0)) { Py_DECREF(tail); - return NULL; + goto error_exit; } + PyMem_FREE(buf); return tail; + +error_exit: + PyMem_FREE(buf); + return NULL; } PyObject * @@ -2567,7 +2609,7 @@ import_submodule(PyObject *mod, char *subname, char *fullname) } else { PyObject *path, *loader = NULL; - char buf[MAXPATHLEN+1]; + char *buf; struct filedescr *fdp; FILE *fp = NULL; @@ -2582,11 +2624,16 @@ import_submodule(PyObject *mod, char *subname, char *fullname) } } + buf = PyMem_MALLOC(MAXPATHLEN+1); + if (buf == NULL) { + return PyErr_NoMemory(); + } buf[0] = '\0'; fdp = find_module(fullname, subname, path, buf, MAXPATHLEN+1, &fp, &loader); Py_XDECREF(path); if (fdp == NULL) { + PyMem_FREE(buf); if (!PyErr_ExceptionMatches(PyExc_ImportError)) return NULL; PyErr_Clear(); @@ -2601,6 +2648,7 @@ import_submodule(PyObject *mod, char *subname, char *fullname) Py_XDECREF(m); m = NULL; } + PyMem_FREE(buf); } return m; @@ -2618,7 +2666,7 @@ PyImport_ReloadModule(PyObject *m) PyObject *modules = PyImport_GetModuleDict(); PyObject *path = NULL, *loader = NULL, *existing_m = NULL; char *name, *subname; - char buf[MAXPATHLEN+1]; + char *buf; struct filedescr *fdp; FILE *fp = NULL; PyObject *newm; @@ -2678,6 +2726,11 @@ PyImport_ReloadModule(PyObject *m) if (path == NULL) PyErr_Clear(); } + buf = PyMem_MALLOC(MAXPATHLEN+1); + if (buf == NULL) { + Py_XDECREF(path); + return PyErr_NoMemory(); + } buf[0] = '\0'; fdp = find_module(name, subname, path, buf, MAXPATHLEN+1, &fp, &loader); Py_XDECREF(path); @@ -2685,6 +2738,7 @@ PyImport_ReloadModule(PyObject *m) if (fdp == NULL) { Py_XDECREF(loader); imp_modules_reloading_clear(); + PyMem_FREE(buf); return NULL; } @@ -2702,6 +2756,7 @@ PyImport_ReloadModule(PyObject *m) PyDict_SetItemString(modules, name, m); } imp_modules_reloading_clear(); + PyMem_FREE(buf); return newm; } @@ -2832,19 +2887,27 @@ call_find_module(char *name, PyObject *path) extern int fclose(FILE *); PyObject *fob, *ret; struct filedescr *fdp; - char pathname[MAXPATHLEN+1]; + char *pathname; FILE *fp = NULL; + pathname = PyMem_MALLOC(MAXPATHLEN+1); + if (pathname == NULL) { + return PyErr_NoMemory(); + } pathname[0] = '\0'; if (path == Py_None) path = NULL; fdp = find_module(NULL, name, path, pathname, MAXPATHLEN+1, &fp, NULL); - if (fdp == NULL) + if (fdp == NULL) { + PyMem_FREE(pathname); return NULL; + } if (fp != NULL) { fob = PyFile_FromFile(fp, pathname, fdp->mode, fclose); - if (fob == NULL) + if (fob == NULL) { + PyMem_FREE(pathname); return NULL; + } } else { fob = Py_None; @@ -2853,6 +2916,7 @@ call_find_module(char *name, PyObject *path) ret = Py_BuildValue("Os(ssi)", fob, pathname, fdp->suffix, fdp->mode, fdp->type); Py_DECREF(fob); + PyMem_FREE(pathname); return ret; } |