summaryrefslogtreecommitdiff
path: root/mesonbuild
diff options
context:
space:
mode:
authorDylan Baker <dylan@pnwbakers.com>2024-08-30 11:12:57 -0700
committerJussi Pakkanen <jpakkane@gmail.com>2025-02-05 17:45:38 +0200
commit177148686c8c207268619d2d58ee021b1d6fd082 (patch)
tree1cdf774e17613f906950f3a7d43dd037849e9950 /mesonbuild
parent164a18d84f4543669e5cab75490ff3629aa961d4 (diff)
downloadmeson-177148686c8c207268619d2d58ee021b1d6fd082.tar.gz
options: split UserIntegerOption and UserUmaskOption
They are very similar, but they are not exactly the same. By splitting them we can get full type safety, and run mypy over the options.py file!
Diffstat (limited to 'mesonbuild')
-rw-r--r--mesonbuild/mintro.py4
-rw-r--r--mesonbuild/options.py45
2 files changed, 31 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]