diff options
| author | Rob van der Linde <rob@catalyst.net.nz> | 2023-05-16 11:47:45 +1200 |
|---|---|---|
| committer | Andrew Bartlett <abartlet@samba.org> | 2023-06-25 23:29:32 +0000 |
| commit | 1a5184e404d602e389b96535e792fc77314f1fd4 (patch) | |
| tree | b8f3b916ffbb1e55ae2197dfb1860bbf2fb2a8df /python | |
| parent | 9f5216912e0b2f2d0e74d4dbd10f3fb5017de331 (diff) | |
| download | samba-1a5184e404d602e389b96535e792fc77314f1fd4.tar.gz samba-1a5184e404d602e389b96535e792fc77314f1fd4.tar.bz2 samba-1a5184e404d602e389b96535e792fc77314f1fd4.zip | |
netcmd: add optparse validators and Range validator
Add the ability to the add validators to optparse Option fields.
The Option class was already subclassed in `netcmd/__init__.py` so
adding some functionality to this was relatively easy.
Added the ability to add Validator classes to a field so that this can
be used for anything else in the future, but for now there is a Range
validator required by upcoming auto silo commands.
Signed-off-by: Rob van der Linde <rob@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Diffstat (limited to 'python')
| -rw-r--r-- | python/samba/netcmd/__init__.py | 28 | ||||
| -rw-r--r-- | python/samba/netcmd/validators.py | 77 |
2 files changed, 105 insertions, 0 deletions
diff --git a/python/samba/netcmd/__init__.py b/python/samba/netcmd/__init__.py index 2e722243715..096ba096d48 100644 --- a/python/samba/netcmd/__init__.py +++ b/python/samba/netcmd/__init__.py @@ -26,10 +26,38 @@ import sys import traceback import textwrap +from .validators import ValidationError + class Option(SambaOption): + ATTRS = SambaOption.ATTRS + ["validators"] SUPPRESS_HELP = optparse.SUPPRESS_HELP + def run_validators(self, opt, value): + """Runs the list of validators on the current option. + + If the validator raises ValidationError, turn that into CommandError + which gives nicer output. + """ + validators = getattr(self, "validators") or [] + + for validator in validators: + try: + validator(opt, value) + except ValidationError as e: + raise CommandError(e) + + def convert_value(self, opt, value): + """Override convert_value to run validators just after. + + This can also be done in process() but there we would have to + replace the entire method. + """ + value = super().convert_value(opt, value) + self.run_validators(opt, value) + return value + + # This help formatter does text wrapping and preserves newlines diff --git a/python/samba/netcmd/validators.py b/python/samba/netcmd/validators.py new file mode 100644 index 00000000000..c8c5697d23f --- /dev/null +++ b/python/samba/netcmd/validators.py @@ -0,0 +1,77 @@ +# Unix SMB/CIFS implementation. +# +# validators +# +# Copyright (C) Catalyst.Net Ltd. 2023 +# +# Written by Rob van der Linde <rob@catalyst.net.nz> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +from abc import ABCMeta, abstractmethod + + +class ValidationError(Exception): + pass + + +class Validator(metaclass=ABCMeta): + + @abstractmethod + def __call__(self, field, value): + pass + + +class Range(Validator): + """Checks if the value is within range min ... max.""" + + def __init__(self, min=None, max=None): + if min is None and max is None: + raise ValueError("Range without a min and max doesn't make sense.") + + self.min = min + self.max = max + + def __call__(self, field, value): + """Check if value is within the range min ... max. + + It is possible to omit min, or omit max, in which case a more + tailored error message is returned. + """ + if self.min is not None and self.max is None: + if value < self.min: + raise ValidationError(f"{field} must be at least {self.min}") + + elif self.min is None and self.max is not None: + if value > self.max: + raise ValidationError( + f"{field} cannot be greater than {self.max}") + + elif self.min is not None and self.max is not None: + if value < self.min or value > self.max: + raise ValidationError( + f"{field} must be between {self.min} and {self.max}") + + +class OneOf(Validator): + """Checks if the value is in a list of possible choices.""" + + def __init__(self, choices): + self.choices = sorted(choices) + + def __call__(self, field, value): + if value not in self.choices: + allowed_choices = ", ".join(self.choices) + raise ValidationError(f"{field} must be one of: {allowed_choices}") |
