|  | r"""Utilities to compile possibly incomplete Python source code. | 
|  |  | 
|  | This module provides two interfaces, broadly similar to the builtin | 
|  | function compile(), which take program text, a filename and a 'mode' | 
|  | and: | 
|  |  | 
|  | - Return 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). | 
|  |  | 
|  | Approach: | 
|  |  | 
|  | 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. | 
|  |  | 
|  | 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. | 
|  |  | 
|  | Caveat: | 
|  |  | 
|  | 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. | 
|  |  | 
|  | The two interfaces are: | 
|  |  | 
|  | compile_command(source, filename, symbol): | 
|  |  | 
|  | Compiles a single command in the manner described above. | 
|  |  | 
|  | 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"] | 
|  |  | 
|  | PyCF_DONT_IMPLY_DEDENT = 0x200          # Matches pythonrun.h | 
|  |  | 
|  | 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() | 
|  | if line and line[0] != '#': | 
|  | break               # Leave it alone | 
|  | else: | 
|  | if symbol != "eval": | 
|  | source = "pass"     # Replace it with a 'pass' statement | 
|  |  | 
|  | err = err1 = err2 = None | 
|  | code = code1 = code2 = None | 
|  |  | 
|  | try: | 
|  | code = compiler(source, filename, symbol) | 
|  | except SyntaxError, err: | 
|  | pass | 
|  |  | 
|  | try: | 
|  | code1 = compiler(source + "\n", filename, symbol) | 
|  | except SyntaxError, err1: | 
|  | pass | 
|  |  | 
|  | try: | 
|  | code2 = compiler(source + "\n\n", filename, symbol) | 
|  | except SyntaxError, err2: | 
|  | pass | 
|  |  | 
|  | if code: | 
|  | return code | 
|  | if not code1 and repr(err1) == repr(err2): | 
|  | raise SyntaxError, err1 | 
|  |  | 
|  | def _compile(source, filename, symbol): | 
|  | return compile(source, filename, symbol, PyCF_DONT_IMPLY_DEDENT) | 
|  |  | 
|  | 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 = PyCF_DONT_IMPLY_DEDENT | 
|  |  | 
|  | 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) |