Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6cd6a82

Browse files
committed
A fiddled version of the rest of Michael Hudson's SF patch
#449043 supporting __future__ in simulated shells which implements PEP 264.
1 parent 10d7255 commit 6cd6a82

4 files changed

Lines changed: 157 additions & 47 deletions

File tree

Lib/code.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77

88
import sys
99
import traceback
10-
from codeop import compile_command
10+
from codeop import CommandCompiler, compile_command
1111

12-
__all__ = ["InteractiveInterpreter","InteractiveConsole","interact",
12+
__all__ = ["InteractiveInterpreter", "InteractiveConsole", "interact",
1313
"compile_command"]
1414

1515
def softspace(file, newvalue):
@@ -45,6 +45,7 @@ def __init__(self, locals=None):
4545
if locals is None:
4646
locals = {"__name__": "__console__", "__doc__": None}
4747
self.locals = locals
48+
self.compile = CommandCompiler()
4849

4950
def runsource(self, source, filename="<input>", symbol="single"):
5051
"""Compile and run some source in the interpreter.
@@ -71,7 +72,7 @@ def runsource(self, source, filename="<input>", symbol="single"):
7172
7273
"""
7374
try:
74-
code = compile_command(source, filename, symbol)
75+
code = self.compile(source, filename, symbol)
7576
except (OverflowError, SyntaxError, ValueError):
7677
# Case 1
7778
self.showsyntaxerror(filename)

Lib/codeop.py

Lines changed: 122 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,69 @@
1-
"""Utility to compile possibly incomplete Python source code."""
1+
r"""Utilities to compile possibly incomplete Python source code.
22
3-
__all__ = ["compile_command"]
3+
This module provides two interfaces, broadly similar to the builtin
4+
function compile(), that take progam text, a filename and a 'mode'
5+
and:
46
5-
def compile_command(source, filename="<input>", symbol="single"):
6-
r"""Compile a command and determine whether it is incomplete.
7+
- Return a code object if the command is complete and valid
8+
- Return None if the command is incomplete
9+
- Raise SyntaxError, ValueError or OverflowError if the command is a
10+
syntax error (OverflowError and ValueError can be produced by
11+
malformed literals).
712
8-
Arguments:
13+
Approach:
914
10-
source -- the source string; may contain \n characters
11-
filename -- optional filename from which source was read; default "<input>"
12-
symbol -- optional grammar start symbol; "single" (default) or "eval"
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.
1318
14-
Return value / exceptions raised:
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.
1527
16-
- Return a code object if the command is complete and valid
17-
- Return None if the command is incomplete
18-
- Raise SyntaxError or OverflowError if the command is a syntax error
19-
(OverflowError if the error is in a numeric constant)
28+
Caveat:
2029
21-
Approach:
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.
2236
23-
First, check if the source consists entirely of blank lines and
24-
comments; if so, replace it with 'pass', because the built-in
25-
parser doesn't always do the right thing for these.
37+
The two interfaces are:
2638
27-
Compile three times: as is, with \n, and with \n\n appended. If
28-
it compiles as is, it's complete. If it compiles with one \n
29-
appended, we expect more. If it doesn't compile either way, we
30-
compare the error we get when compiling with \n or \n\n appended.
31-
If the errors are the same, the code is broken. But if the errors
32-
are different, we expect more. Not intuitive; not even guaranteed
33-
to hold in future releases; but this matches the compiler's
34-
behavior from Python 1.4 through 1.5.2, at least.
39+
compile_command(source, filename, symbol):
3540
36-
Caveat:
41+
Compiles a single command in the manner described above.
3742
38-
It is possible (but not likely) that the parser stops parsing
39-
with a successful outcome before reaching the end of the source;
40-
in this case, trailing symbols may be ignored instead of causing an
41-
error. For example, a backslash followed by two newlines may be
42-
followed by arbitrary garbage. This will be fixed once the API
43-
for the parser is better.
43+
CommandCompiler():
4444
45-
"""
45+
Instances of this class have __call__ methods identical in
46+
signature to compile_command; the difference is that if the
47+
instance compiles program text containing a __future__ statement,
48+
the instance 'remembers' and compiles all subsequent program texts
49+
with the statement in force.
50+
51+
The module also provides another class:
52+
53+
Compile():
54+
55+
Instances of this class act like the built-in function compile,
56+
but with 'memory' in the sense described above.
57+
"""
58+
59+
import __future__
60+
61+
_features = [getattr(__future__, fname)
62+
for fname in __future__.all_feature_names]
63+
64+
__all__ = ["compile_command", "Compile", "CommandCompiler"]
4665

66+
def _maybe_compile(compiler, source, filename, symbol):
4767
# Check for source consisting of only blank lines and comments
4868
for line in source.split("\n"):
4969
line = line.strip()
@@ -56,17 +76,17 @@ def compile_command(source, filename="<input>", symbol="single"):
5676
code = code1 = code2 = None
5777

5878
try:
59-
code = compile(source, filename, symbol)
79+
code = compiler(source, filename, symbol)
6080
except SyntaxError, err:
6181
pass
6282

6383
try:
64-
code1 = compile(source + "\n", filename, symbol)
84+
code1 = compiler(source + "\n", filename, symbol)
6585
except SyntaxError, err1:
6686
pass
6787

6888
try:
69-
code2 = compile(source + "\n\n", filename, symbol)
89+
code2 = compiler(source + "\n\n", filename, symbol)
7090
except SyntaxError, err2:
7191
pass
7292

@@ -82,3 +102,69 @@ def compile_command(source, filename="<input>", symbol="single"):
82102
e2 = err2
83103
if not code1 and e1 == e2:
84104
raise SyntaxError, err1
105+
106+
def compile_command(source, filename="<input>", symbol="single"):
107+
r"""Compile a command and determine whether it is incomplete.
108+
109+
Arguments:
110+
111+
source -- the source string; may contain \n characters
112+
filename -- optional filename from which source was read; default
113+
"<input>"
114+
symbol -- optional grammar start symbol; "single" (default) or "eval"
115+
116+
Return value / exceptions raised:
117+
118+
- Return a code object if the command is complete and valid
119+
- Return None if the command is incomplete
120+
- Raise SyntaxError, ValueError or OverflowError if the command is a
121+
syntax error (OverflowError and ValueError can be produced by
122+
malformed literals).
123+
"""
124+
return _maybe_compile(compile, source, filename, symbol)
125+
126+
class Compile:
127+
"""Instances of this class behave much like the built-in compile
128+
function, but if one is used to compile text containing a future
129+
statement, it "remembers" and compiles all subsequent program texts
130+
with the statement in force."""
131+
def __init__(self):
132+
self.flags = 0
133+
134+
def __call__(self, source, filename, symbol):
135+
codeob = compile(source, filename, symbol, self.flags, 1)
136+
for feature in _features:
137+
if codeob.co_flags & feature.compiler_flag:
138+
self.flags |= feature.compiler_flag
139+
return codeob
140+
141+
class CommandCompiler:
142+
"""Instances of this class have __call__ methods identical in
143+
signature to compile_command; the difference is that if the
144+
instance compiles program text containing a __future__ statement,
145+
the instance 'remembers' and compiles all subsequent program texts
146+
with the statement in force."""
147+
148+
def __init__(self,):
149+
self.compiler = Compile()
150+
151+
def __call__(self, source, filename="<input>", symbol="single"):
152+
r"""Compile a command and determine whether it is incomplete.
153+
154+
Arguments:
155+
156+
source -- the source string; may contain \n characters
157+
filename -- optional filename from which source was read;
158+
default "<input>"
159+
symbol -- optional grammar start symbol; "single" (default) or
160+
"eval"
161+
162+
Return value / exceptions raised:
163+
164+
- Return a code object if the command is complete and valid
165+
- Return None if the command is incomplete
166+
- Raise SyntaxError, ValueError or OverflowError if the command is a
167+
syntax error (OverflowError and ValueError can be produced by
168+
malformed literals).
169+
"""
170+
return _maybe_compile(self.compiler, source, filename, symbol)

Misc/NEWS

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ Tests
2323

2424
Core
2525

26+
- Future statements are now effective in simulated interactive shells
27+
(like IDLE). This should "just work" by magic, but read Michael
28+
Hudson's "Future statements in simulated shells" PEP 264 for full
29+
details: <http://python.sf.net/peps/pep-0264.html>.
30+
2631
- The type/class unification (PEP 252-253) was integrated into the
2732
trunk and is not so tentative any more (the exact specification of
2833
some features is still tentative). A lot of work has done on fixing

Python/bltinmodule.c

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -377,10 +377,14 @@ builtin_compile(PyObject *self, PyObject *args)
377377
char *filename;
378378
char *startstr;
379379
int start;
380+
int dont_inherit = 0;
381+
int supplied_flags = 0;
380382
PyCompilerFlags cf;
381383

382-
if (!PyArg_ParseTuple(args, "sss:compile", &str, &filename, &startstr))
384+
if (!PyArg_ParseTuple(args, "sss|ii:compile", &str, &filename,
385+
&startstr, &supplied_flags, &dont_inherit))
383386
return NULL;
387+
384388
if (strcmp(startstr, "exec") == 0)
385389
start = Py_file_input;
386390
else if (strcmp(startstr, "eval") == 0)
@@ -392,21 +396,35 @@ builtin_compile(PyObject *self, PyObject *args)
392396
"compile() arg 3 must be 'exec' or 'eval' or 'single'");
393397
return NULL;
394398
}
395-
cf.cf_flags = 0;
396-
if (PyEval_MergeCompilerFlags(&cf))
397-
return Py_CompileStringFlags(str, filename, start, &cf);
398-
else
399-
return Py_CompileString(str, filename, start);
399+
400+
if (supplied_flags & ~(PyCF_MASK | PyCF_MASK_OBSOLETE)) {
401+
PyErr_SetString(PyExc_ValueError,
402+
"compile(): unrecognised flags");
403+
return NULL;
404+
}
405+
/* XXX Warn if (supplied_flags & PyCF_MASK_OBSOLETE) != 0? */
406+
407+
cf.cf_flags = supplied_flags;
408+
if (!dont_inherit) {
409+
PyEval_MergeCompilerFlags(&cf);
410+
}
411+
return Py_CompileStringFlags(str, filename, start, &cf);
400412
}
401413

402414
static char compile_doc[] =
403-
"compile(source, filename, mode) -> code object\n\
415+
"compile(source, filename, mode[, flags[, dont_inherit]]) -> code object\n\
404416
\n\
405417
Compile the source string (a Python module, statement or expression)\n\
406418
into a code object that can be executed by the exec statement or eval().\n\
407419
The filename will be used for run-time error messages.\n\
408420
The mode must be 'exec' to compile a module, 'single' to compile a\n\
409-
single (interactive) statement, or 'eval' to compile an expression.";
421+
single (interactive) statement, or 'eval' to compile an expression.\n\
422+
The flags argument, if present, controls which future statements influence\n\
423+
the compilation of the code.\n\
424+
The dont_inherit argument, if non-zero, stops the compilation inheriting\n\
425+
the effects of any future statements in effect in the code calling\n\
426+
compile; if absent or zero these statements do influence the compilation,\n\
427+
in addition to any features explicitly specified.";
410428

411429

412430
static PyObject *

0 commit comments

Comments
 (0)