diff options
| -rw-r--r-- | mesonbuild/mintro.py | 4 | ||||
| -rw-r--r-- | mesonbuild/options.py | 45 | ||||
| -rwxr-xr-x | run_mypy.py | 1 |
3 files changed, 32 insertions, 18 deletions
diff --git a/mesonbuild/mintro.py b/mesonbuild/mintro.py index cf76b6012..4b65c5aca 100644 --- a/mesonbuild/mintro.py +++ b/mesonbuild/mintro.py @@ -317,7 +317,7 @@ def list_buildoptions(coredata: cdata.CoreData, subprojects: T.Optional[T.List[s elif isinstance(opt, options.UserComboOption): optdict['choices'] = opt.printable_choices() typestr = 'combo' - elif isinstance(opt, options.UserIntegerOption): + elif isinstance(opt, (options.UserIntegerOption, options.UserUmaskOption)): typestr = 'integer' elif isinstance(opt, options.UserStringArrayOption): typestr = 'array' @@ -325,7 +325,7 @@ def list_buildoptions(coredata: cdata.CoreData, subprojects: T.Optional[T.List[s if c: optdict['choices'] = c else: - raise RuntimeError("Unknown option type") + raise RuntimeError('Unknown option type: ', repr(type(opt))) optdict['type'] = typestr optdict['description'] = opt.description optlist.append(optdict) diff --git a/mesonbuild/options.py b/mesonbuild/options.py index b61babec2..87c31d21c 100644 --- a/mesonbuild/options.py +++ b/mesonbuild/options.py @@ -29,7 +29,7 @@ from .mesonlib import ( from . import mlog if T.TYPE_CHECKING: - from typing_extensions import TypeAlias, TypedDict + from typing_extensions import Literal, TypeAlias, TypedDict DeprecatedType: TypeAlias = T.Union[bool, str, T.Dict[str, str], T.List[str]] @@ -320,13 +320,16 @@ class UserBooleanOption(EnumeratedUserOption[bool]): return False raise MesonException(f'Option "{self.name}" value {value} is not boolean (true or false).') -@dataclasses.dataclass -class UserIntegerOption(UserOption[int]): - min_value: T.Optional[int] = None - max_value: T.Optional[int] = None +class _UserIntegerBase(UserOption[_T]): + + min_value: T.Optional[int] + max_value: T.Optional[int] + + if T.TYPE_CHECKING: + def toint(self, v: str) -> int: ... - def __post_init__(self, value_: int) -> None: + def __post_init__(self, value_: _T) -> None: super().__post_init__(value_) choices: T.List[str] = [] if self.min_value is not None: @@ -338,16 +341,23 @@ class UserIntegerOption(UserOption[int]): def printable_choices(self) -> T.Optional[T.List[str]]: return [self.__choices] - def validate_value(self, value: T.Any) -> int: + def validate_value(self, value: T.Any) -> _T: if isinstance(value, str): - value = self.toint(value) + value = T.cast('_T', self.toint(value)) if not isinstance(value, int): raise MesonException(f'Value {value!r} for option "{self.name}" is not an integer.') if self.min_value is not None and value < self.min_value: raise MesonException(f'Value {value} for option "{self.name}" is less than minimum value {self.min_value}.') if self.max_value is not None and value > self.max_value: raise MesonException(f'Value {value} for option "{self.name}" is more than maximum value {self.max_value}.') - return value + return T.cast('_T', value) + + +@dataclasses.dataclass +class UserIntegerOption(_UserIntegerBase[int]): + + min_value: T.Optional[int] = None + max_value: T.Optional[int] = None def toint(self, valuestring: str) -> int: try: @@ -355,6 +365,7 @@ class UserIntegerOption(UserOption[int]): except ValueError: raise MesonException(f'Value string "{valuestring}" for option "{self.name}" is not convertible to an integer.') + class OctalInt(int): # NinjaBackend.get_user_option_args uses str() to converts it to a command line option # UserUmaskOption.toint() uses int(str, 8) to convert it to an integer @@ -362,28 +373,30 @@ class OctalInt(int): def __str__(self) -> str: return oct(int(self)) + @dataclasses.dataclass -class UserUmaskOption(UserIntegerOption, UserOption[T.Union[str, OctalInt]]): +class UserUmaskOption(_UserIntegerBase[T.Union["Literal['preserve']", OctalInt]]): min_value: T.Optional[int] = dataclasses.field(default=0, init=False) max_value: T.Optional[int] = dataclasses.field(default=0o777, init=False) def printable_value(self) -> str: - if self.value == 'preserve': - return self.value - return format(self.value, '04o') + if isinstance(self.value, int): + return format(self.value, '04o') + return self.value - def validate_value(self, value: T.Any) -> T.Union[str, OctalInt]: + def validate_value(self, value: T.Any) -> T.Union[Literal['preserve'], OctalInt]: if value == 'preserve': return 'preserve' return OctalInt(super().validate_value(value)) - def toint(self, valuestring: T.Union[str, OctalInt]) -> int: + def toint(self, valuestring: str) -> int: try: return int(valuestring, 8) except ValueError as e: raise MesonException(f'Invalid mode for option "{self.name}" {e}') + @dataclasses.dataclass class UserComboOption(EnumeratedUserOption[str]): @@ -581,7 +594,7 @@ class BuiltinOption(T.Generic[_T]): return '--' + name.replace('_', '-') def prefixed_default(self, name: 'OptionKey', prefix: str = '') -> T.Any: - if self.opt_type in [UserComboOption, UserIntegerOption]: + if self.opt_type in {UserComboOption, UserIntegerOption, UserUmaskOption}: return self.default try: return BUILTIN_DIR_NOPREFIX_OPTIONS[name][prefix] diff --git a/run_mypy.py b/run_mypy.py index 9a4e241ec..4f7a6317b 100755 --- a/run_mypy.py +++ b/run_mypy.py @@ -79,6 +79,7 @@ modules = [ 'mesonbuild/msetup.py', 'mesonbuild/mtest.py', 'mesonbuild/optinterpreter.py', + 'mesonbuild/options.py', 'mesonbuild/programs.py', ] additional = [ |
