diff options
Diffstat (limited to 'mesonbuild/coredata.py')
-rw-r--r-- | mesonbuild/coredata.py | 90 |
1 files changed, 47 insertions, 43 deletions
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py index 183b333aa..34adad3e7 100644 --- a/mesonbuild/coredata.py +++ b/mesonbuild/coredata.py @@ -26,17 +26,19 @@ from .wrap import WrapMode import ast import argparse import configparser -from typing import Optional, Any, TypeVar, Generic, Type, List +from typing import Optional, Any, TypeVar, Generic, Type, List, Union version = '0.50.999' backendlist = ['ninja', 'vs', 'vs2010', 'vs2015', 'vs2017', 'vs2019', 'xcode'] default_yielding = False -class UserOption: - def __init__(self, name, description, choices, yielding): +# Can't bind this near the class method it seems, sadly. +_T = TypeVar('_T') + +class UserOption(Generic[_T]): + def __init__(self, description, choices, yielding): super().__init__() - self.name = name self.choices = choices self.description = description if yielding is None: @@ -51,31 +53,31 @@ class UserOption: # Check that the input is a valid value and return the # "cleaned" or "native" version. For example the Boolean # option could take the string "true" and return True. - def validate_value(self, value): + def validate_value(self, value: Any) -> _T: raise RuntimeError('Derived option class did not override validate_value.') def set_value(self, newvalue): self.value = self.validate_value(newvalue) -class UserStringOption(UserOption): - def __init__(self, name, description, value, choices=None, yielding=None): - super().__init__(name, description, choices, yielding) +class UserStringOption(UserOption[str]): + def __init__(self, description, value, choices=None, yielding=None): + super().__init__(description, choices, yielding) self.set_value(value) def validate_value(self, value): if not isinstance(value, str): - raise MesonException('Value "%s" for string option "%s" is not a string.' % (str(value), self.name)) + raise MesonException('Value "%s" for string option is not a string.' % str(value)) return value -class UserBooleanOption(UserOption): - def __init__(self, name, description, value, yielding=None): - super().__init__(name, description, [True, False], yielding) +class UserBooleanOption(UserOption[bool]): + def __init__(self, description, value, yielding=None): + super().__init__(description, [True, False], yielding) self.set_value(value) - def __bool__(self): + def __bool__(self) -> bool: return self.value - def validate_value(self, value): + def validate_value(self, value) -> bool: if isinstance(value, bool): return value if value.lower() == 'true': @@ -84,9 +86,9 @@ class UserBooleanOption(UserOption): return False raise MesonException('Value %s is not boolean (true or false).' % value) -class UserIntegerOption(UserOption): - def __init__(self, name, description, min_value, max_value, value, yielding=None): - super().__init__(name, description, [True, False], yielding) +class UserIntegerOption(UserOption[int]): + def __init__(self, description, min_value, max_value, value, yielding=None): + super().__init__(description, [True, False], yielding) self.min_value = min_value self.max_value = max_value self.set_value(value) @@ -97,7 +99,7 @@ class UserIntegerOption(UserOption): c.append('<=' + str(max_value)) self.choices = ', '.join(c) - def validate_value(self, value): + def validate_value(self, value) -> int: if isinstance(value, str): value = self.toint(value) if not isinstance(value, int): @@ -108,15 +110,15 @@ class UserIntegerOption(UserOption): raise MesonException('New value %d is more than maximum value %d.' % (value, self.max_value)) return value - def toint(self, valuestring): + def toint(self, valuestring) -> int: try: return int(valuestring) except ValueError: raise MesonException('Value string "%s" is not convertable to an integer.' % valuestring) -class UserUmaskOption(UserIntegerOption): - def __init__(self, name, description, value, yielding=None): - super().__init__(name, description, 0, 0o777, value, yielding) +class UserUmaskOption(UserIntegerOption, UserOption[Union[str, int]]): + def __init__(self, description, value, yielding=None): + super().__init__(description, 0, 0o777, value, yielding) self.choices = ['preserve', '0000-0777'] def printable_value(self): @@ -135,9 +137,9 @@ class UserUmaskOption(UserIntegerOption): except ValueError as e: raise MesonException('Invalid mode: {}'.format(e)) -class UserComboOption(UserOption): - def __init__(self, name, description, choices, value, yielding=None): - super().__init__(name, description, choices, yielding) +class UserComboOption(UserOption[str]): + def __init__(self, description, choices: List[str], value, yielding=None): + super().__init__(description, choices, yielding) if not isinstance(self.choices, list): raise MesonException('Combo choices must be an array.') for i in self.choices: @@ -148,17 +150,17 @@ class UserComboOption(UserOption): def validate_value(self, value): if value not in self.choices: optionsstring = ', '.join(['"%s"' % (item,) for item in self.choices]) - raise MesonException('Value "%s" for combo option "%s" is not one of the choices. Possible choices are: %s.' % (value, self.name, optionsstring)) + raise MesonException('Value "%s" for combo option is not one of the choices. Possible choices are: %s.' % (value, optionsstring)) return value -class UserArrayOption(UserOption): - def __init__(self, name, description, value, shlex_split=False, user_input=False, allow_dups=False, **kwargs): - super().__init__(name, description, kwargs.get('choices', []), yielding=kwargs.get('yielding', None)) +class UserArrayOption(UserOption[List[str]]): + def __init__(self, description, value, shlex_split=False, user_input=False, allow_dups=False, **kwargs): + super().__init__(description, kwargs.get('choices', []), yielding=kwargs.get('yielding', None)) self.shlex_split = shlex_split self.allow_dups = allow_dups self.value = self.validate_value(value, user_input=user_input) - def validate_value(self, value, user_input=True): + def validate_value(self, value, user_input=True) -> List[str]: # User input is for options defined on the command line (via -D # options). Users can put their input in as a comma separated # string, but for defining options in meson_options.txt the format @@ -182,8 +184,8 @@ class UserArrayOption(UserOption): raise MesonException('"{0}" should be a string array, but it is not'.format(str(newvalue))) if not self.allow_dups and len(set(newvalue)) != len(newvalue): - msg = 'Duplicated values in array option "%s" is deprecated. ' \ - 'This will become a hard error in the future.' % (self.name) + msg = 'Duplicated values in array option is deprecated. ' \ + 'This will become a hard error in the future.' mlog.deprecation(msg) for i in newvalue: if not isinstance(i, str): @@ -199,8 +201,8 @@ class UserArrayOption(UserOption): class UserFeatureOption(UserComboOption): static_choices = ['enabled', 'disabled', 'auto'] - def __init__(self, name, description, value, yielding=None): - super().__init__(name, description, self.static_choices, value, yielding) + def __init__(self, description, value, yielding=None): + super().__init__(description, self.static_choices, value, yielding) def is_enabled(self): return self.value == 'enabled' @@ -334,22 +336,20 @@ class CoreData: # Create builtin options with default values self.builtins = {} for key, opt in builtin_options.items(): - self.builtins[key] = opt.init_option(key) + self.builtins[key] = opt.init_option() if opt.separate_cross: - self.builtins['cross_' + key] = opt.init_option(key) + self.builtins['cross_' + key] = opt.init_option() def init_backend_options(self, backend_name): if backend_name == 'ninja': self.backend_options['backend_max_links'] = \ UserIntegerOption( - 'backend_max_links', 'Maximum number of linker processes to run or 0 for no ' 'limit', 0, None, 0) elif backend_name.startswith('vs'): self.backend_options['backend_startup_project'] = \ UserStringOption( - 'backend_startup_project', 'Default project to execute in Visual Studio', '') @@ -433,7 +433,11 @@ class CoreData: for opts in self.get_all_options(): if option_name in opts: opt = opts[option_name] - return opt.validate_value(override_value) + try: + return opt.validate_value(override_value) + except MesonException as e: + raise type(e)(('Validation failed for option %s: ' % option_name) + str(e)) \ + .with_traceback(sys.exc_into()[2]) raise MesonException('Tried to validate unknown option %s.' % option_name) def get_external_args(self, for_machine: MachineChoice, lang): @@ -695,9 +699,9 @@ def parse_cmd_line_options(args): delattr(args, name) -_U = TypeVar('_U', bound=UserOption) +_U = TypeVar('_U', bound=UserOption[_T]) -class BuiltinOption(Generic[_U]): +class BuiltinOption(Generic[_T, _U]): """Class for a builtin option type. @@ -713,12 +717,12 @@ class BuiltinOption(Generic[_U]): self.yielding = yielding self.separate_cross = separate_cross - def init_option(self, name: str) -> _U: + def init_option(self) -> _U: """Create an instance of opt_type and return it.""" keywords = {'yielding': self.yielding, 'value': self.default} if self.choices: keywords['choices'] = self.choices - return self.opt_type(name, self.description, **keywords) + return self.opt_type(self.description, **keywords) def _argparse_action(self) -> Optional[str]: if self.default is True: |