From 9d197c7d48147a9ea2f7f7be917f35514a16524b Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Sat, 27 Jun 2020 17:33:49 -0700 Subject: [PATCH] bpo-35975: Only use cf_feature_version if PyCF_ONLY_AST in cf_flags (#21021) --- Lib/test/test_capi.py | 21 +++++++++++++++++++ .../2020-06-20-17-00-44.bpo-35975.UDHCHp.rst | 3 +++ Modules/_testcapimodule.c | 4 +++- Parser/pegen.c | 5 +++-- 4 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-06-20-17-00-44.bpo-35975.UDHCHp.rst diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py index 73e167a0b05..fa5ca1c97f4 100644 --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -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 index 00000000000..73f4a6da2e5 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-06-20-17-00-44.bpo-35975.UDHCHp.rst @@ -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. diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index adc5877c48a..aafbc392a48 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -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); diff --git a/Parser/pegen.c b/Parser/pegen.c index 19762b06d3c..53e3d491383 100644 --- a/Parser/pegen.c +++ b/Parser/pegen.c @@ -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) {