mirror of https://github.com/python/cpython.git
gh-124960: Fixed `barry_as_FLUFL` future flag does not work in new REPL (#124999)
Co-authored-by: Wulian <xiguawulian@gmail.com>
Co-authored-by: Nice Zombies <nineteendo19d0@gmail.com>
Co-authored-by: Łukasz Langa <lukasz@langa.pl>
(cherry picked from commit 6a08a753b7
)
This commit is contained in:
parent
cbcdf34a4b
commit
d54dbd62cc
|
@ -174,7 +174,13 @@ def _excepthook(self, typ, value, tb):
|
||||||
|
|
||||||
def runsource(self, source, filename="<input>", symbol="single"):
|
def runsource(self, source, filename="<input>", symbol="single"):
|
||||||
try:
|
try:
|
||||||
tree = ast.parse(source)
|
tree = self.compile.compiler(
|
||||||
|
source,
|
||||||
|
filename,
|
||||||
|
"exec",
|
||||||
|
ast.PyCF_ONLY_AST,
|
||||||
|
incomplete_input=False,
|
||||||
|
)
|
||||||
except (SyntaxError, OverflowError, ValueError):
|
except (SyntaxError, OverflowError, ValueError):
|
||||||
self.showsyntaxerror(filename, source=source)
|
self.showsyntaxerror(filename, source=source)
|
||||||
return False
|
return False
|
||||||
|
@ -185,7 +191,7 @@ def runsource(self, source, filename="<input>", symbol="single"):
|
||||||
the_symbol = symbol if stmt is last_stmt else "exec"
|
the_symbol = symbol if stmt is last_stmt else "exec"
|
||||||
item = wrapper([stmt])
|
item = wrapper([stmt])
|
||||||
try:
|
try:
|
||||||
code = self.compile.compiler(item, filename, the_symbol, dont_inherit=True)
|
code = self.compile.compiler(item, filename, the_symbol)
|
||||||
except SyntaxError as e:
|
except SyntaxError as e:
|
||||||
if e.args[0] == "'await' outside function":
|
if e.args[0] == "'await' outside function":
|
||||||
python = os.path.basename(sys.executable)
|
python = os.path.basename(sys.executable)
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
# Caveat emptor: These flags are undocumented on purpose and depending
|
# Caveat emptor: These flags are undocumented on purpose and depending
|
||||||
# on their effect outside the standard library is **unsupported**.
|
# on their effect outside the standard library is **unsupported**.
|
||||||
PyCF_DONT_IMPLY_DEDENT = 0x200
|
PyCF_DONT_IMPLY_DEDENT = 0x200
|
||||||
|
PyCF_ONLY_AST = 0x400
|
||||||
PyCF_ALLOW_INCOMPLETE_INPUT = 0x4000
|
PyCF_ALLOW_INCOMPLETE_INPUT = 0x4000
|
||||||
|
|
||||||
def _maybe_compile(compiler, source, filename, symbol):
|
def _maybe_compile(compiler, source, filename, symbol):
|
||||||
|
@ -109,12 +110,14 @@ class Compile:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.flags = PyCF_DONT_IMPLY_DEDENT | PyCF_ALLOW_INCOMPLETE_INPUT
|
self.flags = PyCF_DONT_IMPLY_DEDENT | PyCF_ALLOW_INCOMPLETE_INPUT
|
||||||
|
|
||||||
def __call__(self, source, filename, symbol, **kwargs):
|
def __call__(self, source, filename, symbol, flags=0, **kwargs):
|
||||||
flags = self.flags
|
flags |= self.flags
|
||||||
if kwargs.get('incomplete_input', True) is False:
|
if kwargs.get('incomplete_input', True) is False:
|
||||||
flags &= ~PyCF_DONT_IMPLY_DEDENT
|
flags &= ~PyCF_DONT_IMPLY_DEDENT
|
||||||
flags &= ~PyCF_ALLOW_INCOMPLETE_INPUT
|
flags &= ~PyCF_ALLOW_INCOMPLETE_INPUT
|
||||||
codeob = compile(source, filename, symbol, flags, True)
|
codeob = compile(source, filename, symbol, flags, True)
|
||||||
|
if flags & PyCF_ONLY_AST:
|
||||||
|
return codeob # this is an ast.Module in this case
|
||||||
for feature in _features:
|
for feature in _features:
|
||||||
if codeob.co_flags & feature.compiler_flag:
|
if codeob.co_flags & feature.compiler_flag:
|
||||||
self.flags |= feature.compiler_flag
|
self.flags |= feature.compiler_flag
|
||||||
|
|
|
@ -119,13 +119,38 @@ def test_runsource_shows_syntax_error_for_failed_compilation(self):
|
||||||
|
|
||||||
def test_no_active_future(self):
|
def test_no_active_future(self):
|
||||||
console = InteractiveColoredConsole()
|
console = InteractiveColoredConsole()
|
||||||
source = "x: int = 1; print(__annotations__)"
|
source = dedent("""\
|
||||||
|
x: int = 1
|
||||||
|
print(__annotations__)
|
||||||
|
""")
|
||||||
f = io.StringIO()
|
f = io.StringIO()
|
||||||
with contextlib.redirect_stdout(f):
|
with contextlib.redirect_stdout(f):
|
||||||
result = console.runsource(source)
|
result = console.runsource(source)
|
||||||
self.assertFalse(result)
|
self.assertFalse(result)
|
||||||
self.assertEqual(f.getvalue(), "{'x': <class 'int'>}\n")
|
self.assertEqual(f.getvalue(), "{'x': <class 'int'>}\n")
|
||||||
|
|
||||||
|
def test_future_annotations(self):
|
||||||
|
console = InteractiveColoredConsole()
|
||||||
|
source = dedent("""\
|
||||||
|
from __future__ import annotations
|
||||||
|
def g(x: int): ...
|
||||||
|
print(g.__annotations__)
|
||||||
|
""")
|
||||||
|
f = io.StringIO()
|
||||||
|
with contextlib.redirect_stdout(f):
|
||||||
|
result = console.runsource(source)
|
||||||
|
self.assertFalse(result)
|
||||||
|
self.assertEqual(f.getvalue(), "{'x': 'int'}\n")
|
||||||
|
|
||||||
|
def test_future_barry_as_flufl(self):
|
||||||
|
console = InteractiveColoredConsole()
|
||||||
|
f = io.StringIO()
|
||||||
|
with contextlib.redirect_stdout(f):
|
||||||
|
result = console.runsource("from __future__ import barry_as_FLUFL\n")
|
||||||
|
result = console.runsource("""print("black" <> 'blue')\n""")
|
||||||
|
self.assertFalse(result)
|
||||||
|
self.assertEqual(f.getvalue(), "True\n")
|
||||||
|
|
||||||
|
|
||||||
class TestMoreLines(unittest.TestCase):
|
class TestMoreLines(unittest.TestCase):
|
||||||
def test_invalid_syntax_single_line(self):
|
def test_invalid_syntax_single_line(self):
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Fix support for the ``barry_as_FLUFL`` future flag in the new REPL.
|
Loading…
Reference in New Issue