[Python-checkins] bpo-44885: Correct the ast locations of f-strings with format specs and repeated expressions (GH-27729)

pablogsal webhook-mailer at python.org
Thu Aug 12 12:13:41 EDT 2021


https://github.com/python/cpython/commit/8e832fb2a2cb54d7262148b6ec15563dffb48d63
commit: 8e832fb2a2cb54d7262148b6ec15563dffb48d63
branch: main
author: Pablo Galindo Salgado <Pablogsal at gmail.com>
committer: pablogsal <Pablogsal at gmail.com>
date: 2021-08-12T17:13:30+01:00
summary:

bpo-44885: Correct the ast locations of f-strings with format specs and repeated expressions (GH-27729)

files:
A Misc/NEWS.d/next/Core and Builtins/2021-08-11-15-39-57.bpo-44885.i4noUO.rst
M Lib/test/test_fstring.py
M Parser/string_parser.c
M Python/importlib.h
M Python/importlib_external.h
M Python/importlib_zipimport.h

diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py
index caae1b7c4f8535..14a4c678fc9097 100644
--- a/Lib/test/test_fstring.py
+++ b/Lib/test/test_fstring.py
@@ -212,11 +212,6 @@ def test_ast_line_numbers_nested(self):
         self.assertEqual(call.col_offset, 11)
 
     def test_ast_line_numbers_duplicate_expression(self):
-        """Duplicate expression
-
-        NOTE: this is currently broken, always sets location of the first
-        expression.
-        """
         expr = """
 a = 10
 f'{a * x()} {a * x()} {a * x()}'
@@ -266,9 +261,9 @@ def test_ast_line_numbers_duplicate_expression(self):
         self.assertEqual(binop.lineno, 3)
         self.assertEqual(binop.left.lineno, 3)
         self.assertEqual(binop.right.lineno, 3)
-        self.assertEqual(binop.col_offset, 3)  # FIXME: this is wrong
-        self.assertEqual(binop.left.col_offset, 3)  # FIXME: this is wrong
-        self.assertEqual(binop.right.col_offset, 7)  # FIXME: this is wrong
+        self.assertEqual(binop.col_offset, 13)
+        self.assertEqual(binop.left.col_offset, 13)
+        self.assertEqual(binop.right.col_offset, 17)
         # check the third binop location
         binop = t.body[1].value.values[4].value
         self.assertEqual(type(binop), ast.BinOp)
@@ -278,9 +273,32 @@ def test_ast_line_numbers_duplicate_expression(self):
         self.assertEqual(binop.lineno, 3)
         self.assertEqual(binop.left.lineno, 3)
         self.assertEqual(binop.right.lineno, 3)
-        self.assertEqual(binop.col_offset, 3)  # FIXME: this is wrong
-        self.assertEqual(binop.left.col_offset, 3)  # FIXME: this is wrong
-        self.assertEqual(binop.right.col_offset, 7)  # FIXME: this is wrong
+        self.assertEqual(binop.col_offset, 23)
+        self.assertEqual(binop.left.col_offset, 23)
+        self.assertEqual(binop.right.col_offset, 27)
+
+    def test_ast_numbers_fstring_with_formatting(self):
+
+        t = ast.parse('f"Here is that pesky {xxx:.3f} again"')
+        self.assertEqual(len(t.body), 1)
+        self.assertEqual(t.body[0].lineno, 1)
+
+        self.assertEqual(type(t.body[0]), ast.Expr)
+        self.assertEqual(type(t.body[0].value), ast.JoinedStr)
+        self.assertEqual(len(t.body[0].value.values), 3)
+
+        self.assertEqual(type(t.body[0].value.values[0]), ast.Constant)
+        self.assertEqual(type(t.body[0].value.values[1]), ast.FormattedValue)
+        self.assertEqual(type(t.body[0].value.values[2]), ast.Constant)
+
+        _, expr, _ = t.body[0].value.values
+
+        name = expr.value
+        self.assertEqual(type(name), ast.Name)
+        self.assertEqual(name.lineno, 1)
+        self.assertEqual(name.end_lineno, 1)
+        self.assertEqual(name.col_offset, 22)
+        self.assertEqual(name.end_col_offset, 25)
 
     def test_ast_line_numbers_multiline_fstring(self):
         # See bpo-30465 for details.
diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-08-11-15-39-57.bpo-44885.i4noUO.rst b/Misc/NEWS.d/next/Core and Builtins/2021-08-11-15-39-57.bpo-44885.i4noUO.rst
new file mode 100644
index 00000000000000..c6abd7363af711
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2021-08-11-15-39-57.bpo-44885.i4noUO.rst	
@@ -0,0 +1,2 @@
+Correct the ast locations of f-strings with format specs and repeated
+expressions. Patch by Pablo Galindo
diff --git a/Parser/string_parser.c b/Parser/string_parser.c
index 66405b26f37e4c..fb37d37553a552 100644
--- a/Parser/string_parser.c
+++ b/Parser/string_parser.c
@@ -279,49 +279,48 @@ _PyPegen_parsestr(Parser *p, int *bytesmode, int *rawmode, PyObject **result,
 /* Fix locations for the given node and its children.
 
    `parent` is the enclosing node.
+   `expr_start` is the starting position of the expression (pointing to the open brace).
    `n` is the node which locations are going to be fixed relative to parent.
    `expr_str` is the child node's string representation, including braces.
 */
 static bool
-fstring_find_expr_location(Token *parent, char *expr_str, int *p_lines, int *p_cols)
+fstring_find_expr_location(Token *parent, const char* expr_start, char *expr_str, int *p_lines, int *p_cols)
 {
     *p_lines = 0;
     *p_cols = 0;
+    assert(expr_start != NULL && *expr_start == '{');
     if (parent && parent->bytes) {
         const char *parent_str = PyBytes_AsString(parent->bytes);
         if (!parent_str) {
             return false;
         }
-        const char *substr = strstr(parent_str, expr_str);
-        if (substr) {
-            // The following is needed, in order to correctly shift the column
-            // offset, in the case that (disregarding any whitespace) a newline
-            // immediately follows the opening curly brace of the fstring expression.
-            bool newline_after_brace = 1;
-            const char *start = substr + 1;
-            while (start && *start != '}' && *start != '\n') {
-                if (*start != ' ' && *start != '\t' && *start != '\f') {
-                    newline_after_brace = 0;
-                    break;
-                }
-                start++;
+        // The following is needed, in order to correctly shift the column
+        // offset, in the case that (disregarding any whitespace) a newline
+        // immediately follows the opening curly brace of the fstring expression.
+        bool newline_after_brace = 1;
+        const char *start = expr_start + 1;
+        while (start && *start != '}' && *start != '\n') {
+            if (*start != ' ' && *start != '\t' && *start != '\f') {
+                newline_after_brace = 0;
+                break;
             }
+            start++;
+        }
 
-            // Account for the characters from the last newline character to our
-            // left until the beginning of substr.
-            if (!newline_after_brace) {
-                start = substr;
-                while (start > parent_str && *start != '\n') {
-                    start--;
-                }
-                *p_cols += (int)(substr - start);
+        // Account for the characters from the last newline character to our
+        // left until the beginning of expr_start.
+        if (!newline_after_brace) {
+            start = expr_start;
+            while (start > parent_str && *start != '\n') {
+                start--;
             }
-            /* adjust the start based on the number of newlines encountered
-               before the f-string expression */
-            for (const char *p = parent_str; p < substr; p++) {
-                if (*p == '\n') {
-                    (*p_lines)++;
-                }
+            *p_cols += (int)(expr_start - start);
+        }
+        /* adjust the start based on the number of newlines encountered
+           before the f-string expression */
+        for (const char *p = parent_str; p < expr_start; p++) {
+            if (*p == '\n') {
+                (*p_lines)++;
             }
         }
     }
@@ -365,7 +364,7 @@ fstring_compile_expr(Parser *p, const char *expr_start, const char *expr_end,
 
     len = expr_end - expr_start;
     /* Allocate 3 extra bytes: open paren, close paren, null byte. */
-    str = PyMem_Malloc(len + 3);
+    str = PyMem_Calloc(len + 3, sizeof(char));
     if (str == NULL) {
         PyErr_NoMemory();
         return NULL;
@@ -373,17 +372,10 @@ fstring_compile_expr(Parser *p, const char *expr_start, const char *expr_end,
 
     // The call to fstring_find_expr_location is responsible for finding the column offset
     // the generated AST nodes need to be shifted to the right, which is equal to the number
-    // of the f-string characters before the expression starts. In order to correctly compute
-    // this offset, strstr gets called in fstring_find_expr_location which only succeeds
-    // if curly braces appear before and after the f-string expression (exactly like they do
-    // in the f-string itself), hence the following lines.
-    str[0] = '{';
+    // of the f-string characters before the expression starts.
     memcpy(str+1, expr_start, len);
-    str[len+1] = '}';
-    str[len+2] = 0;
-
     int lines, cols;
-    if (!fstring_find_expr_location(t, str, &lines, &cols)) {
+    if (!fstring_find_expr_location(t, expr_start-1, str+1, &lines, &cols)) {
         PyMem_Free(str);
         return NULL;
     }
diff --git a/Python/importlib.h b/Python/importlib.h
index b62cc9db179168..da94fc35c7f06f 100644
--- a/Python/importlib.h
+++ b/Python/importlib.h
@@ -1518,7 +1518,7 @@ const unsigned char _Py_M__importlib_bootstrap[] = {
     109,111,100,117,108,101,95,114,101,112,114,224,2,0,0,115,
     8,0,0,0,6,7,2,1,4,255,22,2,115,6,0,0,
     0,2,7,10,1,22,1,115,34,0,0,0,9,18,9,80,
-    24,59,61,79,9,80,9,80,16,75,17,23,17,32,16,75,
+    24,59,61,79,9,80,9,80,16,75,27,33,27,42,16,75,
     16,75,48,63,48,71,16,75,16,75,16,75,9,75,114,17,
     0,0,0,78,99,4,0,0,0,0,0,0,0,0,0,0,
     0,5,0,0,0,3,0,0,0,115,42,0,0,0,124,2,
@@ -2127,7 +2127,7 @@ const unsigned char _Py_M__importlib_bootstrap[] = {
     60,13,60,0,0,8,14,5,47,25,28,25,36,37,43,25,
     44,9,22,9,47,13,20,21,34,36,41,43,49,13,50,13,
     50,12,18,5,18,0,0,9,47,16,30,9,47,9,47,9,
-    47,9,47,19,86,20,26,19,86,19,86,20,25,19,86,19,
+    47,9,47,19,86,49,55,19,86,19,86,77,82,19,86,19,
     86,13,16,13,22,13,47,28,31,33,46,13,47,13,47,13,
     47,12,18,5,18,9,47,0,0,12,18,5,18,115,39,0,
     0,0,167,3,43,0,171,23,65,2,7,193,40,4,65,52,
@@ -2323,7 +2323,7 @@ const unsigned char _Py_M__importlib_bootstrap[] = {
     0,15,22,15,41,27,40,15,41,5,12,12,19,12,35,24,
     34,12,35,5,9,8,15,23,27,8,27,5,49,12,16,24,
     28,12,28,9,56,33,40,44,48,44,55,33,55,9,56,13,
-    22,13,56,28,63,29,36,28,63,28,63,29,33,29,40,28,
+    22,13,56,28,63,32,39,28,63,28,63,47,51,47,58,28,
     63,28,63,28,63,28,41,54,55,13,56,13,56,13,56,16,
     23,9,23,10,14,22,26,10,26,5,49,16,20,16,27,9,
     27,9,18,9,52,24,63,24,37,50,51,9,52,9,52,9,
diff --git a/Python/importlib_external.h b/Python/importlib_external.h
index 1572d0d4d9bca0..c49fa5516eb26c 100644
--- a/Python/importlib_external.h
+++ b/Python/importlib_external.h
@@ -685,15 +685,15 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = {
     41,44,52,28,52,12,53,9,43,20,24,25,28,29,42,25,
     43,25,44,25,44,20,45,13,17,39,43,13,36,12,35,5,
     42,25,36,37,41,25,42,9,22,9,13,15,22,12,19,23,
-    31,12,31,9,42,19,29,33,41,30,41,30,41,31,35,30,
+    31,12,31,9,42,19,29,33,41,30,41,30,41,33,37,30,
     41,30,41,19,42,13,42,17,33,17,44,40,43,17,44,5,
-    14,8,17,25,31,8,31,5,51,15,25,26,78,27,43,26,
+    14,8,17,25,31,8,31,5,51,15,25,26,78,58,74,26,
     78,26,78,15,79,9,79,10,19,23,24,10,24,5,51,24,
     40,24,55,48,51,53,54,24,55,56,58,24,59,9,21,16,
-    28,16,45,40,44,16,45,9,47,19,29,30,46,31,35,30,
+    28,16,45,40,44,16,45,9,47,19,29,30,46,38,42,30,
     46,30,46,19,47,13,47,21,33,34,37,38,42,34,43,34,
     44,34,44,21,45,9,18,16,25,16,35,16,35,9,51,19,
-    29,30,50,31,43,30,50,30,50,30,50,19,51,13,51,21,
+    29,30,50,52,64,30,50,30,50,30,50,19,51,13,51,21,
     37,21,52,48,51,21,52,53,54,21,55,5,18,12,22,23,
     27,29,42,45,60,61,62,45,63,29,63,12,64,5,64,114,
     10,0,0,0,99,1,0,0,0,0,0,0,0,0,0,0,
@@ -974,15 +974,15 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = {
     16,6,1,2,3,16,254,12,1,16,1,10,1,2,3,10,
     254,12,1,8,1,16,1,6,2,2,2,16,255,16,1,4,
     1,115,166,0,0,0,13,17,18,20,19,20,18,20,13,21,
-    5,10,8,13,17,29,8,29,5,50,19,61,20,24,19,61,
-    19,61,20,25,19,61,19,61,9,16,9,19,9,51,37,41,
+    5,10,8,13,17,29,8,29,5,50,19,61,42,46,19,61,
+    19,61,52,57,19,61,19,61,9,16,9,19,9,51,37,41,
     43,50,9,51,9,51,15,26,27,34,15,50,15,50,38,49,
     15,50,15,50,9,50,8,11,12,16,8,17,20,22,8,22,
-    5,32,19,70,20,24,19,70,19,70,9,16,9,19,9,51,
+    5,32,19,70,62,66,19,70,19,70,9,16,9,19,9,51,
     37,41,43,50,9,51,9,51,15,23,24,31,15,32,9,32,
     13,27,28,32,33,34,35,36,33,36,28,37,13,38,5,10,
-    8,13,16,21,8,21,5,50,19,57,20,25,19,57,19,57,
-    20,24,19,57,19,57,9,16,15,26,27,34,15,50,15,50,
+    8,13,16,21,8,21,5,50,19,57,36,41,19,57,19,57,
+    49,53,19,57,19,57,9,16,15,26,27,34,15,50,15,50,
     38,49,15,50,15,50,9,50,12,17,5,17,114,10,0,0,
     0,99,5,0,0,0,0,0,0,0,0,0,0,0,4,0,
     0,0,3,0,0,0,115,124,0,0,0,116,0,124,0,100,
@@ -1041,12 +1041,12 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = {
     1,2,255,22,2,8,254,115,18,0,0,0,22,19,2,3,
     10,254,12,1,16,1,6,1,2,2,22,255,32,1,115,124,
     0,0,0,8,22,23,27,28,29,30,32,28,32,23,33,8,
-    34,39,51,54,64,39,64,8,65,5,50,19,52,20,24,19,
+    34,39,51,54,64,39,64,8,65,5,50,19,52,44,48,19,
     52,19,52,9,16,9,19,9,51,37,41,43,50,9,51,9,
     51,15,26,27,34,15,50,15,50,38,49,15,50,15,50,9,
     50,9,20,28,32,9,32,5,76,9,23,24,28,29,31,32,
     34,29,34,24,35,9,36,41,52,55,65,41,65,9,66,5,
-    76,15,26,27,60,28,32,27,60,27,60,15,76,15,76,64,
+    76,15,26,27,60,52,56,27,60,27,60,15,76,15,76,64,
     75,15,76,15,76,9,76,5,76,5,76,5,76,5,76,114,
     10,0,0,0,99,4,0,0,0,0,0,0,0,0,0,0,
     0,4,0,0,0,3,0,0,0,115,42,0,0,0,124,0,
@@ -1096,7 +1096,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = {
     0,0,16,17,2,1,8,1,4,255,2,2,6,254,4,255,
     115,14,0,0,0,14,17,2,4,2,253,8,1,4,2,2,
     255,10,1,115,42,0,0,0,8,12,13,14,15,17,13,17,
-    8,18,22,33,8,33,5,10,15,26,13,71,14,18,13,71,
+    8,18,22,33,8,33,5,10,15,26,13,71,63,67,13,71,
     13,71,15,10,15,10,15,26,15,10,15,10,9,10,5,10,
     5,10,114,10,0,0,0,99,4,0,0,0,0,0,0,0,
     0,0,0,0,5,0,0,0,3,0,0,0,115,76,0,0,
diff --git a/Python/importlib_zipimport.h b/Python/importlib_zipimport.h
index 370c980c8fe73b..c12ed5215b3f88 100644
--- a/Python/importlib_zipimport.h
+++ b/Python/importlib_zipimport.h
@@ -481,7 +481,7 @@ const unsigned char _Py_M__zipimport[] = {
     0,0,10,7,6,1,20,1,10,2,2,1,2,3,14,254,
     10,2,2,6,12,253,2,128,2,3,2,254,16,2,2,128,
     16,1,115,128,0,0,0,14,30,31,35,37,45,14,46,9,
-    11,12,14,18,22,12,22,9,83,19,33,34,67,35,43,34,
+    11,12,14,18,22,12,22,9,83,19,33,34,67,55,63,34,
     67,34,67,74,82,19,83,19,83,13,83,16,32,33,37,39,
     47,16,48,9,13,12,14,9,36,24,43,24,54,55,59,61,
     74,24,75,13,21,13,21,27,31,24,36,24,36,24,36,13,
@@ -513,7 +513,7 @@ const unsigned char _Py_M__zipimport[] = {
     8,0,0,0,10,6,8,1,18,1,4,1,115,8,0,0,
     0,10,6,6,1,20,1,4,1,115,40,0,0,0,14,30,
     31,35,37,45,14,46,9,11,12,14,18,22,12,22,9,83,
-    19,33,34,67,35,43,34,67,34,67,74,82,19,83,19,83,
+    19,33,34,67,55,63,34,67,34,67,74,82,19,83,19,83,
     13,83,16,18,9,18,114,10,0,0,0,99,2,0,0,0,
     0,0,0,0,0,0,0,0,8,0,0,0,3,0,0,0,
     115,0,1,0,0,100,1,125,2,116,0,106,1,124,2,116,
@@ -607,7 +607,7 @@ const unsigned char _Py_M__zipimport[] = {
     13,37,0,0,9,18,9,18,9,18,17,20,17,28,29,37,
     17,38,13,18,0,0,9,86,19,22,19,30,31,39,19,40,
     13,16,13,16,0,0,9,86,16,24,9,86,9,86,9,86,
-    9,86,19,30,31,85,32,40,31,85,31,85,31,85,19,86,
+    9,86,19,30,31,85,48,56,31,85,31,85,31,85,19,86,
     13,86,9,86,0,0,9,19,9,36,37,69,71,79,81,88,
     9,89,9,89,16,19,9,19,115,23,0,0,0,172,40,65,
     21,0,193,21,9,65,30,7,193,32,5,65,38,0,193,38,
@@ -918,42 +918,42 @@ const unsigned char _Py_M__zipimport[] = {
     2,128,12,2,12,1,20,1,8,1,8,1,4,202,2,6,
     22,48,2,128,12,0,14,1,4,1,115,240,4,0,0,5,
     80,14,17,14,27,28,35,14,36,9,11,9,11,0,0,5,
-    80,12,19,5,80,5,80,5,80,5,80,15,29,30,65,31,
-    38,30,65,30,65,72,79,15,80,15,80,9,80,5,80,0,
+    80,12,19,5,80,5,80,5,80,5,80,15,29,30,65,54,
+    61,30,65,30,65,72,79,15,80,15,80,9,80,5,80,0,
     0,10,12,5,23,5,23,9,84,13,15,13,46,22,42,21,
     42,44,45,13,46,13,46,31,33,31,40,31,40,13,28,22,
     24,22,51,30,50,22,51,13,19,13,19,0,0,9,84,16,
-    23,9,84,9,84,9,84,9,84,19,33,34,69,35,42,34,
+    23,9,84,9,84,9,84,9,84,19,33,34,69,58,65,34,
     69,34,69,76,83,19,84,19,84,13,84,9,84,0,0,12,
-    15,16,22,12,23,27,47,12,47,9,84,19,33,34,69,35,
-    42,34,69,34,69,76,83,19,84,19,84,13,84,12,18,19,
+    15,16,22,12,23,27,47,12,47,9,84,19,33,34,69,58,
+    65,34,69,34,69,76,83,19,84,19,84,13,84,12,18,19,
     21,20,21,19,21,12,22,26,44,12,44,9,58,13,51,17,
     19,17,30,25,26,28,29,17,30,17,30,29,31,29,38,29,
     38,17,26,17,26,0,0,13,51,20,27,13,51,13,51,13,
-    51,13,51,23,37,38,73,39,46,38,73,38,73,43,50,23,
+    51,13,51,23,37,38,73,62,69,38,73,38,73,43,50,23,
     51,23,51,17,51,13,51,0,0,33,36,37,46,49,64,37,
     64,37,57,37,57,59,60,33,61,13,30,13,51,17,19,17,
     43,25,42,17,43,17,43,24,26,24,33,24,33,17,21,17,
     21,0,0,13,51,20,27,13,51,13,51,13,51,13,51,23,
-    37,38,73,39,46,38,73,38,73,43,50,23,51,23,51,17,
+    37,38,73,62,69,38,73,38,73,43,50,23,51,23,51,17,
     51,13,51,0,0,19,23,19,49,30,48,19,49,13,16,16,
-    19,22,23,16,23,13,51,23,37,38,68,39,46,38,68,38,
+    19,22,23,16,23,13,51,23,37,38,68,57,64,38,68,38,
     68,43,50,23,51,23,51,17,51,22,26,27,30,31,34,35,
     55,31,55,27,55,22,56,13,19,16,19,20,26,16,27,31,
-    51,16,51,13,51,23,37,38,70,39,46,38,70,38,70,43,
+    51,16,51,13,51,23,37,38,70,59,66,38,70,38,70,43,
     50,23,51,23,51,17,51,31,40,43,46,47,51,43,52,31,
     52,55,58,31,58,13,28,23,37,38,44,45,47,48,50,45,
     50,38,51,23,52,9,20,25,39,40,46,47,49,50,52,47,
     52,40,53,25,54,9,22,12,27,30,41,12,41,9,91,19,
-    33,34,76,35,42,34,76,34,76,83,90,19,91,19,91,13,
-    91,12,27,30,43,12,43,9,93,19,33,34,78,35,42,34,
+    33,34,76,65,72,34,76,34,76,83,90,19,91,19,91,13,
+    91,12,27,30,43,12,43,9,93,19,33,34,78,67,74,34,
     78,34,78,85,92,19,93,19,93,13,93,9,24,28,39,9,
     39,9,24,22,37,40,53,22,53,9,19,12,22,25,26,12,
-    26,9,101,9,101,19,33,34,86,35,42,34,86,34,86,93,
+    26,9,101,9,101,19,33,34,86,75,82,34,86,34,86,93,
     100,19,101,19,101,13,101,17,19,9,14,17,18,9,14,9,
     84,13,15,13,37,21,36,13,37,13,37,13,37,0,0,9,
     84,16,23,9,84,9,84,9,84,9,84,9,84,19,33,34,
-    69,35,42,34,69,34,69,76,83,19,84,19,84,13,84,9,
+    69,58,65,34,69,34,69,76,83,19,84,19,84,13,84,9,
     84,0,0,15,19,22,24,22,33,30,32,22,33,13,19,16,
     19,20,26,16,27,30,31,16,31,13,62,13,62,23,31,32,
     61,23,62,17,62,16,22,23,25,24,25,23,25,16,26,30,
@@ -971,18 +971,18 @@ const unsigned char _Py_M__zipimport[] = {
     23,28,42,43,49,50,52,53,55,50,55,43,56,28,57,13,
     25,27,41,42,48,49,51,52,54,49,54,42,55,27,56,13,
     24,27,36,39,49,27,49,52,64,27,64,13,24,16,27,30,
-    43,16,43,13,92,13,92,23,37,38,77,39,46,38,77,38,
+    43,16,43,13,92,13,92,23,37,38,77,66,73,38,77,38,
     77,84,91,23,92,23,92,17,92,13,24,28,38,13,38,13,
     24,13,88,24,26,24,42,32,41,24,42,17,21,17,21,0,
     0,13,88,20,27,13,88,13,88,13,88,13,88,13,88,23,
-    37,38,73,39,46,38,73,38,73,80,87,23,88,23,88,17,
+    37,38,73,62,69,38,73,38,73,80,87,23,88,23,88,17,
     88,13,88,0,0,16,19,20,24,16,25,29,38,16,38,13,
-    88,13,88,23,37,38,73,39,46,38,73,38,73,80,87,23,
+    88,13,88,23,37,38,73,62,69,38,73,38,73,80,87,23,
     88,23,88,17,88,13,88,20,23,24,26,24,56,32,43,46,
     55,32,55,24,56,20,57,61,72,75,84,61,84,20,84,17,
-    92,17,92,27,41,42,77,43,50,42,77,42,77,84,91,27,
+    92,17,92,27,41,42,77,66,73,42,77,42,77,84,91,27,
     92,27,92,21,92,17,92,0,0,13,88,20,27,13,88,13,
-    88,13,88,13,88,13,88,23,37,38,73,39,46,38,73,38,
+    88,13,88,13,88,13,88,23,37,38,73,62,69,38,73,38,
     73,80,87,23,88,23,88,17,88,13,88,0,0,16,21,24,
     29,16,29,13,72,13,72,24,28,24,37,24,37,17,21,17,
     21,17,72,28,32,28,48,40,47,28,48,21,25,21,25,0,
@@ -1137,17 +1137,17 @@ const unsigned char _Py_M__zipimport[] = {
     29,30,50,15,51,9,51,10,13,10,23,24,31,10,32,5,
     56,36,38,9,84,13,15,13,33,21,32,13,33,13,33,13,
     33,0,0,9,84,16,23,9,84,9,84,9,84,9,84,19,
-    33,34,69,35,42,34,69,34,69,76,83,19,84,19,84,13,
+    33,34,69,58,65,34,69,34,69,76,83,19,84,19,84,13,
     84,9,84,0,0,18,20,18,29,26,28,18,29,9,15,12,
     15,16,22,12,23,27,29,12,29,9,58,19,27,28,57,19,
     58,13,58,12,18,19,21,20,21,19,21,12,22,26,39,12,
-    39,9,86,19,33,34,71,35,42,34,71,34,71,78,85,19,
+    39,9,86,19,33,34,71,60,67,34,71,34,71,78,85,19,
     86,19,86,13,86,21,35,36,42,43,45,46,48,43,48,36,
     49,21,50,9,18,22,36,37,43,44,46,47,49,44,49,37,
     50,22,51,9,19,23,25,28,37,23,37,40,50,23,50,9,
     20,9,20,24,35,9,35,9,20,9,84,13,15,13,33,21,
     32,13,33,13,33,13,33,0,0,9,84,16,23,9,84,9,
-    84,9,84,9,84,19,33,34,69,35,42,34,69,34,69,76,
+    84,9,84,9,84,19,33,34,69,58,65,34,69,34,69,76,
     83,19,84,19,84,13,84,9,84,0,0,20,22,20,38,28,
     37,20,38,9,17,12,15,16,24,12,25,29,38,12,38,9,
     56,19,26,27,55,19,56,13,56,9,56,5,56,5,56,5,
@@ -1241,10 +1241,10 @@ const unsigned char _Py_M__zipimport[] = {
     57,13,58,9,34,9,21,23,34,12,24,9,28,21,30,31,
     45,46,50,51,52,53,55,51,55,46,56,31,57,59,71,21,
     72,13,28,21,35,36,40,41,43,44,46,41,46,36,47,21,
-    48,52,63,21,63,13,28,17,27,17,44,21,58,22,30,21,
+    48,52,63,21,63,13,28,17,27,17,44,21,58,46,54,21,
     58,21,58,17,59,17,59,24,28,24,28,12,19,12,25,26,
     30,31,33,31,34,31,34,26,35,12,36,5,9,12,22,23,
-    27,29,39,12,40,5,78,15,24,25,77,26,34,25,77,25,
+    27,29,39,12,40,5,78,15,24,25,77,44,52,25,77,25,
     77,25,77,15,78,9,78,12,16,5,16,114,10,0,0,0,
     99,1,0,0,0,0,0,0,0,0,0,0,0,4,0,0,
     0,3,0,0,0,115,28,0,0,0,124,0,160,0,100,1,
@@ -1402,7 +1402,7 @@ const unsigned char _Py_M__zipimport[] = {
     25,23,32,33,34,23,35,13,20,20,24,26,35,37,44,20,
     44,13,44,13,44,13,44,12,24,9,83,19,56,42,54,19,
     56,19,56,13,16,19,33,34,37,44,52,19,53,19,53,59,
-    71,13,71,19,33,34,67,35,43,34,67,34,67,74,82,19,
+    71,13,71,19,33,34,67,55,63,34,67,34,67,74,82,19,
     83,19,83,13,83,115,35,0,0,0,158,5,36,2,164,7,
     46,9,173,1,46,9,190,8,65,7,2,193,7,7,65,26,
     9,193,14,2,65,21,9,193,21,5,65,26,9,41,46,114,



More information about the Python-checkins mailing list