summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorTim Peters <tim.peters@gmail.com>2001-08-17 22:11:27 (GMT)
committerTim Peters <tim.peters@gmail.com>2001-08-17 22:11:27 (GMT)
commit6cd6a82db93fa37a13d0b5312ce6510c4d6967de (patch)
treec43eca432a18a364fb1c004d4dfcfe904fa7cefd /Lib
parent10d72552495a1967af7174f6ed52eb3340799c76 (diff)
downloadcpython-6cd6a82db93fa37a13d0b5312ce6510c4d6967de.zip
cpython-6cd6a82db93fa37a13d0b5312ce6510c4d6967de.tar.gz
cpython-6cd6a82db93fa37a13d0b5312ce6510c4d6967de.tar.bz2
A fiddled version of the rest of Michael Hudson's SF patch
#449043 supporting __future__ in simulated shells which implements PEP 264.
Diffstat (limited to 'Lib')
-rw-r--r--Lib/code.py7
-rw-r--r--Lib/codeop.py158
2 files changed, 126 insertions, 39 deletions
diff --git a/Lib/code.py b/Lib/code.py
index d56681c..e2d5065 100644
--- a/Lib/code.py
+++ b/Lib/code.py
@@ -7,9 +7,9 @@
import sys
import traceback
-from codeop import compile_command
+from codeop import CommandCompiler, compile_command
-__all__ = ["InteractiveInterpreter","InteractiveConsole","interact",
+__all__ = ["InteractiveInterpreter", "InteractiveConsole", "interact",
"compile_command"]
def softspace(file, newvalue):
@@ -45,6 +45,7 @@ class InteractiveInterpreter:
if locals is None:
locals = {"__name__": "__console__", "__doc__": None}
self.locals = locals
+ self.compile = CommandCompiler()
def runsource(self, source, filename="<input>", symbol="single"):
"""Compile and run some source in the interpreter.
@@ -71,7 +72,7 @@ class InteractiveInterpreter:
"""
try:
- code = compile_command(source, filename, symbol)
+ code = self.compile(source, filename, symbol)
except (OverflowError, SyntaxError, ValueError):
# Case 1
self.showsyntaxerror(filename)
diff --git a/Lib/codeop.py b/Lib/codeop.py
index 3335f09..c97b4df 100644
--- a/Lib/codeop.py
+++ b/Lib/codeop.py
@@ -1,49 +1,69 @@
-"""Utility to compile possibly incomplete Python source code."""
+r"""Utilities to compile possibly incomplete Python source code.
-__all__ = ["compile_command"]
+This module provides two interfaces, broadly similar to the builtin
+function compile(), that take progam text, a filename and a 'mode'
+and:
-def compile_command(source, filename="<input>", symbol="single"):
- r"""Compile a command and determine whether it is incomplete.
+- Return a code object if the command is complete and valid
+- Return None if the command is incomplete
+- Raise SyntaxError, ValueError or OverflowError if the command is a
+ syntax error (OverflowError and ValueError can be produced by
+ malformed literals).
- Arguments:
+Approach:
- source -- the source string; may contain \n characters
- filename -- optional filename from which source was read; default "<input>"
- symbol -- optional grammar start symbol; "single" (default) or "eval"
+First, check if the source consists entirely of blank lines and
+comments; if so, replace it with 'pass', because the built-in
+parser doesn't always do the right thing for these.
- Return value / exceptions raised:
+Compile three times: as is, with \n, and with \n\n appended. If it
+compiles as is, it's complete. If it compiles with one \n appended,
+we expect more. If it doesn't compile either way, we compare the
+error we get when compiling with \n or \n\n appended. If the errors
+are the same, the code is broken. But if the errors are different, we
+expect more. Not intuitive; not even guaranteed to hold in future
+releases; but this matches the compiler's behavior from Python 1.4
+through 2.2, at least.
- - Return a code object if the command is complete and valid
- - Return None if the command is incomplete
- - Raise SyntaxError or OverflowError if the command is a syntax error
- (OverflowError if the error is in a numeric constant)
+Caveat:
- Approach:
+It is possible (but not likely) that the parser stops parsing with a
+successful outcome before reaching the end of the source; in this
+case, trailing symbols may be ignored instead of causing an error.
+For example, a backslash followed by two newlines may be followed by
+arbitrary garbage. This will be fixed once the API for the parser is
+better.
- First, check if the source consists entirely of blank lines and
- comments; if so, replace it with 'pass', because the built-in
- parser doesn't always do the right thing for these.
+The two interfaces are:
- Compile three times: as is, with \n, and with \n\n appended. If
- it compiles as is, it's complete. If it compiles with one \n
- appended, we expect more. If it doesn't compile either way, we
- compare the error we get when compiling with \n or \n\n appended.
- If the errors are the same, the code is broken. But if the errors
- are different, we expect more. Not intuitive; not even guaranteed
- to hold in future releases; but this matches the compiler's
- behavior from Python 1.4 through 1.5.2, at least.
+compile_command(source, filename, symbol):
- Caveat:
+ Compiles a single command in the manner described above.
- It is possible (but not likely) that the parser stops parsing
- with a successful outcome before reaching the end of the source;
- in this case, trailing symbols may be ignored instead of causing an
- error. For example, a backslash followed by two newlines may be
- followed by arbitrary garbage. This will be fixed once the API
- for the parser is better.
+CommandCompiler():
- """
+ Instances of this class have __call__ methods identical in
+ signature to compile_command; the difference is that if the
+ instance compiles program text containing a __future__ statement,
+ the instance 'remembers' and compiles all subsequent program texts
+ with the statement in force.
+
+The module also provides another class:
+
+Compile():
+
+ Instances of this class act like the built-in function compile,
+ but with 'memory' in the sense described above.
+"""
+
+import __future__
+
+_features = [getattr(__future__, fname)
+ for fname in __future__.all_feature_names]
+
+__all__ = ["compile_command", "Compile", "CommandCompiler"]
+def _maybe_compile(compiler, source, filename, symbol):
# Check for source consisting of only blank lines and comments
for line in source.split("\n"):
line = line.strip()
@@ -56,17 +76,17 @@ def compile_command(source, filename="<input>", symbol="single"):
code = code1 = code2 = None
try:
- code = compile(source, filename, symbol)
+ code = compiler(source, filename, symbol)
except SyntaxError, err:
pass
try:
- code1 = compile(source + "\n", filename, symbol)
+ code1 = compiler(source + "\n", filename, symbol)
except SyntaxError, err1:
pass
try:
- code2 = compile(source + "\n\n", filename, symbol)
+ code2 = compiler(source + "\n\n", filename, symbol)
except SyntaxError, err2:
pass
@@ -82,3 +102,69 @@ def compile_command(source, filename="<input>", symbol="single"):
e2 = err2
if not code1 and e1 == e2:
raise SyntaxError, err1
+
+def compile_command(source, filename="<input>", symbol="single"):
+ r"""Compile a command and determine whether it is incomplete.
+
+ Arguments:
+
+ source -- the source string; may contain \n characters
+ filename -- optional filename from which source was read; default
+ "<input>"
+ symbol -- optional grammar start symbol; "single" (default) or "eval"
+
+ Return value / exceptions raised:
+
+ - Return a code object if the command is complete and valid
+ - Return None if the command is incomplete
+ - Raise SyntaxError, ValueError or OverflowError if the command is a
+ syntax error (OverflowError and ValueError can be produced by
+ malformed literals).
+ """
+ return _maybe_compile(compile, source, filename, symbol)
+
+class Compile:
+ """Instances of this class behave much like the built-in compile
+ function, but if one is used to compile text containing a future
+ statement, it "remembers" and compiles all subsequent program texts
+ with the statement in force."""
+ def __init__(self):
+ self.flags = 0
+
+ def __call__(self, source, filename, symbol):
+ codeob = compile(source, filename, symbol, self.flags, 1)
+ for feature in _features:
+ if codeob.co_flags & feature.compiler_flag:
+ self.flags |= feature.compiler_flag
+ return codeob
+
+class CommandCompiler:
+ """Instances of this class have __call__ methods identical in
+ signature to compile_command; the difference is that if the
+ instance compiles program text containing a __future__ statement,
+ the instance 'remembers' and compiles all subsequent program texts
+ with the statement in force."""
+
+ def __init__(self,):
+ self.compiler = Compile()
+
+ def __call__(self, source, filename="<input>", symbol="single"):
+ r"""Compile a command and determine whether it is incomplete.
+
+ Arguments:
+
+ source -- the source string; may contain \n characters
+ filename -- optional filename from which source was read;
+ default "<input>"
+ symbol -- optional grammar start symbol; "single" (default) or
+ "eval"
+
+ Return value / exceptions raised:
+
+ - Return a code object if the command is complete and valid
+ - Return None if the command is incomplete
+ - Raise SyntaxError, ValueError or OverflowError if the command is a
+ syntax error (OverflowError and ValueError can be produced by
+ malformed literals).
+ """
+ return _maybe_compile(self.compiler, source, filename, symbol)