| # Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html |
| # For details: https://github.com/PyCQA/pylint/blob/master/LICENSE |
| |
| import copy |
| import optparse # pylint: disable=deprecated-module |
| import re |
| |
| from pylint import utils |
| |
| |
| # pylint: disable=unused-argument |
| def _csv_validator(_, name, value): |
| return utils._check_csv(value) |
| |
| |
| # pylint: disable=unused-argument |
| def _regexp_validator(_, name, value): |
| if hasattr(value, "pattern"): |
| return value |
| return re.compile(value) |
| |
| |
| # pylint: disable=unused-argument |
| def _regexp_csv_validator(_, name, value): |
| return [_regexp_validator(_, name, val) for val in _csv_validator(_, name, value)] |
| |
| |
| def _choice_validator(choices, name, value): |
| if value not in choices: |
| msg = "option %s: invalid value: %r, should be in %s" |
| raise optparse.OptionValueError(msg % (name, value, choices)) |
| return value |
| |
| |
| def _yn_validator(opt, _, value): |
| if isinstance(value, int): |
| return bool(value) |
| if value in ("y", "yes"): |
| return True |
| if value in ("n", "no"): |
| return False |
| msg = "option %s: invalid yn value %r, should be in (y, yes, n, no)" |
| raise optparse.OptionValueError(msg % (opt, value)) |
| |
| |
| def _multiple_choice_validator(choices, name, value): |
| values = utils._check_csv(value) |
| for csv_value in values: |
| if csv_value not in choices: |
| msg = "option %s: invalid value: %r, should be in %s" |
| raise optparse.OptionValueError(msg % (name, csv_value, choices)) |
| return values |
| |
| |
| def _non_empty_string_validator(opt, _, value): |
| if not value: |
| msg = "indent string can't be empty." |
| raise optparse.OptionValueError(msg) |
| return utils._unquote(value) |
| |
| |
| def _multiple_choices_validating_option(opt, name, value): |
| return _multiple_choice_validator(opt.choices, name, value) |
| |
| |
| def _py_version_validator(_, name, value): |
| if not isinstance(value, tuple): |
| try: |
| value = tuple(int(val) for val in value.split(".")) |
| except (ValueError, AttributeError): |
| raise optparse.OptionValueError(f"Invalid format for {name}") from None |
| return value |
| |
| |
| VALIDATORS = { |
| "string": utils._unquote, |
| "int": int, |
| "float": float, |
| "regexp": re.compile, |
| "regexp_csv": _regexp_csv_validator, |
| "csv": _csv_validator, |
| "yn": _yn_validator, |
| "choice": lambda opt, name, value: _choice_validator(opt["choices"], name, value), |
| "multiple_choice": lambda opt, name, value: _multiple_choice_validator( |
| opt["choices"], name, value |
| ), |
| "non_empty_string": _non_empty_string_validator, |
| "py_version": _py_version_validator, |
| } |
| |
| |
| def _call_validator(opttype, optdict, option, value): |
| if opttype not in VALIDATORS: |
| raise Exception('Unsupported type "%s"' % opttype) |
| try: |
| return VALIDATORS[opttype](optdict, option, value) |
| except TypeError: |
| try: |
| return VALIDATORS[opttype](value) |
| except Exception as e: |
| raise optparse.OptionValueError( |
| f"{option} value ({value!r}) should be of type {opttype}" |
| ) from e |
| |
| |
| def _validate(value, optdict, name=""): |
| """return a validated value for an option according to its type |
| |
| optional argument name is only used for error message formatting |
| """ |
| try: |
| _type = optdict["type"] |
| except KeyError: |
| return value |
| return _call_validator(_type, optdict, name, value) |
| |
| |
| # pylint: disable=no-member |
| class Option(optparse.Option): |
| TYPES = optparse.Option.TYPES + ( |
| "regexp", |
| "regexp_csv", |
| "csv", |
| "yn", |
| "multiple_choice", |
| "non_empty_string", |
| "py_version", |
| ) |
| ATTRS = optparse.Option.ATTRS + ["hide", "level"] |
| TYPE_CHECKER = copy.copy(optparse.Option.TYPE_CHECKER) |
| TYPE_CHECKER["regexp"] = _regexp_validator |
| TYPE_CHECKER["regexp_csv"] = _regexp_csv_validator |
| TYPE_CHECKER["csv"] = _csv_validator |
| TYPE_CHECKER["yn"] = _yn_validator |
| TYPE_CHECKER["multiple_choice"] = _multiple_choices_validating_option |
| TYPE_CHECKER["non_empty_string"] = _non_empty_string_validator |
| TYPE_CHECKER["py_version"] = _py_version_validator |
| |
| def __init__(self, *opts, **attrs): |
| optparse.Option.__init__(self, *opts, **attrs) |
| if hasattr(self, "hide") and self.hide: |
| self.help = optparse.SUPPRESS_HELP |
| |
| def _check_choice(self): |
| if self.type in ("choice", "multiple_choice"): |
| if self.choices is None: |
| raise optparse.OptionError( |
| "must supply a list of choices for type 'choice'", self |
| ) |
| if not isinstance(self.choices, (tuple, list)): |
| raise optparse.OptionError( |
| "choices must be a list of strings ('%s' supplied)" |
| % str(type(self.choices)).split("'")[1], |
| self, |
| ) |
| elif self.choices is not None: |
| raise optparse.OptionError( |
| "must not supply choices for type %r" % self.type, self |
| ) |
| |
| # pylint: disable=unsupported-assignment-operation |
| optparse.Option.CHECK_METHODS[2] = _check_choice # type: ignore |
| |
| def process(self, opt, value, values, parser): |
| # First, convert the value(s) to the right type. Howl if any |
| # value(s) are bogus. |
| value = self.convert_value(opt, value) |
| if self.type == "named": |
| existent = getattr(values, self.dest) |
| if existent: |
| existent.update(value) |
| value = existent |
| # And then take whatever action is expected of us. |
| # This is a separate method to make life easier for |
| # subclasses to add new actions. |
| return self.take_action(self.action, self.dest, opt, value, values, parser) |