mirror of
https://github.com/3minbe/DBC_Converter.git
synced 2026-05-17 01:23:58 +09:00
216 lines
6.2 KiB
Python
216 lines
6.2 KiB
Python
"""
|
|
Author: Dogeek
|
|
License: GNU GPLv3
|
|
Source: This repository
|
|
|
|
Validators to validate entry input.
|
|
"""
|
|
|
|
import re
|
|
import sys
|
|
|
|
from ttkwidgets.utilities import isint, isfloat
|
|
|
|
|
|
class Validator:
|
|
"""
|
|
Base validator class
|
|
|
|
Specify the VALIDATE_ON class attribute (defaults to 'all') to change
|
|
on which tkinter condition the validation will be done.
|
|
|
|
Possibilities are :
|
|
* 'all'
|
|
* 'none'
|
|
* 'focus'
|
|
* 'focusin'
|
|
* 'focusout'
|
|
* 'key'
|
|
"""
|
|
VALIDATE_ON = 'all'
|
|
|
|
def __init__(self, validate_on=None):
|
|
if validate_on is not None:
|
|
self.VALIDATE_ON = validate_on
|
|
self.widget = None
|
|
|
|
def validate(self, widget):
|
|
self.widget = widget
|
|
validatecmd = (widget.register(self._validate), '%P')
|
|
return {'validate': self.VALIDATE_ON, 'validatecommand': validatecmd}
|
|
|
|
def _validate(self, value):
|
|
return not value
|
|
|
|
@property
|
|
def is_valid(self):
|
|
if self.widget is not None:
|
|
return self._validate(self.widget.get())
|
|
raise ValueError('Widget is not attached to this validator')
|
|
|
|
|
|
class MultiValidator:
|
|
"""
|
|
Base class to handle multiple validators attachment.
|
|
"""
|
|
def __init__(self, *validators, validate_on='all'):
|
|
"""
|
|
:param *validators: Validator instances or classes to attach
|
|
:param validate_on: tkinter condition on which the validation will be done
|
|
default : 'all', see `help(Validator)` for a list of
|
|
possible values
|
|
"""
|
|
if validate_on not in ('all', 'none', 'focusin', 'focusout', 'focus', 'key'):
|
|
raise ValueError(
|
|
"validate_on is not in ('all', 'none', "
|
|
"'focusin', 'focusout', 'focus', 'key')"
|
|
)
|
|
self.validators = []
|
|
for v in validators:
|
|
if isinstance(v, type):
|
|
v = v()
|
|
if isinstance(v, (MultiValidator, Validator)):
|
|
self.validators.append(v)
|
|
else:
|
|
raise TypeError("One of the provided validators is not a Validator or MultiValidator instance")
|
|
self.validate_on = validate_on
|
|
self.widget = None
|
|
|
|
def validate(self, widget):
|
|
self.widget = widget
|
|
validatecmd = (widget.register(self._validate), '%P')
|
|
return {'validate': self.validate_on, 'validatecommand': validatecmd}
|
|
|
|
def _validate(self, value):
|
|
raise NotImplementedError()
|
|
|
|
@property
|
|
def is_valid(self):
|
|
if self.widget is not None:
|
|
return self._validate(self.widget.get())
|
|
raise ValueError('Widget is not attached to this validator')
|
|
|
|
|
|
class AnyValidator(MultiValidator):
|
|
"""
|
|
Validates any attached validators. The input will be deemed valid if and only if
|
|
one of the attached validators deem the value valid.
|
|
"""
|
|
def _validate(self, value):
|
|
return any(validator._validate(value) for validator in self.validators)
|
|
|
|
|
|
class AllValidator(MultiValidator):
|
|
"""
|
|
Validates all attached validators. The input will be deemed valid if and only if
|
|
all attached validators deem the value valid.
|
|
"""
|
|
def _validate(self, value):
|
|
return all(validator._validate(value) for validator in self.validators)
|
|
|
|
|
|
class RegexValidator(Validator):
|
|
"""
|
|
A validator that will check against a regular expression stored in the REGEX
|
|
class attribute
|
|
|
|
REGEX can either be a re.Pattern or a python string.
|
|
"""
|
|
REGEX = None
|
|
|
|
def __init__(self, regex=None, **kwargs):
|
|
if regex is not None:
|
|
self.REGEX = regex
|
|
super().__init__(**kwargs)
|
|
|
|
def _validate(self, value):
|
|
if not isinstance(value, str):
|
|
raise TypeError('{} is not a string.'.format(value))
|
|
|
|
if super()._validate(value):
|
|
return True
|
|
# isinstance(self.REGEX, re.Pattern) only works on 3.7+
|
|
if re.search(r'(Pattern|SRE_Pattern)', self.REGEX.__class__.__name__):
|
|
return self.REGEX.search(value) is not None
|
|
if isinstance(self.REGEX, str):
|
|
return re.search(self.REGEX, value) is not None
|
|
raise TypeError('{} is not a pattern or a string'.format(self.regex))
|
|
|
|
|
|
class IntValidator(Validator):
|
|
def _validate(self, value):
|
|
if super()._validate(value):
|
|
return True
|
|
|
|
return isint(value)
|
|
|
|
|
|
class FloatValidator(RegexValidator):
|
|
REGEX = r'[0-9\.]'
|
|
|
|
|
|
class PercentValidator(Validator):
|
|
def _validate(self, value):
|
|
# percentages can be 0-100 integer
|
|
# float 0-1
|
|
if super()._validate(value):
|
|
return True
|
|
return ((isfloat(value) or isint(value)) and 0 <= float(value) <= 100)
|
|
|
|
|
|
class StringValidator(Validator):
|
|
"""
|
|
A validator you have to instanciate with a string containing the
|
|
characters you want in.
|
|
"""
|
|
def __init__(self, string):
|
|
"""
|
|
:param string: String of allowed characters
|
|
:type string: str
|
|
"""
|
|
self.string = string
|
|
|
|
def _validate(self, value):
|
|
if super()._validate(value):
|
|
return True
|
|
return all([c in self.string for c in value])
|
|
|
|
|
|
class CapitalizedStringValidator(RegexValidator):
|
|
REGEX = '[{}].*'.format("".join([chr(i) for i in range(sys.maxunicode) if chr(i).isupper()]))
|
|
|
|
|
|
class EmailValidator(RegexValidator):
|
|
VALIDATE_ON = 'focusout'
|
|
|
|
REGEX = (
|
|
r'^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|'
|
|
r'(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$'
|
|
)
|
|
|
|
|
|
class PasswordValidator(RegexValidator):
|
|
"""
|
|
Password validator. The requirements are as follows :
|
|
* At least 1 lowercase character
|
|
* At least 1 uppercase character
|
|
* At least 1 digit
|
|
* At least 1 special character (!@#$%^&*)
|
|
* Be at least 8 characters long
|
|
"""
|
|
VALIDATE_ON = 'focusout'
|
|
|
|
REGEX = r'^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#\$%\^&\*])(?=.{8,})'
|
|
|
|
|
|
class IPv4Validator(RegexValidator):
|
|
"""
|
|
Validates IPv4 addresses. The following are valid:
|
|
* localhost
|
|
* 192.168.0.1
|
|
* localhost:3158
|
|
"""
|
|
VALIDATE_ON = 'focusout'
|
|
|
|
REGEX = r'^((?:[0-9]{1,3}\.){3}[0-9]{1,3}|localhost)(:\d{2,6})?$'
|