diff options
Diffstat (limited to 'ptpython/validator.py')
-rw-r--r-- | ptpython/validator.py | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/ptpython/validator.py b/ptpython/validator.py new file mode 100644 index 0000000..91b9c28 --- /dev/null +++ b/ptpython/validator.py @@ -0,0 +1,62 @@ +from __future__ import annotations + +from typing import Callable + +from prompt_toolkit.document import Document +from prompt_toolkit.validation import ValidationError, Validator + +from .utils import unindent_code + +__all__ = ["PythonValidator"] + + +class PythonValidator(Validator): + """ + Validation of Python input. + + :param get_compiler_flags: Callable that returns the currently + active compiler flags. + """ + + def __init__(self, get_compiler_flags: Callable[[], int] | None = None) -> None: + self.get_compiler_flags = get_compiler_flags + + def validate(self, document: Document) -> None: + """ + Check input for Python syntax errors. + """ + text = unindent_code(document.text) + + # When the input starts with Ctrl-Z, always accept. This means EOF in a + # Python REPL. + if text.startswith("\x1a"): + return + + # When the input starts with an exclamation mark. Accept as shell + # command. + if text.lstrip().startswith("!"): + return + + try: + if self.get_compiler_flags: + flags = self.get_compiler_flags() + else: + flags = 0 + + compile(text, "<input>", "exec", flags=flags, dont_inherit=True) + except SyntaxError as e: + # Note, the 'or 1' for offset is required because Python 2.7 + # gives `None` as offset in case of '4=4' as input. (Looks like + # fixed in Python 3.) + # TODO: This is not correct if indentation was removed. + index = document.translate_row_col_to_index( + (e.lineno or 1) - 1, (e.offset or 1) - 1 + ) + raise ValidationError(index, f"Syntax Error: {e}") + except TypeError as e: + # e.g. "compile() expected string without null bytes" + raise ValidationError(0, str(e)) + except ValueError as e: + # In Python 2, compiling "\x9" (an invalid escape sequence) raises + # ValueError instead of SyntaxError. + raise ValidationError(0, "Syntax Error: %s" % e) |