pmb: Add more type hints (MR 2513)

And fix some consequential type errors.

[ci:skip-build]: already built successfully in CI
This commit is contained in:
Newbyte 2024-12-19 18:49:49 +01:00
parent c8194302fc
commit 0925b3e425
No known key found for this signature in database
GPG key ID: ACD854892B38D898
12 changed files with 69 additions and 19 deletions

View file

@ -8,7 +8,7 @@ from pmb.core.arch import Arch
from pmb.core.context import Context
from pmb.core.pkgrepo import pkgrepo_relative_path
from pmb.helpers import logging
from pmb.types import CrossCompileType
from pmb.types import Apkbuild, CrossCompileType
from pathlib import Path
import pmb.build
@ -187,7 +187,7 @@ def is_cached_or_cache(arch: Arch, pkgname: str) -> bool:
return visited
def get_apkbuild(pkgname):
def get_apkbuild(pkgname: str) -> tuple[Path | None, Apkbuild | None]:
"""Parse the APKBUILD path for pkgname.
When there is none, try to find it in the binary package APKINDEX files or raise an exception.
@ -580,7 +580,7 @@ def packages(
for pkgname in pmb.config.build_packages:
if pkgname not in pkgnames:
aport, apkbuild = get_apkbuild(pkgname)
if not aport:
if not aport or not apkbuild:
continue
bstatus = pmb.build.get_status(arch, apkbuild)
if bstatus.necessary():

View file

@ -4,7 +4,6 @@ import enum
from pmb.helpers import logging
import os
from pathlib import Path
from typing import Any
import shlex
import datetime
@ -20,6 +19,7 @@ import pmb.parse.version
from pmb.core import Chroot
from pmb.core.arch import Arch
from pmb.core.context import get_context
from pmb.types import Apkbuild
def copy_to_buildpath(
@ -81,7 +81,7 @@ class BuildStatus(enum.Enum):
return self in [BuildStatus.OUTDATED, BuildStatus.NEW]
def get_status(arch: Arch | None, apkbuild: dict[str, Any]) -> BuildStatus:
def get_status(arch: Arch | None, apkbuild: Apkbuild) -> BuildStatus:
"""Check if the package has already been built.
Compared to abuild's check, this check also works for different architectures.

View file

@ -83,7 +83,7 @@ def init_usr_merge(chroot: Chroot) -> None:
@Cache()
def warn_if_chroots_outdated():
def warn_if_chroots_outdated() -> None:
outdated = pmb.config.workdir.chroots_outdated()
if outdated:
days_warn = int(pmb.config.chroot_outdated / 3600 / 24)

View file

@ -13,11 +13,11 @@ class Log(commands.Command):
clear_log: bool
lines: int
def __init__(self, clear_log: bool, lines: int):
def __init__(self, clear_log: bool, lines: int) -> None:
self.clear_log = clear_log
self.lines = lines
def run(self):
def run(self) -> None:
context = get_context()
log_testsuite = pmb.config.pmb_src / ".pytest_tmp/log_testsuite.txt"

View file

@ -58,7 +58,9 @@ def replace_apkbuild(
)
def is_up_to_date(path_sources, path_target=None, lastmod_target=None):
def is_up_to_date(
path_sources: list[Path], path_target: Path | None = None, lastmod_target: float | None = None
) -> bool:
"""Check if a file is up-to-date by comparing the last modified timestamps.
(just like make does it).
@ -81,6 +83,9 @@ def is_up_to_date(path_sources, path_target=None, lastmod_target=None):
if path_target:
lastmod_target = os.path.getmtime(path_target)
if lastmod_target is None or lastmod_source is None:
raise AssertionError
return lastmod_target >= lastmod_source

View file

@ -285,6 +285,8 @@ def config(args: PmbArgs) -> None:
def repo_missing(args: PmbArgs) -> None:
if args.arch is None or isinstance(args.package, list):
raise AssertionError
missing = pmb.helpers.repo_missing.generate(args.arch, args.overview, args.package, args.built)
print(json.dumps(missing, indent=4))

View file

@ -34,7 +34,7 @@ class log_handler(logging.StreamHandler):
self.styles = pmb.config.styles
def emit(self, record):
def emit(self, record: logging.LogRecord) -> None:
try:
msg = self.format(record)

View file

@ -12,8 +12,8 @@ from pmb.core.arch import Arch
from pmb.core.pkgrepo import pkgrepo_iter_package_dirs
from pmb.helpers import logging
from pathlib import Path
from typing import Any
from pmb.types import WithExtraRepos
from typing import overload, Any, Literal
from pmb.types import Apkbuild, WithExtraRepos
from pmb.meta import Cache
import pmb.parse
@ -260,7 +260,7 @@ def get_with_path(
must_exist: bool = True,
subpackages: bool = True,
with_extra_repos: WithExtraRepos = "default",
) -> tuple[Path | None, dict[str, Any] | None]:
) -> tuple[Path | None, Apkbuild | None]:
"""Find and parse an APKBUILD file.
Run 'pmbootstrap apkbuild_parse hello-world' for a full output example.
@ -288,12 +288,30 @@ def get_with_path(
return None, None
@overload
def get(
pkgname: str,
must_exist: Literal[True] = ...,
subpackages: bool = ...,
with_extra_repos: WithExtraRepos = ...,
) -> Apkbuild: ...
@overload
def get(
pkgname: str,
must_exist: bool = ...,
subpackages: bool = ...,
with_extra_repos: WithExtraRepos = ...,
) -> Apkbuild | None: ...
def get(
pkgname: str,
must_exist: bool = True,
subpackages: bool = True,
with_extra_repos: WithExtraRepos = "default",
) -> dict[str, Any]:
) -> Apkbuild | None:
return get_with_path(pkgname, must_exist, subpackages, with_extra_repos)[1]

View file

@ -1,6 +1,8 @@
# Copyright 2023 Oliver Smith
# SPDX-License-Identifier: GPL-3.0-or-later
from typing import overload, Literal
from pmb.core.arch import Arch
from pmb.helpers import logging
from pmb.types import Apkbuild
@ -126,7 +128,27 @@ def generate_output_format(arch: Arch, pkgnames: list[str]) -> list[Apkbuild]:
return ret
def generate(arch, overview, pkgname=None, built=False):
@overload
def generate(
arch: Arch, overview: Literal[False], pkgname: str | None = ..., built: bool = ...
) -> list[Apkbuild]: ...
@overload
def generate(
arch: Arch, overview: Literal[True], pkgname: str | None = ..., built: bool = ...
) -> list[str]: ...
@overload
def generate(
arch: Arch, overview: bool, pkgname: str | None = ..., built: bool = ...
) -> list[Apkbuild] | list[str]: ...
def generate(
arch: Arch, overview: bool, pkgname: str | None = None, built: bool = False
) -> list[Apkbuild] | list[str]:
"""Get packages that need to be built, with all their dependencies.
:param arch: architecture (e.g. "armhf")

View file

@ -4,6 +4,7 @@ import argparse
import os
from pathlib import Path
import sys
from typing import cast
from pmb.core.arch import Arch
from pmb.core import Config
@ -827,7 +828,7 @@ def add_kernel_arg(subparser, name="package", nargs="?", *args, **kwargs):
arg.completer = kernel_completer
def get_parser():
def get_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(prog="pmbootstrap")
arch_native = Arch.native()
arch_choices = Arch.supported()
@ -1297,7 +1298,8 @@ def get_parser():
def arguments() -> PmbArgs:
args: PmbArgs = get_parser().parse_args()
# FIXME: It would be nice to not use cast here, but I don't know what else we could do.
args = cast(PmbArgs, get_parser().parse_args())
if getattr(args, "fork_alpine_retain_branch", False):
# fork_alpine_retain_branch largely matches the behaviour of fork_alpine, so

View file

@ -18,7 +18,7 @@ from pmb.meta import Cache
# to specify which one they're using.
# Basically: treat Deviceinfo as a standalone type that
# doesn't need to traverse pmaports.
def _parse_kernel_suffix(info, device, kernel):
def _parse_kernel_suffix(info: dict[str, str], device: str, kernel: str | None) -> dict[str, str]:
"""
Remove the kernel suffix (as selected in 'pmbootstrap init') from
deviceinfo variables. Related:

View file

@ -12,6 +12,7 @@ import re
import signal
import shlex
import shutil
from types import FrameType
import pmb.build
import pmb.chroot
@ -327,7 +328,7 @@ def resize_image(img_size_new: str, img_path: Path) -> None:
raise RuntimeError(f"IMAGE_SIZE must be {img_size_str} or greater")
def sigterm_handler(number, frame):
def sigterm_handler(number: int, stack_frame: FrameType | None) -> None:
raise RuntimeError(
"pmbootstrap was terminated by another process, and killed the QEMU VM it was running."
)