From cd886b491626d2156ba7d0a4ba9ac2d059db1c05 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Fri, 8 May 2026 08:53:29 -0700 Subject: [PATCH 1/5] modules/hotdoc: use SubProject instead of str --- mesonbuild/modules/hotdoc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mesonbuild/modules/hotdoc.py b/mesonbuild/modules/hotdoc.py index a45fd57ecafd..9641678ac8df 100644 --- a/mesonbuild/modules/hotdoc.py +++ b/mesonbuild/modules/hotdoc.py @@ -28,7 +28,7 @@ from . import ModuleState from ..environment import Environment from ..interpreter import Interpreter - from ..interpreterbase import TYPE_kwargs, TYPE_var + from ..interpreterbase import TYPE_kwargs, TYPE_var, SubProject _T = T.TypeVar('_T') @@ -365,7 +365,7 @@ def config_path_method(self, *args: T.Any, **kwargs: T.Any) -> str: class HotdocTarget(CustomTarget): - def __init__(self, name: str, subdir: str, subproject: str, hotdoc_conf: File, + def __init__(self, name: str, subdir: str, subproject: SubProject, hotdoc_conf: File, extra_extension_paths: T.Set[str], extra_assets: T.List[str], subprojects: T.List['HotdocTarget'], environment: Environment, **kwargs: T.Any): super().__init__(name, subdir, subproject, environment, **kwargs, absolute_paths=True) From 9afb4a626dad4c85d7394536a6f12798b7098f1d Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Fri, 8 May 2026 08:53:49 -0700 Subject: [PATCH 2/5] modules/hotdoc: Add assert for option values --- mesonbuild/modules/hotdoc.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mesonbuild/modules/hotdoc.py b/mesonbuild/modules/hotdoc.py index 9641678ac8df..7992e111c4cf 100644 --- a/mesonbuild/modules/hotdoc.py +++ b/mesonbuild/modules/hotdoc.py @@ -329,7 +329,11 @@ def make_targets(self) -> T.Tuple[HotdocTarget, mesonlib.ExecutableSerialisation install_script = None if install: - datadir = os.path.join(self.state.get_option('prefix'), self.state.get_option('datadir')) + prefix = self.state.get_option('prefix') + assert isinstance(prefix, str), 'for mypy' + datadir = self.state.get_option('datadir') + assert isinstance(datadir, str), 'for mypy' + datadir = os.path.join(prefix, datadir) devhelp = self.kwargs.get('devhelp_activate', False) if not isinstance(devhelp, bool): FeatureDeprecated.single_use('hotdoc.generate_doc() devhelp_activate must be boolean', '1.1.0', self.state.subproject) From 8134313923f060af0e4e5ea7181fe9b4f794f088 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Fri, 8 May 2026 08:58:32 -0700 Subject: [PATCH 3/5] modules/hotdoc: Fix missing and incorrect annotations Also, remove the unused HotdocTargetBuilder.extra_assets --- mesonbuild/modules/hotdoc.py | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/mesonbuild/modules/hotdoc.py b/mesonbuild/modules/hotdoc.py index 7992e111c4cf..99097d5d3499 100644 --- a/mesonbuild/modules/hotdoc.py +++ b/mesonbuild/modules/hotdoc.py @@ -28,6 +28,7 @@ from . import ModuleState from ..environment import Environment from ..interpreter import Interpreter + from ..interpreter.kwargs import TargetDepends from ..interpreterbase import TYPE_kwargs, TYPE_var, SubProject _T = T.TypeVar('_T') @@ -64,7 +65,7 @@ def run_hotdoc(self, cmd: T.List[str]) -> int: class HotdocTargetBuilder: - def __init__(self, name: str, state: ModuleState, hotdoc: HotdocExternalProgram, interpreter: Interpreter, kwargs): + def __init__(self, name: str, state: ModuleState, hotdoc: HotdocExternalProgram, interpreter: Interpreter, kwargs: GenerateDocKwargs): self.hotdoc = hotdoc self.build_by_default = kwargs.pop('build_by_default', False) self.kwargs = kwargs @@ -81,10 +82,9 @@ def __init__(self, name: str, state: ModuleState, hotdoc: HotdocExternalProgram, self.cmd: T.List[TYPE_var] = ['conf', '--project-name', name, "--disable-incremental-build", '--output', os.path.join(self.builddir, self.subdir, self.name + '-doc')] - self._extra_extension_paths = set() - self.extra_assets = set() - self.extra_depends = [] - self._subprojects = [] + self._extra_extension_paths: set[str] = set() + self.extra_depends: list[build.BuildTargetTypes] = [] + self._subprojects: list[HotdocTarget] = [] def process_known_arg(self, option: str, argname: T.Optional[str] = None, value_processor: T.Optional[T.Callable] = None) -> None: if not argname: @@ -169,7 +169,9 @@ def process_gi_c_source_roots(self) -> None: self.cmd += ['--gi-c-source-roots'] + value - def process_dependencies(self, deps: T.List[T.Union[Dependency, build.StaticLibrary, build.SharedLibrary, CustomTarget, CustomTargetIndex]]) -> T.List[str]: + def process_dependencies(self, deps: T.Sequence[TargetDepends | Dependency | File | build.ExtractedObjects | build.StructuredSources]) -> T.List[str]: + # build.StructuredSources and build.ExtractedObjects shouldn't actually + # happen here, but we get them from Dependency. cflags = set() for dep in mesonlib.listify(ensure_list(deps)): if isinstance(dep, InternalDependency): @@ -241,9 +243,18 @@ def generate_hotdoc_config(self) -> None: raise MesonException('hotdoc failed to configure') os.chdir(cwd) - def ensure_file(self, value: T.Union[str, File, CustomTarget, CustomTargetIndex]) -> T.Union[File, CustomTarget, CustomTargetIndex]: + @T.overload + def ensure_file(self, value: list[str | File | CustomTarget | CustomTargetIndex] + ) -> list[File | CustomTarget | CustomTargetIndex]: ... + + @T.overload + def ensure_file(self, value: str | File | CustomTarget | CustomTargetIndex + ) -> File | CustomTarget | CustomTargetIndex: ... + + def ensure_file(self, value: str | File | CustomTarget | CustomTargetIndex | list[str | File | CustomTarget | CustomTargetIndex] + ) -> File | CustomTarget | CustomTargetIndex | list[File | CustomTarget | CustomTargetIndex]: if isinstance(value, list): - res = [] + res: list[File | CustomTarget | CustomTargetIndex] = [] for val in value: res.append(self.ensure_file(val)) return res From 99096dc7560865674e0b4ab99ec7882bdf7a3f98 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Fri, 8 May 2026 09:17:15 -0700 Subject: [PATCH 4/5] modules/hotdoc: fix issues with the kwargs the TypedDict Mainly this is due to deleting fields (requires Total=False), and the fact that Python cannot (yet) represent arbitrary keys. I've just type: ignored those issues for now and we can revisit when PEP 728 is implemented and Python can represent that. Also, make the build_by_default parameter explicit --- mesonbuild/modules/hotdoc.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/mesonbuild/modules/hotdoc.py b/mesonbuild/modules/hotdoc.py index 99097d5d3499..5a2715b9adb3 100644 --- a/mesonbuild/modules/hotdoc.py +++ b/mesonbuild/modules/hotdoc.py @@ -33,7 +33,12 @@ _T = T.TypeVar('_T') - class GenerateDocKwargs(TypedDict): + # there is currently no way to represent the arbitrary key/value paris that + # the hotdoc module allows. + # + # PEP-728, which is due in Python 3.15, will fix this, we can then add a new + # extra_items=str keyword argument. + class GenerateDocKwargs(TypedDict, total=False): sitemap: T.Union[str, File, CustomTarget, CustomTargetIndex] index: T.Union[str, File, CustomTarget, CustomTargetIndex] project_version: str @@ -46,6 +51,8 @@ class GenerateDocKwargs(TypedDict): extra_extension_paths: T.List[str] subprojects: T.List['HotdocTarget'] install: bool + build_by_default: bool + def ensure_list(value: T.Union[_T, T.List[_T]]) -> T.List[_T]: if not isinstance(value, list): @@ -90,7 +97,7 @@ def process_known_arg(self, option: str, argname: T.Optional[str] = None, value_ if not argname: argname = option.strip("-").replace("-", "_") - value = self.kwargs.pop(argname) + value = self.kwargs.pop(argname) # type: ignore[misc] if value is not None and value_processor: value = value_processor(value) @@ -143,8 +150,8 @@ def check_extra_arg_type(self, arg: str, value: TYPE_var) -> None: def process_extra_args(self) -> None: for arg, value in self.kwargs.items(): option = "--" + arg.replace("_", "-") - self.check_extra_arg_type(arg, value) - self.set_arg_value(option, value) + self.check_extra_arg_type(arg, value) # type: ignore[arg-type] + self.set_arg_value(option, value) # type: ignore[arg-type] def add_extension_paths(self, paths: T.Union[T.List[str], T.Set[str]]) -> None: for path in paths: @@ -448,6 +455,7 @@ def has_extensions(self, state: ModuleState, args: T.Tuple[T.List[str]], kwargs: KwargInfo('extra_extension_paths', ContainerTypeInfo(list, str), listify=True, default=[]), KwargInfo('subprojects', ContainerTypeInfo(list, HotdocTarget), listify=True, default=[]), KwargInfo('install', bool, default=False), + KwargInfo('build_by_default', bool, default=False), allow_unknown=True ) def generate_doc(self, state: ModuleState, args: T.Tuple[str], kwargs: GenerateDocKwargs) -> ModuleReturnValue: From 5f94c011fda23e89fdf14921f3387a72c86daf58 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Fri, 8 May 2026 09:22:39 -0700 Subject: [PATCH 5/5] run_mypy: all modules are now type safe! --- run_mypy.py | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/run_mypy.py b/run_mypy.py index 7a6d29c699ce..224c3119a9ca 100755 --- a/run_mypy.py +++ b/run_mypy.py @@ -22,6 +22,7 @@ 'mesonbuild/interpreter/primitives/', 'mesonbuild/interpreterbase/', 'mesonbuild/linkers/', + 'mesonbuild/modules/', 'mesonbuild/scripts/', 'mesonbuild/templates/', 'mesonbuild/utils/', @@ -54,32 +55,6 @@ 'mesonbuild/mintro.py', 'mesonbuild/mlog.py', 'mesonbuild/msubprojects.py', - 'mesonbuild/modules/__init__.py', - 'mesonbuild/modules/cmake.py', - 'mesonbuild/modules/codegen.py', - 'mesonbuild/modules/cuda.py', - 'mesonbuild/modules/dlang.py', - 'mesonbuild/modules/external_project.py', - 'mesonbuild/modules/fs.py', - 'mesonbuild/modules/gnome.py', - 'mesonbuild/modules/i18n.py', - 'mesonbuild/modules/icestorm.py', - 'mesonbuild/modules/java.py', - 'mesonbuild/modules/keyval.py', - 'mesonbuild/modules/modtest.py', - 'mesonbuild/modules/pkgconfig.py', - 'mesonbuild/modules/python.py', - 'mesonbuild/modules/python3.py', - 'mesonbuild/modules/_qt.py', - 'mesonbuild/modules/qt4.py', - 'mesonbuild/modules/qt5.py', - 'mesonbuild/modules/qt6.py', - 'mesonbuild/modules/rust.py', - 'mesonbuild/modules/simd.py', - 'mesonbuild/modules/snippets.py', - 'mesonbuild/modules/sourceset.py', - 'mesonbuild/modules/wayland.py', - 'mesonbuild/modules/windows.py', 'mesonbuild/mparser.py', 'mesonbuild/msetup.py', 'mesonbuild/mtest.py',