treewide: string-quote the first argument to T.cast

Using future annotations, type annotations become strings at runtime and
don't impact performance. This is not possible to do with T.cast though,
because it is a function argument instead of an annotation.

Quote the type argument everywhere in order to have the same effect as
future annotations. This also allows linters to better detect in some
cases that a given import is typing-only.
This commit is contained in:
Eli Schwartz
2022-03-01 23:32:14 -05:00
parent 187dc656f4
commit a009eacc65
17 changed files with 39 additions and 37 deletions

View File

@@ -31,7 +31,6 @@ from ..interpreterbase import (
)
from ..interpreter import (
Interpreter,
StringHolder,
BooleanHolder,
IntegerHolder,
@@ -64,6 +63,9 @@ from ..mparser import (
import os, sys
import typing as T
if T.TYPE_CHECKING:
from ..interpreter import Interpreter
class DontCareObject(MesonInterpreterObject):
pass
@@ -378,15 +380,15 @@ class AstInterpreter(InterpreterBase):
mkwargs = {} # type: T.Dict[str, TYPE_nvar]
try:
if isinstance(src, str):
result = StringHolder(src, T.cast(Interpreter, self)).method_call(node.name, margs, mkwargs)
result = StringHolder(src, T.cast('Interpreter', self)).method_call(node.name, margs, mkwargs)
elif isinstance(src, bool):
result = BooleanHolder(src, T.cast(Interpreter, self)).method_call(node.name, margs, mkwargs)
result = BooleanHolder(src, T.cast('Interpreter', self)).method_call(node.name, margs, mkwargs)
elif isinstance(src, int):
result = IntegerHolder(src, T.cast(Interpreter, self)).method_call(node.name, margs, mkwargs)
result = IntegerHolder(src, T.cast('Interpreter', self)).method_call(node.name, margs, mkwargs)
elif isinstance(src, list):
result = ArrayHolder(src, T.cast(Interpreter, self)).method_call(node.name, margs, mkwargs)
result = ArrayHolder(src, T.cast('Interpreter', self)).method_call(node.name, margs, mkwargs)
elif isinstance(src, dict):
result = DictHolder(src, T.cast(Interpreter, self)).method_call(node.name, margs, mkwargs)
result = DictHolder(src, T.cast('Interpreter', self)).method_call(node.name, margs, mkwargs)
except mesonlib.MesonException:
return None

View File

@@ -328,7 +328,7 @@ class Backend:
# cast, we know what's in coredata anyway.
# TODO: if it's possible to annotate get_option or validate_option_value
# in the future we might be able to remove the cast here
return T.cast(T.Union[str, int, bool, 'WrapMode'], v)
return T.cast('T.Union[str, int, bool, WrapMode]', v)
def get_source_dir_include_args(self, target: build.BuildTarget, compiler: 'Compiler', *, absolute_path: bool = False) -> T.List[str]:
curdir = target.get_subdir()
@@ -937,7 +937,7 @@ class Backend:
commands += compiler.get_no_warn_args()
else:
# warning_level is a string, but mypy can't determine that
commands += compiler.get_warn_args(T.cast(str, self.get_option_for_target(OptionKey('warning_level'), target)))
commands += compiler.get_warn_args(T.cast('str', self.get_option_for_target(OptionKey('warning_level'), target)))
# Add -Werror if werror=true is set in the build options set on the
# command-line or default_options inside project(). This only sets the
# action to be done for warnings if/when they are emitted, so it's ok

View File

@@ -657,7 +657,7 @@ class Target(HoldableObject):
# In this case we have an already parsed and ready to go dictionary
# provided by typed_kwargs
if isinstance(opts, dict):
return T.cast(T.Dict[OptionKey, str], opts)
return T.cast('T.Dict[OptionKey, str]', opts)
result: T.Dict[OptionKey, str] = {}
overrides = stringlistify(opts)

View File

@@ -622,7 +622,7 @@ class VisualStudioLikeCPPCompilerMixin(CompilerMixinBase):
def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
# need a typeddict for this
key = OptionKey('winlibs', machine=self.for_machine, lang=self.language)
return T.cast(T.List[str], options[key].value[:])
return T.cast('T.List[str]', options[key].value[:])
def _get_options_impl(self, opts: 'KeyedOptionDictType', cpp_stds: T.List[str]) -> 'KeyedOptionDictType':
key = OptionKey('std', machine=self.for_machine, lang=self.language)

View File

@@ -176,13 +176,13 @@ def _build_external_dependency_list(name: str, env: 'Environment', for_machine:
# class method, if one exists, otherwise the list just consists of the
# constructor
if isinstance(packages[lname], type):
entry1 = T.cast(T.Type[ExternalDependency], packages[lname]) # mypy doesn't understand isinstance(..., type)
entry1 = T.cast('T.Type[ExternalDependency]', packages[lname]) # mypy doesn't understand isinstance(..., type)
if issubclass(entry1, ExternalDependency):
# TODO: somehow make mypy understand that entry1(env, kwargs) is OK...
func: T.Callable[[], 'ExternalDependency'] = lambda: entry1(env, kwargs) # type: ignore
dep = [func]
else:
entry2 = T.cast(T.Union['DependencyFactory', 'WrappedFactoryFunc'], packages[lname])
entry2 = T.cast('T.Union[DependencyFactory, WrappedFactoryFunc]', packages[lname])
dep = entry2(env, for_machine, kwargs)
return dep

View File

@@ -127,13 +127,13 @@ class _QtBase:
else:
self.qtpkgname = self.qtname
self.private_headers = T.cast(bool, kwargs.get('private_headers', False))
self.private_headers = T.cast('bool', kwargs.get('private_headers', False))
self.requested_modules = mesonlib.stringlistify(mesonlib.extract_as_list(kwargs, 'modules'))
if not self.requested_modules:
raise DependencyException('No ' + self.qtname + ' modules specified.')
self.qtmain = T.cast(bool, kwargs.get('main', False))
self.qtmain = T.cast('bool', kwargs.get('main', False))
if not isinstance(self.qtmain, bool):
raise DependencyException('"main" argument must be a boolean')

View File

@@ -216,7 +216,7 @@ class Properties:
return res
def get_java_home(self) -> T.Optional[Path]:
value = T.cast(T.Optional[str], self.properties.get('java_home'))
value = T.cast('T.Optional[str]', self.properties.get('java_home'))
return Path(value) if value else None
def __eq__(self, other: object) -> bool:

View File

@@ -88,7 +88,7 @@ class FeatureOptionHolder(ObjectHolder[coredata.UserFeatureOption]):
super().__init__(option, interpreter)
if option and option.is_auto():
# TODO: we need to case here because options is not a TypedDict
self.held_object = T.cast(coredata.UserFeatureOption, self.env.coredata.options[OptionKey('auto_features')])
self.held_object = T.cast('coredata.UserFeatureOption', self.env.coredata.options[OptionKey('auto_features')])
self.held_object.name = option.name
self.methods.update({'enabled': self.enabled_method,
'disabled': self.disabled_method,

View File

@@ -372,7 +372,7 @@ class MesonMain(MesonInterpreterObject):
static: T.Optional[bool], permissive: bool = False) -> None:
# We need the cast here as get_dep_identifier works on such a dict,
# which FuncOverrideDependency is, but mypy can't fgure that out
nkwargs = T.cast(T.Dict[str, T.Any], kwargs.copy())
nkwargs = T.cast('T.Dict[str, T.Any]', kwargs.copy())
if static is None:
del nkwargs['static']
else:

View File

@@ -62,7 +62,7 @@ def noPosargs(f: TV_func) -> TV_func:
if args:
raise InvalidArguments('Function does not take positional arguments.')
return f(*wrapped_args, **wrapped_kwargs)
return T.cast(TV_func, wrapped)
return T.cast('TV_func', wrapped)
def noKwargs(f: TV_func) -> TV_func:
@wraps(f)
@@ -71,7 +71,7 @@ def noKwargs(f: TV_func) -> TV_func:
if kwargs:
raise InvalidArguments('Function does not take keyword arguments.')
return f(*wrapped_args, **wrapped_kwargs)
return T.cast(TV_func, wrapped)
return T.cast('TV_func', wrapped)
def stringArgs(f: TV_func) -> TV_func:
@wraps(f)
@@ -84,7 +84,7 @@ def stringArgs(f: TV_func) -> TV_func:
mlog.debug('Element not a string:', str(args))
raise InvalidArguments('Arguments must be strings.')
return f(*wrapped_args, **wrapped_kwargs)
return T.cast(TV_func, wrapped)
return T.cast('TV_func', wrapped)
def noArgsFlattening(f: TV_func) -> TV_func:
setattr(f, 'no-args-flattening', True) # noqa: B010
@@ -99,7 +99,7 @@ def unholder_return(f: TV_func) -> T.Callable[..., TYPE_var]:
def wrapped(*wrapped_args: T.Any, **wrapped_kwargs: T.Any) -> T.Any:
res = f(*wrapped_args, **wrapped_kwargs)
return _unholder(res)
return T.cast(T.Callable[..., TYPE_var], wrapped)
return T.cast('T.Callable[..., TYPE_var]', wrapped)
def disablerIfNotFound(f: TV_func) -> TV_func:
@wraps(f)
@@ -110,7 +110,7 @@ def disablerIfNotFound(f: TV_func) -> TV_func:
if disabler and not ret.found():
return Disabler()
return ret
return T.cast(TV_func, wrapped)
return T.cast('TV_func', wrapped)
@dataclass(repr=False, eq=False)
class permittedKwargs:
@@ -125,7 +125,7 @@ class permittedKwargs:
ustr = ', '.join([f'"{u}"' for u in sorted(unknowns)])
raise InvalidArguments(f'Got unknown keyword arguments {ustr}')
return f(*wrapped_args, **wrapped_kwargs)
return T.cast(TV_func, wrapped)
return T.cast('TV_func', wrapped)
def typed_operator(operator: MesonOperator,
types: T.Union[T.Type, T.Tuple[T.Type, ...]]) -> T.Callable[['_TV_FN_Operator'], '_TV_FN_Operator']:
@@ -276,7 +276,7 @@ def typed_pos_args(name: str, *types: T.Union[T.Type, T.Tuple[T.Type, ...]],
nargs[i] = tuple(args)
return f(*nargs, **wrapped_kwargs)
return T.cast(TV_func, wrapper)
return T.cast('TV_func', wrapper)
return inner
@@ -521,7 +521,7 @@ def typed_kwargs(name: str, *types: KwargInfo) -> T.Callable[..., T.Any]:
node, _, _kwargs, subproject = get_callee_args(wrapped_args)
# Cast here, as the convertor function may place something other than a TYPE_var in the kwargs
kwargs = T.cast(T.Dict[str, object], _kwargs)
kwargs = T.cast('T.Dict[str, object]', _kwargs)
all_names = {t.name for t in types}
unknowns = set(kwargs).difference(all_names)
@@ -572,7 +572,7 @@ def typed_kwargs(name: str, *types: KwargInfo) -> T.Callable[..., T.Any]:
kwargs[info.name] = info.convertor(kwargs[info.name])
return f(*wrapped_args, **wrapped_kwargs)
return T.cast(TV_func, wrapper)
return T.cast('TV_func', wrapper)
return inner
@@ -664,7 +664,7 @@ class FeatureCheckBase(metaclass=abc.ABCMeta):
raise AssertionError(f'{wrapped_args!r}')
self.use(subproject, node)
return f(*wrapped_args, **wrapped_kwargs)
return T.cast(TV_func, wrapped)
return T.cast('TV_func', wrapped)
@classmethod
def single_use(cls, feature_name: str, version: str, subproject: 'SubProject',
@@ -766,7 +766,7 @@ class FeatureCheckKwargsBase(metaclass=abc.ABCMeta):
self.feature_check_class.single_use(
name, self.feature_version, subproject, self.extra_message, node)
return f(*wrapped_args, **wrapped_kwargs)
return T.cast(TV_func, wrapped)
return T.cast('TV_func', wrapped)
class FeatureNewKwargs(FeatureCheckKwargsBase):
feature_check_class = FeatureNew

View File

@@ -1182,7 +1182,7 @@ class VisualStudioLikeLinkerMixin:
def get_always_args(self) -> T.List[str]:
parent = super().get_always_args() # type: ignore
return self._apply_prefix('/nologo') + T.cast(T.List[str], parent)
return self._apply_prefix('/nologo') + T.cast('T.List[str]', parent)
def get_search_args(self, dirname: str) -> T.List[str]:
return self._apply_prefix('/LIBPATH:' + dirname)

View File

@@ -890,7 +890,7 @@ def version_compare_condition_with_min(condition: str, minimum: str) -> bool:
if re.match(r'^\d+.\d+$', condition):
condition += '.0'
return T.cast(bool, cmpop(Version(minimum), Version(condition)))
return T.cast('bool', cmpop(Version(minimum), Version(condition)))
def search_version(text: str) -> str:
# Usually of the type 4.1.4 but compiler output may contain
@@ -1336,7 +1336,7 @@ def typeslistify(item: 'T.Union[_T, T.Sequence[_T]]',
list of items all of which are of type @types
'''
if isinstance(item, types):
item = T.cast(T.List[_T], [item])
item = T.cast('T.List[_T]', [item])
if not isinstance(item, list):
raise MesonException('Item must be a list or one of {!r}, not {!r}'.format(types, type(item)))
for i in item:

View File

@@ -320,7 +320,7 @@ def _log_error(severity: str, *rargs: TV_Loggable,
location_str = get_error_location_string(location_file, location.lineno)
# Unions are frankly awful, and we have to T.cast here to get mypy
# to understand that the list concatenation is safe
location_list = T.cast(TV_LoggableList, [location_str])
location_list = T.cast('TV_LoggableList', [location_str])
args = location_list + args
log(*args, once=once, **kwargs)

View File

@@ -1168,7 +1168,7 @@ class GnomeModule(ExtensionModule):
scan_target = self._make_gir_target(
state, girfile, scan_command, generated_files, depends,
# We have to cast here because mypy can't figure this out
T.cast(T.Dict[str, T.Any], kwargs))
T.cast('T.Dict[str, T.Any]', kwargs))
typelib_output = f'{ns}-{nsversion}.typelib'
typelib_cmd = [gicompiler, scan_target, '--output', '@OUTPUT@']
@@ -1177,7 +1177,7 @@ class GnomeModule(ExtensionModule):
for incdir in typelib_includes:
typelib_cmd += ["--includedir=" + incdir]
typelib_target = self._make_typelib_target(state, typelib_output, typelib_cmd, generated_files, T.cast(T.Dict[str, T.Any], kwargs))
typelib_target = self._make_typelib_target(state, typelib_output, typelib_cmd, generated_files, T.cast('T.Dict[str, T.Any]', kwargs))
self._devenv_prepend('GI_TYPELIB_PATH', os.path.join(state.environment.get_build_dir(), state.subdir))

View File

@@ -88,7 +88,7 @@ class JavaModule(NewExtensionModule):
KwargInfo('package', str, default=None))
def generate_native_headers(self, state: ModuleState, args: T.Tuple[T.List[mesonlib.FileOrString]],
kwargs: T.Dict[str, T.Optional[str]]) -> ModuleReturnValue:
classes = T.cast(T.List[str], kwargs.get('classes'))
classes = T.cast('T.List[str]', kwargs.get('classes'))
package = kwargs.get('package')
headers: T.List[str] = []

View File

@@ -486,7 +486,7 @@ class QtBaseModule(ExtensionModule):
if _sources:
FeatureDeprecated.single_use('qt.preprocess positional sources', '0.59', state.subproject, location=state.current_node)
# List is invariant, os we have to cast...
sources = T.cast(T.List[T.Union[str, File, build.GeneratedList, build.CustomTarget]],
sources = T.cast('T.List[T.Union[str, File, build.GeneratedList, build.CustomTarget]]',
_sources + kwargs['sources'])
for s in sources:
if not isinstance(s, (str, File)):

View File

@@ -60,7 +60,7 @@ def add_arguments(parser: 'argparse.ArgumentParser') -> None:
def get_releases() -> T.Dict[str, T.Any]:
url = urlopen('https://wrapdb.mesonbuild.com/v2/releases.json')
return T.cast(T.Dict[str, T.Any], json.loads(url.read().decode()))
return T.cast('T.Dict[str, T.Any]', json.loads(url.read().decode()))
def list_projects(options: 'argparse.Namespace') -> None:
releases = get_releases()