Skip to content

Commit 5b013d9

Browse files
committed
initial fix
1 parent a46ed66 commit 5b013d9

File tree

8 files changed

+107
-11
lines changed

8 files changed

+107
-11
lines changed

Include/internal/pycore_global_objects_fini_generated.h

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_global_strings.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,7 @@ struct _Py_global_strings {
441441
STRUCT_FOR_ID(fd)
442442
STRUCT_FOR_ID(fd2)
443443
STRUCT_FOR_ID(fdel)
444+
STRUCT_FOR_ID(feature_version)
444445
STRUCT_FOR_ID(fget)
445446
STRUCT_FOR_ID(fields)
446447
STRUCT_FOR_ID(file)

Include/internal/pycore_runtime_init_generated.h

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_unicodeobject_generated.h

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/_pyrepl/console.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,12 @@
2020
from __future__ import annotations
2121

2222
import _colorize
23+
import _symtable
2324

2425
from abc import ABC, abstractmethod
2526
import ast
2627
import code
28+
import codeop
2729
import linecache
2830
from dataclasses import dataclass, field
2931
import os.path
@@ -211,6 +213,17 @@ def runsource(self, source, filename="<input>", symbol="single"):
211213
except (OverflowError, ValueError):
212214
self.showsyntaxerror(filename, source=source)
213215
return False
216+
217+
try:
218+
# validate stuff that cannot be validated with AST parsing only
219+
flags = self.compile.compiler.flags
220+
flags &= ~codeop.PyCF_DONT_IMPLY_DEDENT
221+
flags &= ~codeop.PyCF_ALLOW_INCOMPLETE_INPUT
222+
_symtable.symtable(source, filename, "exec", flags=flags)
223+
except (SyntaxError, OverflowError, ValueError):
224+
self.showsyntaxerror(filename, source=source)
225+
return False
226+
214227
if tree.body:
215228
*_, last_stmt = tree.body
216229
for stmt in tree.body:

Lib/test/test_pyrepl/test_interact.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,15 @@ def test_runsource_shows_syntax_error_for_failed_compilation(self):
131131
console.runsource(source)
132132
mock_showsyntaxerror.assert_called_once()
133133

134+
def test_runsource_shows_syntax_error_for_failed_symtable_checks(self):
135+
# Some checks cannot be performed by AST parsing only.
136+
# See https://github.com/python/cpython/issues/137376.
137+
console = InteractiveColoredConsole()
138+
source = "x = 1; global x; x = 2"
139+
with patch.object(console, "showsyntaxerror") as mock_showsyntaxerror:
140+
console.runsource(source)
141+
mock_showsyntaxerror.assert_called_once()
142+
134143
def test_runsource_survives_null_bytes(self):
135144
console = InteractiveColoredConsole()
136145
source = "\x00\n"

Modules/clinic/symtablemodule.c.h

Lines changed: 64 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/symtablemodule.c

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,33 @@ _symtable.symtable
1616
filename: object(converter='PyUnicode_FSDecoder')
1717
startstr: str
1818
/
19+
*
20+
flags: int = 0
21+
feature_version: int = 0
1922
2023
Return symbol and scope dictionaries used internally by compiler.
2124
[clinic start generated code]*/
2225

2326
static PyObject *
2427
_symtable_symtable_impl(PyObject *module, PyObject *source,
25-
PyObject *filename, const char *startstr)
26-
/*[clinic end generated code: output=59eb0d5fc7285ac4 input=9dd8a50c0c36a4d7]*/
28+
PyObject *filename, const char *startstr, int flags,
29+
int feature_version)
30+
/*[clinic end generated code: output=1e766ac3387e156a input=5ccfb94e8a19a975]*/
2731
{
2832
struct symtable *st;
2933
PyObject *t;
3034
int start;
3135
PyCompilerFlags cf = _PyCompilerFlags_INIT;
3236
PyObject *source_copy = NULL;
3337

34-
cf.cf_flags = PyCF_SOURCE_IS_UTF8;
38+
cf.cf_flags = flags | PyCF_SOURCE_IS_UTF8;
39+
if (feature_version >= 0 && (flags & PyCF_ONLY_AST)) {
40+
cf.cf_feature_version = feature_version;
41+
}
42+
if (flags & ~(PyCF_MASK | PyCF_MASK_OBSOLETE | PyCF_COMPILE_MASK)) {
43+
PyErr_SetString(PyExc_ValueError, "_symtable.symtable(): unrecognised flags");
44+
return NULL;
45+
}
3546

3647
const char *str = _Py_SourceAsString(source, "symtable", "string or bytes", &cf, &source_copy);
3748
if (str == NULL) {

0 commit comments

Comments
 (0)