|
"""Module contains pre-built validators.""" |
|
import re |
|
from pathlib import Path |
|
from typing import Optional |
|
|
|
from prompt_toolkit.validation import ValidationError, Validator |
|
|
|
__all__ = [ |
|
"PathValidator", |
|
"EmptyInputValidator", |
|
"PasswordValidator", |
|
"NumberValidator", |
|
] |
|
|
|
|
|
class NumberValidator(Validator): |
|
""":class:`~prompt_toolkit.validation.Validator` to validate if input is a number. |
|
|
|
Args: |
|
message: Error message to display in the validatation toolbar when validation failed. |
|
float_allowed: Allow input to contain floating number (with decimal). |
|
""" |
|
|
|
def __init__( |
|
self, message: str = "Input should be a number", float_allowed: bool = False |
|
) -> None: |
|
self._message = message |
|
self._float_allowed = float_allowed |
|
|
|
def validate(self, document) -> None: |
|
"""Check if user input is a valid number. |
|
|
|
This method is used internally by `prompt_toolkit <https://python-prompt-toolkit.readthedocs.io/en/master/>`_. |
|
|
|
See Also: |
|
https://python-prompt-toolkit.readthedocs.io/en/master/pages/asking_for_input.html?highlight=validator#input-validation |
|
""" |
|
try: |
|
if self._float_allowed: |
|
float(document.text) |
|
else: |
|
int(document.text) |
|
except ValueError: |
|
raise ValidationError( |
|
message=self._message, cursor_position=document.cursor_position |
|
) |
|
|
|
|
|
class PathValidator(Validator): |
|
""":class:`~prompt_toolkit.validation.Validator` to validate if input is a valid filepath on the system. |
|
|
|
Args: |
|
message: Error message to display in the validatation toolbar when validation failed. |
|
is_file: Explicitly check if the input is a valid file on the system. |
|
is_dir: Explicitly check if the input is a valid directory/folder on the system. |
|
""" |
|
|
|
def __init__( |
|
self, |
|
message: str = "Input is not a valid path", |
|
is_file: bool = False, |
|
is_dir: bool = False, |
|
) -> None: |
|
self._message = message |
|
self._is_file = is_file |
|
self._is_dir = is_dir |
|
|
|
def validate(self, document) -> None: |
|
"""Check if user input is a filepath that exists on the system based on conditions. |
|
|
|
This method is used internally by `prompt_toolkit <https://python-prompt-toolkit.readthedocs.io/en/master/>`_. |
|
|
|
See Also: |
|
https://python-prompt-toolkit.readthedocs.io/en/master/pages/asking_for_input.html?highlight=validator#input-validation |
|
""" |
|
path = Path(document.text).expanduser() |
|
if self._is_file and not path.is_file(): |
|
raise ValidationError( |
|
message=self._message, |
|
cursor_position=document.cursor_position, |
|
) |
|
elif self._is_dir and not path.is_dir(): |
|
raise ValidationError( |
|
message=self._message, |
|
cursor_position=document.cursor_position, |
|
) |
|
elif not path.exists(): |
|
raise ValidationError( |
|
message=self._message, |
|
cursor_position=document.cursor_position, |
|
) |
|
|
|
|
|
class EmptyInputValidator(Validator): |
|
""":class:`~prompt_toolkit.validation.Validator` to validate if the input is empty. |
|
|
|
Args: |
|
message: Error message to display in the validatation toolbar when validation failed. |
|
""" |
|
|
|
def __init__(self, message: str = "Input cannot be empty") -> None: |
|
self._message = message |
|
|
|
def validate(self, document) -> None: |
|
"""Check if user input is empty. |
|
|
|
This method is used internally by `prompt_toolkit <https://python-prompt-toolkit.readthedocs.io/en/master/>`_. |
|
|
|
See Also: |
|
https://python-prompt-toolkit.readthedocs.io/en/master/pages/asking_for_input.html?highlight=validator#input-validation |
|
""" |
|
if not len(document.text) > 0: |
|
raise ValidationError( |
|
message=self._message, |
|
cursor_position=document.cursor_position, |
|
) |
|
|
|
|
|
class PasswordValidator(Validator): |
|
""":class:`~prompt_toolkit.validation.Validator` to validate password compliance. |
|
|
|
Args: |
|
message: Error message to display in the validatation toolbar when validation failed. |
|
length: The minimum length of the password. |
|
cap: Password should include at least one capital letter. |
|
special: Password should include at least one special char "@$!%*#?&". |
|
number: Password should include at least one number. |
|
""" |
|
|
|
def __init__( |
|
self, |
|
message: str = "Input is not compliant with the password constraints", |
|
length: Optional[int] = None, |
|
cap: bool = False, |
|
special: bool = False, |
|
number: bool = False, |
|
) -> None: |
|
password_pattern = r"^" |
|
if cap: |
|
password_pattern += r"(?=.*[A-Z])" |
|
if special: |
|
password_pattern += r"(?=.*[@$!%*#?&])" |
|
if number: |
|
password_pattern += r"(?=.*[0-9])" |
|
password_pattern += r"." |
|
if length: |
|
password_pattern += r"{%s,}" % length |
|
else: |
|
password_pattern += r"*" |
|
password_pattern += r"$" |
|
self._re = re.compile(password_pattern) |
|
self._message = message |
|
|
|
def validate(self, document) -> None: |
|
"""Check if user input is compliant with the specified password constraints. |
|
|
|
This method is used internally by `prompt_toolkit <https://python-prompt-toolkit.readthedocs.io/en/master/>`_. |
|
|
|
See Also: |
|
https://python-prompt-toolkit.readthedocs.io/en/master/pages/asking_for_input.html?highlight=validator#input-validation |
|
""" |
|
if not self._re.match(document.text): |
|
raise ValidationError( |
|
message=self._message, cursor_position=document.cursor_position |
|
) |
|
|