]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-35975: Only use cf_feature_version if PyCF_ONLY_AST in cf_flags (#21021)
authorGuido van Rossum <guido@python.org>
Sun, 28 Jun 2020 00:33:49 +0000 (17:33 -0700)
committerGitHub <noreply@github.com>
Sun, 28 Jun 2020 00:33:49 +0000 (17:33 -0700)
Lib/test/test_capi.py
Misc/NEWS.d/next/Core and Builtins/2020-06-20-17-00-44.bpo-35975.UDHCHp.rst [new file with mode: 0644]
Modules/_testcapimodule.c
Parser/pegen.c

index 73e167a0b05a53310e4ea04940ed2980fadfcf56..fa5ca1c97f458328d1b3eee21514d57035ca678e 100644 (file)
@@ -627,6 +627,27 @@ class SubinterpreterTest(unittest.TestCase):
             self.assertNotEqual(pickle.load(f), id(sys.modules))
             self.assertNotEqual(pickle.load(f), id(builtins))
 
+    def test_subinterps_recent_language_features(self):
+        r, w = os.pipe()
+        code = """if 1:
+            import pickle
+            with open({:d}, "wb") as f:
+
+                @(lambda x:x)  # Py 3.9
+                def noop(x): return x
+
+                a = (b := f'1{{2}}3') + noop('x')  # Py 3.8 (:=) / 3.6 (f'')
+
+                async def foo(arg): return await arg  # Py 3.5
+
+                pickle.dump(dict(a=a, b=b), f)
+            """.format(w)
+
+        with open(r, "rb") as f:
+            ret = support.run_in_subinterp(code)
+            self.assertEqual(ret, 0)
+            self.assertEqual(pickle.load(f), {'a': '123x', 'b': '123'})
+
     def test_mutate_exception(self):
         """
         Exceptions saved in global module state get shared between
diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-06-20-17-00-44.bpo-35975.UDHCHp.rst b/Misc/NEWS.d/next/Core and Builtins/2020-06-20-17-00-44.bpo-35975.UDHCHp.rst
new file mode 100644 (file)
index 0000000..73f4a6d
--- /dev/null
@@ -0,0 +1,3 @@
+Stefan Behnel reported that cf_feature_version is used even when
+PyCF_ONLY_AST is not set. This is against the intention and against the
+documented behavior, so it's been fixed.
index adc5877c48a24480354bb1be8d37b4e24108e9d0..aafbc392a4846d13e52dab071346f0111474a711 100644 (file)
@@ -3468,6 +3468,8 @@ run_in_subinterp(PyObject *self, PyObject *args)
     const char *code;
     int r;
     PyThreadState *substate, *mainstate;
+    /* only initialise 'cflags.cf_flags' to test backwards compatibility */
+    PyCompilerFlags cflags = {0};
 
     if (!PyArg_ParseTuple(args, "s:run_in_subinterp",
                           &code))
@@ -3486,7 +3488,7 @@ run_in_subinterp(PyObject *self, PyObject *args)
         PyErr_SetString(PyExc_RuntimeError, "sub-interpreter creation failed");
         return NULL;
     }
-    r = PyRun_SimpleString(code);
+    r = PyRun_SimpleStringFlags(code, &cflags);
     Py_EndInterpreter(substate);
 
     PyThreadState_Swap(mainstate);
index 19762b06d3caf2347a0e6021e1d153f3ee6331a5..53e3d4913830689099af2153466e884f328dc9c7 100644 (file)
@@ -1042,7 +1042,7 @@ compute_parser_flags(PyCompilerFlags *flags)
     if (flags->cf_flags & PyCF_TYPE_COMMENTS) {
         parser_flags |= PyPARSE_TYPE_COMMENTS;
     }
-    if (flags->cf_feature_version < 7) {
+    if ((flags->cf_flags & PyCF_ONLY_AST) && flags->cf_feature_version < 7) {
         parser_flags |= PyPARSE_ASYNC_HACKS;
     }
     return parser_flags;
@@ -1215,7 +1215,8 @@ _PyPegen_run_parser_from_string(const char *str, int start_rule, PyObject *filen
     mod_ty result = NULL;
 
     int parser_flags = compute_parser_flags(flags);
-    int feature_version = flags ? flags->cf_feature_version : PY_MINOR_VERSION;
+    int feature_version = flags && (flags->cf_flags & PyCF_ONLY_AST) ?
+        flags->cf_feature_version : PY_MINOR_VERSION;
     Parser *p = _PyPegen_Parser_New(tok, start_rule, parser_flags, feature_version,
                                     NULL, arena);
     if (p == NULL) {