Source code interpreter for use in bpython.
| 101 | |
| 102 | |
| 103 | class Interpreter(code.InteractiveInterpreter): |
| 104 | """Source code interpreter for use in bpython.""" |
| 105 | |
| 106 | bpython_input_re = LazyReCompile(r"<bpython-input-\d+>") |
| 107 | |
| 108 | def __init__( |
| 109 | self, |
| 110 | locals: dict[str, Any] | None = None, |
| 111 | ) -> None: |
| 112 | """Constructor. |
| 113 | |
| 114 | The optional 'locals' argument specifies the dictionary in which code |
| 115 | will be executed; it defaults to a newly created dictionary with key |
| 116 | "__name__" set to "__main__". |
| 117 | |
| 118 | The syntaxerror callback can be set at any time and will be called |
| 119 | on a caught syntax error. The purpose for this in bpython is so that |
| 120 | the repl can be instantiated after the interpreter (which it |
| 121 | necessarily must be with the current factoring) and then an exception |
| 122 | callback can be added to the Interpreter instance afterwards - more |
| 123 | specifically, this is so that autoindentation does not occur after a |
| 124 | traceback. |
| 125 | """ |
| 126 | |
| 127 | self.syntaxerror_callback: Callable | None = None |
| 128 | |
| 129 | if locals is None: |
| 130 | # instead of messing with sys.modules, we should modify sys.modules |
| 131 | # in the interpreter instance |
| 132 | sys.modules["__main__"] = main_mod = ModuleType("__main__") |
| 133 | locals = main_mod.__dict__ |
| 134 | |
| 135 | super().__init__(locals) |
| 136 | self.timer = RuntimeTimer() |
| 137 | |
| 138 | def runsource( |
| 139 | self, |
| 140 | source: str, |
| 141 | filename: str | None = None, |
| 142 | symbol: str = "single", |
| 143 | ) -> bool: |
| 144 | """Execute Python code. |
| 145 | |
| 146 | source, filename and symbol are passed on to |
| 147 | code.InteractiveInterpreter.runsource.""" |
| 148 | |
| 149 | if filename is None: |
| 150 | filename = filename_for_console_input(source) |
| 151 | with self.timer: |
| 152 | return super().runsource(source, filename, symbol) |
| 153 | |
| 154 | def showsyntaxerror(self, filename: str | None = None, **kwargs) -> None: |
| 155 | """Override the regular handler, the code's copied and pasted from |
| 156 | code.py, as per showtraceback, but with the syntaxerror callback called |
| 157 | and the text in a pretty colour.""" |
| 158 | if self.syntaxerror_callback is not None: |
| 159 | self.syntaxerror_callback() |
| 160 |
nothing calls this directly
no test coverage detected