bpo-46521: Fix codeop to use a new partial-input mode of the parser (… · python/cpython@69e1097

GitHub

@@ -10,30 +10,6 @@

1010 syntax error (OverflowError and ValueError can be produced by

1111 malformed literals).

121213-Approach:

14-15-First, check if the source consists entirely of blank lines and

16-comments; if so, replace it with 'pass', because the built-in

17-parser doesn't always do the right thing for these.

18-19-Compile three times: as is, with \n, and with \n\n appended. If it

20-compiles as is, it's complete. If it compiles with one \n appended,

21-we expect more. If it doesn't compile either way, we compare the

22-error we get when compiling with \n or \n\n appended. If the errors

23-are the same, the code is broken. But if the errors are different, we

24-expect more. Not intuitive; not even guaranteed to hold in future

25-releases; but this matches the compiler's behavior from Python 1.4

26-through 2.2, at least.

27-28-Caveat:

29-30-It is possible (but not likely) that the parser stops parsing with a

31-successful outcome before reaching the end of the source; in this

32-case, trailing symbols may be ignored instead of causing an error.

33-For example, a backslash followed by two newlines may be followed by

34-arbitrary garbage. This will be fixed once the API for the parser is

35-better.

36-3713The two interfaces are:

38143915compile_command(source, filename, symbol):

@@ -64,7 +40,11 @@

64406541__all__= ["compile_command", "Compile", "CommandCompiler"]

664267-PyCF_DONT_IMPLY_DEDENT=0x200# Matches pythonrun.h.

43+# The following flags match the values from Include/cpython/compile.h

44+# Caveat emptor: These flags are undocumented on purpose and depending

45+# on their effect outside the standard library is **unsupported**.

46+PyCF_DONT_IMPLY_DEDENT=0x200

47+PyCF_ALLOW_INCOMPLETE_INPUT=0x4000

68486949def_maybe_compile(compiler, source, filename, symbol):

7050# Check for source consisting of only blank lines and comments.

@@ -86,24 +66,12 @@ def _maybe_compile(compiler, source, filename, symbol):

8666withwarnings.catch_warnings():

8767warnings.simplefilter("error")

886889-code1=err1=err2=None

90-try:

91-code1=compiler(source+"\n", filename, symbol)

92-exceptSyntaxErrorase:

93-err1=e

94-9569try:

96-code2=compiler(source+"\n\n", filename, symbol)

70+compiler(source+"\n", filename, symbol)

9771exceptSyntaxErrorase:

98-err2=e

99-100-try:

101-ifnotcode1and_is_syntax_error(err1, err2):

102-raiseerr1

103-else:

104-returnNone

105-finally:

106-err1=err2=None

72+if"incomplete input"instr(e):

73+returnNone

74+raise

1077510876def_is_syntax_error(err1, err2):

10977rep1=repr(err1)

@@ -115,7 +83,7 @@ def _is_syntax_error(err1, err2):

11583returnFalse

1168411785def_compile(source, filename, symbol):

118-returncompile(source, filename, symbol, PyCF_DONT_IMPLY_DEDENT)

86+returncompile(source, filename, symbol, PyCF_DONT_IMPLY_DEDENT|PyCF_ALLOW_INCOMPLETE_INPUT)

1198712088defcompile_command(source, filename="<input>", symbol="single"):

12189r"""Compile a command and determine whether it is incomplete.

@@ -144,7 +112,7 @@ class Compile:

144112 statement, it "remembers" and compiles all subsequent program texts

145113 with the statement in force."""

146114def__init__(self):

147-self.flags=PyCF_DONT_IMPLY_DEDENT

115+self.flags=PyCF_DONT_IMPLY_DEDENT|PyCF_ALLOW_INCOMPLETE_INPUT

148116149117def__call__(self, source, filename, symbol):

150118codeob=compile(source, filename, symbol, self.flags, True)