| 
									
										
										
										
											2001-08-17 22:11:27 +00:00
										 |  |  | r"""Utilities to compile possibly incomplete Python source code.
 | 
					
						
							| 
									
										
										
										
											1998-10-22 21:56:15 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-08-17 22:11:27 +00:00
										 |  |  | This module provides two interfaces, broadly similar to the builtin | 
					
						
							| 
									
										
										
										
											2003-11-20 13:38:01 +00:00
										 |  |  | function compile(), which take program text, a filename and a 'mode' | 
					
						
							| 
									
										
										
										
											2001-08-17 22:11:27 +00:00
										 |  |  | and: | 
					
						
							| 
									
										
										
										
											2001-01-20 19:54:20 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-11-20 13:38:01 +00:00
										 |  |  | - 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 | 
					
						
							| 
									
										
										
										
											2001-08-17 22:11:27 +00:00
										 |  |  |   syntax error (OverflowError and ValueError can be produced by | 
					
						
							|  |  |  |   malformed literals). | 
					
						
							| 
									
										
										
										
											1998-10-22 21:56:15 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-08-17 22:11:27 +00:00
										 |  |  | The two interfaces are: | 
					
						
							| 
									
										
										
										
											1998-10-22 21:56:15 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-08-17 22:11:27 +00:00
										 |  |  | compile_command(source, filename, symbol): | 
					
						
							| 
									
										
										
										
											1998-10-22 21:56:15 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-08-17 22:11:27 +00:00
										 |  |  |     Compiles a single command in the manner described above. | 
					
						
							| 
									
										
										
										
											1998-10-22 21:56:15 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-08-17 22:11:27 +00:00
										 |  |  | CommandCompiler(): | 
					
						
							| 
									
										
										
										
											1998-10-22 21:56:15 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-08-17 22:11:27 +00:00
										 |  |  |     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__ | 
					
						
							| 
									
										
										
										
											2020-06-04 19:40:24 -04:00
										 |  |  | import warnings | 
					
						
							| 
									
										
										
										
											2001-08-17 22:11:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | _features = [getattr(__future__, fname) | 
					
						
							|  |  |  |              for fname in __future__.all_feature_names] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | __all__ = ["compile_command", "Compile", "CommandCompiler"] | 
					
						
							| 
									
										
										
										
											1998-10-22 21:56:15 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-08 11:54:37 +00:00
										 |  |  | # 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**. | 
					
						
							| 
									
										
										
										
											2022-03-05 17:47:00 +02:00
										 |  |  | PyCF_DONT_IMPLY_DEDENT = 0x200 | 
					
						
							| 
									
										
										
										
											2022-02-08 11:54:37 +00:00
										 |  |  | PyCF_ALLOW_INCOMPLETE_INPUT = 0x4000 | 
					
						
							| 
									
										
										
										
											2003-02-13 22:07:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-08-17 22:11:27 +00:00
										 |  |  | def _maybe_compile(compiler, source, filename, symbol): | 
					
						
							| 
									
										
										
										
											2021-02-13 01:49:18 -05:00
										 |  |  |     # Check for source consisting of only blank lines and comments. | 
					
						
							| 
									
										
										
										
											2001-02-09 08:56:30 +00:00
										 |  |  |     for line in source.split("\n"): | 
					
						
							|  |  |  |         line = line.strip() | 
					
						
							| 
									
										
										
										
											1998-10-22 21:56:15 +00:00
										 |  |  |         if line and line[0] != '#': | 
					
						
							| 
									
										
										
										
											2021-02-13 01:49:18 -05:00
										 |  |  |             break               # Leave it alone. | 
					
						
							| 
									
										
										
										
											1998-10-22 21:56:15 +00:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											2003-05-16 01:24:30 +00:00
										 |  |  |         if symbol != "eval": | 
					
						
							|  |  |  |             source = "pass"     # Replace it with a 'pass' statement | 
					
						
							| 
									
										
										
										
											1998-10-22 21:56:15 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-16 17:37:30 +03:00
										 |  |  |     # Disable compiler warnings when checking for incomplete input. | 
					
						
							| 
									
										
										
										
											2020-06-04 19:40:24 -04:00
										 |  |  |     with warnings.catch_warnings(): | 
					
						
							| 
									
										
										
										
											2022-09-16 17:37:30 +03:00
										 |  |  |         warnings.simplefilter("ignore", (SyntaxWarning, DeprecationWarning)) | 
					
						
							| 
									
										
										
										
											2020-06-04 19:40:24 -04:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2022-09-16 17:37:30 +03:00
										 |  |  |             compiler(source, filename, symbol) | 
					
						
							|  |  |  |         except SyntaxError:  # Let other compile() errors propagate. | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 compiler(source + "\n", filename, symbol) | 
					
						
							| 
									
										
										
										
											2022-02-08 11:54:37 +00:00
										 |  |  |                 return None | 
					
						
							| 
									
										
										
										
											2022-09-16 17:37:30 +03:00
										 |  |  |             except SyntaxError as e: | 
					
						
							|  |  |  |                 if "incomplete input" in str(e): | 
					
						
							|  |  |  |                     return None | 
					
						
							|  |  |  |                 # fallthrough | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return compiler(source, filename, symbol) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-08-17 22:11:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-09 20:07:38 +00:00
										 |  |  | def _is_syntax_error(err1, err2): | 
					
						
							|  |  |  |     rep1 = repr(err1) | 
					
						
							|  |  |  |     rep2 = repr(err2) | 
					
						
							|  |  |  |     if "was never closed" in rep1 and "was never closed" in rep2: | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     if rep1 == rep2: | 
					
						
							|  |  |  |         return True | 
					
						
							|  |  |  |     return False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-02-13 22:07:59 +00:00
										 |  |  | def _compile(source, filename, symbol): | 
					
						
							| 
									
										
										
										
											2022-02-08 11:54:37 +00:00
										 |  |  |     return compile(source, filename, symbol, PyCF_DONT_IMPLY_DEDENT | PyCF_ALLOW_INCOMPLETE_INPUT) | 
					
						
							| 
									
										
										
										
											2003-02-13 22:07:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-08-17 22:11:27 +00:00
										 |  |  | 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>" | 
					
						
							| 
									
										
										
										
											2020-05-14 21:59:46 -03:00
										 |  |  |     symbol -- optional grammar start symbol; "single" (default), "exec" | 
					
						
							|  |  |  |               or "eval" | 
					
						
							| 
									
										
										
										
											2001-08-17 22:11:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     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). | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2003-02-13 22:07:59 +00:00
										 |  |  |     return _maybe_compile(_compile, source, filename, symbol) | 
					
						
							| 
									
										
										
										
											2001-08-17 22:11:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 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): | 
					
						
							| 
									
										
										
										
											2022-02-08 11:54:37 +00:00
										 |  |  |         self.flags = PyCF_DONT_IMPLY_DEDENT | PyCF_ALLOW_INCOMPLETE_INPUT | 
					
						
							| 
									
										
										
										
											2001-08-17 22:11:27 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __call__(self, source, filename, symbol): | 
					
						
							| 
									
										
										
										
											2019-09-01 12:16:51 +03:00
										 |  |  |         codeob = compile(source, filename, symbol, self.flags, True) | 
					
						
							| 
									
										
										
										
											2001-08-17 22:11:27 +00:00
										 |  |  |         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) |