| 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). | 
 |  | 
 | 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__ | 
 | import warnings | 
 |  | 
 | _features = [getattr(__future__, fname) | 
 |              for fname in __future__.all_feature_names] | 
 |  | 
 | __all__ = ["compile_command", "Compile", "CommandCompiler"] | 
 |  | 
 | # The following flags match the values from Include/cpython/compile.h | 
 | # Caveat emptor: These flags are undocumented on purpose and depending | 
 | # on their effect outside the standard library is **unsupported**. | 
 | PyCF_DONT_IMPLY_DEDENT = 0x200 | 
 | PyCF_ALLOW_INCOMPLETE_INPUT = 0x4000 | 
 |  | 
 | 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 | 
 |  | 
 |     # Disable compiler warnings when checking for incomplete input. | 
 |     with warnings.catch_warnings(): | 
 |         warnings.simplefilter("ignore", (SyntaxWarning, DeprecationWarning)) | 
 |         try: | 
 |             compiler(source, filename, symbol) | 
 |         except SyntaxError:  # Let other compile() errors propagate. | 
 |             try: | 
 |                 compiler(source + "\n", filename, symbol) | 
 |                 return None | 
 |             except SyntaxError as e: | 
 |                 if "incomplete input" in str(e): | 
 |                     return None | 
 |                 # fallthrough | 
 |  | 
 |     return compiler(source, filename, symbol) | 
 |  | 
 | def _compile(source, filename, symbol): | 
 |     return compile(source, filename, symbol, PyCF_DONT_IMPLY_DEDENT | PyCF_ALLOW_INCOMPLETE_INPUT) | 
 |  | 
 | 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), "exec" | 
 |               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 | PyCF_ALLOW_INCOMPLETE_INPUT | 
 |  | 
 |     def __call__(self, source, filename, symbol): | 
 |         codeob = compile(source, filename, symbol, self.flags, True) | 
 |         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) |