Skip to content

Commit

Permalink
options: Replace uses of UserOption[T.Any] with a Union of UserOpti…
Browse files Browse the repository at this point in the history
…on types

The fact that UserOption is generic is really an implementation detail,
not something to be used publicly. So by having an `AnyOptionType`
alias, we can get better type checking, as can be seen by the patch as a
whole. One of the big fixes it replace open-coded equivlalents of
`MutableKeydOptionDictType` with that type alias.
  • Loading branch information
dcbaker committed Sep 9, 2024
1 parent 00ce663 commit 8c97002
Show file tree
Hide file tree
Showing 6 changed files with 24 additions and 25 deletions.
3 changes: 1 addition & 2 deletions mesonbuild/compilers/compilers.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
from ..dependencies import Dependency

CompilerType = T.TypeVar('CompilerType', bound='Compiler')
UserOptionType = T.TypeVar('UserOptionType', bound=options.UserOption)

_T = T.TypeVar('_T')

Expand Down Expand Up @@ -590,7 +589,7 @@ def make_option_name(self, key: OptionKey) -> str:
return f'{self.language}_{key.name}'

@staticmethod
def update_options(options: MutableKeyedOptionDictType, *args: T.Tuple[OptionKey, UserOptionType]) -> MutableKeyedOptionDictType:
def update_options(options: MutableKeyedOptionDictType, *args: T.Tuple[OptionKey, options.AnyOptionType]) -> MutableKeyedOptionDictType:
options.update(args)
return options

Expand Down
4 changes: 2 additions & 2 deletions mesonbuild/coredata.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ class SharedCMDOptions(Protocol):
cross_file: T.List[str]
native_file: T.List[str]

OptionDictType = T.Union[T.Dict[str, 'options.UserOption[T.Any]'], 'OptionsView']
MutableKeyedOptionDictType = T.Dict['OptionKey', 'options.UserOption[T.Any]']
OptionDictType = T.Union[T.Dict[str, options.AnyOptionType], 'OptionsView']
MutableKeyedOptionDictType = T.Dict['OptionKey', options.AnyOptionType]
KeyedOptionDictType = T.Union['options.OptionStore', 'OptionsView']
CompilerCheckCacheKey = T.Tuple[T.Tuple[str, ...], str, FileOrString, T.Tuple[str, ...], CompileCheckMode]
# code, args
Expand Down
6 changes: 2 additions & 4 deletions mesonbuild/mconf.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@

if T.TYPE_CHECKING:
from typing_extensions import Protocol
from typing import Any
from .options import UserOption
import argparse

class CMDOptions(coredata.SharedCMDOptions, Protocol):
Expand Down Expand Up @@ -189,7 +187,7 @@ def wrap_text(text: LOGLINE, width: int) -> mlog.TV_LoggableList:
items = [l[i] if l[i] else ' ' * four_column[i] for i in range(4)]
mlog.log(*items)

def split_options_per_subproject(self, options: 'T.Union[dict[OptionKey, UserOption[Any]], coredata.KeyedOptionDictType]') -> T.Dict[str, 'coredata.MutableKeyedOptionDictType']:
def split_options_per_subproject(self, options: T.Union[coredata.MutableKeyedOptionDictType, coredata.KeyedOptionDictType]) -> T.Dict[str, 'coredata.MutableKeyedOptionDictType']:
result: T.Dict[str, 'coredata.MutableKeyedOptionDictType'] = {}
for k, o in options.items():
if k.subproject:
Expand Down Expand Up @@ -227,7 +225,7 @@ def add_section(self, section: str) -> None:
self._add_line(mlog.normal_yellow(section + ':'), '', '', '')
self.print_margin = 2

def print_options(self, title: str, opts: 'T.Union[dict[OptionKey, UserOption[Any]], coredata.KeyedOptionDictType]') -> None:
def print_options(self, title: str, opts: T.Union[coredata.MutableKeyedOptionDictType, coredata.KeyedOptionDictType]) -> None:
if not opts:
return
if title:
Expand Down
4 changes: 1 addition & 3 deletions mesonbuild/mintro.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@

if T.TYPE_CHECKING:
import argparse
from typing import Any
from .options import UserOption

from .interpreter import Interpreter
from .mparser import BaseNode
Expand Down Expand Up @@ -305,7 +303,7 @@ def list_buildoptions(coredata: cdata.CoreData, subprojects: T.Optional[T.List[s
for s in subprojects:
core_options[k.evolve(subproject=s)] = v

def add_keys(opts: 'T.Union[dict[OptionKey, UserOption[Any]], cdata.KeyedOptionDictType]', section: str) -> None:
def add_keys(opts: T.Union[cdata.MutableKeyedOptionDictType, cdata.KeyedOptionDictType], section: str) -> None:
for key, opt in sorted(opts.items()):
optdict = {'name': str(key), 'value': opt.value, 'section': section,
'machine': key.machine.get_lower_case_name() if coredata.is_per_machine_option(key) else 'any'}
Expand Down
2 changes: 1 addition & 1 deletion mesonbuild/optinterpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ class OptionInterpreter:
def __init__(self, optionstore: 'OptionStore', subproject: 'SubProject') -> None:
self.options: 'coredata.MutableKeyedOptionDictType' = {}
self.subproject = subproject
self.option_types: T.Dict[str, T.Callable[..., options.UserOption]] = {
self.option_types: T.Dict[str, T.Callable[..., options.AnyOptionType]] = {
'string': self.string_parser,
'boolean': self.boolean_parser,
'combo': self.combo_parser,
Expand Down
30 changes: 17 additions & 13 deletions mesonbuild/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@
from typing_extensions import Literal, TypeAlias, TypedDict

DeprecatedType: TypeAlias = T.Union[bool, str, T.Dict[str, str], T.List[str]]
AnyOptionType: TypeAlias = T.Union[
'UserBooleanOption', 'UserComboOption', 'UserFeatureOption',
'UserIntegerOption', 'UserStdOption', 'UserStringArrayOption',
'UserStringOption', 'UserUmaskOption']

class ArgparseKWs(TypedDict, total=False):

Expand Down Expand Up @@ -734,7 +738,7 @@ def add_to_argparse(self, name: OptionKey, parser: argparse.ArgumentParser, help

class OptionStore:
def __init__(self) -> None:
self.d: T.Dict['OptionKey', 'UserOption[T.Any]'] = {}
self.d: T.Dict['OptionKey', AnyOptionType] = {}
self.project_options: T.Set[OptionKey] = set()
self.module_options: T.Set[OptionKey] = set()
from .compilers import all_languages
Expand All @@ -748,35 +752,35 @@ def ensure_key(self, key: T.Union[OptionKey, str]) -> OptionKey:
return OptionKey(key)
return key

def get_value_object(self, key: T.Union[OptionKey, str]) -> 'UserOption[T.Any]':
def get_value_object(self, key: T.Union[OptionKey, str]) -> AnyOptionType:
return self.d[self.ensure_key(key)]

def get_value(self, key: T.Union[OptionKey, str]) -> 'T.Any':
return self.get_value_object(key).value

def add_system_option(self, key: T.Union[OptionKey, str], valobj: 'UserOption[T.Any]') -> None:
def add_system_option(self, key: T.Union[OptionKey, str], valobj: AnyOptionType) -> None:
key = self.ensure_key(key)
if '.' in key.name:
raise MesonException(f'Internal error: non-module option has a period in its name {key.name}.')
self.add_system_option_internal(key, valobj)

def add_system_option_internal(self, key: T.Union[OptionKey, str], valobj: 'UserOption[T.Any]') -> None:
def add_system_option_internal(self, key: T.Union[OptionKey, str], valobj: AnyOptionType) -> None:
key = self.ensure_key(key)
assert isinstance(valobj, UserOption)
self.d[key] = valobj

def add_compiler_option(self, language: str, key: T.Union[OptionKey, str], valobj: 'UserOption[T.Any]') -> None:
def add_compiler_option(self, language: str, key: T.Union[OptionKey, str], valobj: AnyOptionType) -> None:
key = self.ensure_key(key)
if not key.name.startswith(language + '_'):
raise MesonException(f'Internal error: all compiler option names must start with language prefix. ({key.name} vs {language}_)')
self.add_system_option(key, valobj)

def add_project_option(self, key: T.Union[OptionKey, str], valobj: 'UserOption[T.Any]') -> None:
def add_project_option(self, key: T.Union[OptionKey, str], valobj: AnyOptionType) -> None:
key = self.ensure_key(key)
self.d[key] = valobj
self.project_options.add(key)

def add_module_option(self, modulename: str, key: T.Union[OptionKey, str], valobj: 'UserOption[T.Any]') -> None:
def add_module_option(self, modulename: str, key: T.Union[OptionKey, str], valobj: AnyOptionType) -> None:
key = self.ensure_key(key)
if key.name.startswith('build.'):
raise MesonException('FATAL internal error: somebody goofed option handling.')
Expand All @@ -790,7 +794,7 @@ def set_value(self, key: T.Union[OptionKey, str], new_value: 'T.Any') -> bool:
return self.d[key].set_value(new_value)

# FIXME, this should be removed.or renamed to "change_type_of_existing_object" or something like that
def set_value_object(self, key: T.Union[OptionKey, str], new_object: 'UserOption[T.Any]') -> None:
def set_value_object(self, key: T.Union[OptionKey, str], new_object: AnyOptionType) -> None:
key = self.ensure_key(key)
self.d[key] = new_object

Expand All @@ -807,20 +811,20 @@ def __repr__(self) -> str:
def keys(self) -> T.KeysView[OptionKey]:
return self.d.keys()

def values(self) -> T.ValuesView[UserOption[T.Any]]:
def values(self) -> T.ValuesView[AnyOptionType]:
return self.d.values()

def items(self) -> T.ItemsView['OptionKey', 'UserOption[T.Any]']:
def items(self) -> T.ItemsView['OptionKey', AnyOptionType]:
return self.d.items()

# FIXME: this method must be deleted and users moved to use "add_xxx_option"s instead.
def update(self, **kwargs: UserOption[T.Any]) -> None:
def update(self, **kwargs: AnyOptionType) -> None:
self.d.update(**kwargs)

def setdefault(self, k: OptionKey, o: UserOption[T.Any]) -> UserOption[T.Any]:
def setdefault(self, k: OptionKey, o: AnyOptionType) -> AnyOptionType:
return self.d.setdefault(k, o)

def get(self, o: OptionKey, default: T.Optional[UserOption[T.Any]] = None) -> T.Optional[UserOption[T.Any]]:
def get(self, o: OptionKey, default: T.Optional[AnyOptionType] = None) -> T.Optional[AnyOptionType]:
return self.d.get(o, default)

def is_project_option(self, key: OptionKey) -> bool:
Expand Down

0 comments on commit 8c97002

Please sign in to comment.