[Python-checkins] cpython (merge 2.7 -> 2.7): merge heads

benjamin.peterson python-checkins at python.org
Mon Mar 19 02:23:35 CET 2012


http://hg.python.org/cpython/rev/22db03646d9b
changeset:   75832:22db03646d9b
branch:      2.7
parent:      75831:9f0bf9992664
parent:      75825:ad030571e6c0
user:        Benjamin Peterson <benjamin at python.org>
date:        Sun Mar 18 21:23:22 2012 -0400
summary:
  merge heads

files:
  .hgtags                        |    2 +
  Doc/faq/design.rst             |   10 +-
  Doc/library/email.encoders.rst |    4 +
  Doc/library/json.rst           |    8 +
  Doc/library/re.rst             |   30 +----
  Lib/test/test_queue.py         |    8 +-
  Mac/README                     |   10 +-
  Misc/NEWS                      |    3 +
  Python/import.c                |  126 +++++++++++++++-----
  9 files changed, 130 insertions(+), 71 deletions(-)


diff --git a/.hgtags b/.hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -137,6 +137,8 @@
 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
--- a/Doc/faq/design.rst
+++ b/Doc/faq/design.rst
@@ -297,8 +297,9 @@
 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 @@
 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
--- a/Doc/library/email.encoders.rst
+++ b/Doc/library/email.encoders.rst
@@ -18,6 +18,10 @@
 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
--- a/Doc/library/json.rst
+++ b/Doc/library/json.rst
@@ -170,6 +170,14 @@
    :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
--- a/Doc/library/re.rst
+++ b/Doc/library/re.rst
@@ -766,8 +766,8 @@
 
    .. 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 @@
    (\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 @@
 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 @@
 .. 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
--- a/Lib/test/test_queue.py
+++ b/Lib/test/test_queue.py
@@ -79,7 +79,7 @@
                 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 @@
         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
 
 
diff --git a/Mac/README b/Mac/README
--- a/Mac/README
+++ b/Mac/README
@@ -70,7 +70,7 @@
   $ 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 @@
 
 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 @@
 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
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -9,6 +9,9 @@
 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
--- a/Python/import.c
+++ b/Python/import.c
@@ -996,7 +996,7 @@
 {
     struct stat st;
     FILE *fpc;
-    char buf[MAXPATHLEN+1];
+    char *buf;
     char *cpathname;
     PyCodeObject *co;
     PyObject *m;
@@ -1015,6 +1015,10 @@
          */
         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 @@
         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 @@
     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 @@
     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 @@
     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 @@
         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 @@
   error:
     m = NULL;
   cleanup:
+    if (buf)
+        PyMem_FREE(buf);
     Py_XDECREF(path);
     Py_XDECREF(file);
     return m;
@@ -1235,7 +1251,7 @@
     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 @@
                         "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 @@
             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 @@
                                          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 @@
         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 @@
         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 @@
         fp = PyWin_FindRegisteredModule(name, &fdp, buf, buflen);
         if (fp != NULL) {
             *p_fp = fp;
+            PyMem_FREE(name);
             return fdp;
         }
 #endif
@@ -1328,7 +1353,7 @@
     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 @@
         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 @@
         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 @@
                                          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 @@
                                              "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 @@
             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 @@
                 if (PyErr_Warn(PyExc_ImportWarning,
                                warnstr)) {
                     Py_XDECREF(copy);
-                    return NULL;
+                    goto error_exit;
                 }
             }
         }
@@ -1506,10 +1533,15 @@
     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 @@
 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 @@
         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 @@
         Py_DECREF(tail);
         if (next == NULL) {
             Py_DECREF(head);
-            return NULL;
+            goto error_exit;
         }
         tail = next;
     }
@@ -2158,7 +2194,7 @@
         Py_DECREF(head);
         PyErr_SetString(PyExc_ValueError,
                         "Empty module name");
-        return NULL;
+        goto error_exit;
     }
 
     if (fromlist != NULL) {
@@ -2168,16 +2204,22 @@
 
     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 @@
     }
     else {
         PyObject *path, *loader = NULL;
-        char buf[MAXPATHLEN+1];
+        char *buf;
         struct filedescr *fdp;
         FILE *fp = NULL;
 
@@ -2582,11 +2624,16 @@
             }
         }
 
+        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 @@
             Py_XDECREF(m);
             m = NULL;
         }
+        PyMem_FREE(buf);
     }
 
     return m;
@@ -2618,7 +2666,7 @@
     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 @@
         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 @@
     if (fdp == NULL) {
         Py_XDECREF(loader);
         imp_modules_reloading_clear();
+        PyMem_FREE(buf);
         return NULL;
     }
 
@@ -2702,6 +2756,7 @@
         PyDict_SetItemString(modules, name, m);
     }
     imp_modules_reloading_clear();
+    PyMem_FREE(buf);
     return newm;
 }
 
@@ -2832,19 +2887,27 @@
     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 @@
     ret = Py_BuildValue("Os(ssi)",
                   fob, pathname, fdp->suffix, fdp->mode, fdp->type);
     Py_DECREF(fob);
+    PyMem_FREE(pathname);
     return ret;
 }
 

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list