From: Joerg Behrmann Date: Fri, 13 Jan 2023 09:20:45 +0000 (+0100) Subject: Update typing to use generics for standard container classes X-Git-Tag: v15~366^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=53a18f599891ee7b138f4892cbdd4a06c486f69b;p=thirdparty%2Fmkosi.git Update typing to use generics for standard container classes Also use the non-deprecated typing imports --- diff --git a/mkosi/__init__.py b/mkosi/__init__.py index 512a777ae..db7b12b6c 100644 --- a/mkosi/__init__.py +++ b/mkosi/__init__.py @@ -29,6 +29,7 @@ import sys import tempfile import time import uuid +from collections.abc import Iterable, Iterator, Sequence from pathlib import Path from textwrap import dedent, wrap from typing import ( @@ -36,16 +37,9 @@ from typing import ( Any, BinaryIO, Callable, - Dict, - Iterable, - Iterator, - List, NoReturn, Optional, - Sequence, - Set, TextIO, - Tuple, TypeVar, Union, cast, @@ -375,7 +369,7 @@ def prepare_tree(state: MkosiState, cached: bool) -> None: state.root.joinpath("etc/kernel/install.conf").write_text("layout=bls\n") -def flatten(lists: Iterable[Iterable[T]]) -> List[T]: +def flatten(lists: Iterable[Iterable[T]]) -> list[T]: """Flatten a sequence of sequences into a single list.""" return list(itertools.chain.from_iterable(lists)) @@ -601,7 +595,7 @@ def configure_root_password(state: MkosiState, cached: bool) -> None: patch_file(state.root / "etc/shadow", set_root_pw) -def pam_add_autologin(root: Path, ttys: List[str]) -> None: +def pam_add_autologin(root: Path, ttys: list[str]) -> None: login = root / "etc/pam.d/login" original = login.read_text() if login.exists() else "" @@ -666,7 +660,7 @@ def nspawn_id_map_supported() -> bool: return ret.returncode == 0 -def nspawn_params_for_build_sources(config: MkosiConfig, sft: SourceFileTransfer) -> List[str]: +def nspawn_params_for_build_sources(config: MkosiConfig, sft: SourceFileTransfer) -> list[str]: params = ["--setenv=SRCDIR=/root/src", "--chdir=/root/src"] if sft == SourceFileTransfer.mount: @@ -772,7 +766,7 @@ def copy_git_files(src: Path, dest: Path, *, source_file_transfer: SourceFileTra uid = int(os.getenv("SUDO_UID", 0)) c = run(["git", "-C", src, "ls-files", "-z", *what_files], stdout=subprocess.PIPE, text=False, user=uid) - files: Set[str] = {x.decode("utf-8") for x in c.stdout.rstrip(b"\0").split(b"\0")} + files = {x.decode("utf-8") for x in c.stdout.rstrip(b"\0").split(b"\0")} # Add the .git/ directory in as well. if source_file_transfer == SourceFileTransfer.copy_git_more: @@ -885,7 +879,7 @@ def xz_binary() -> str: return "pxz" if shutil.which("pxz") else "xz" -def compressor_command(option: Union[str, bool], src: Path) -> List[PathString]: +def compressor_command(option: Union[str, bool], src: Path) -> list[PathString]: """Returns a command suitable for compressing archives.""" if option == "xz": @@ -915,7 +909,7 @@ def make_tar(state: MkosiState) -> None: if state.for_cache: return - cmd: List[PathString] = [tar_binary(), "-C", state.root, "-c", "--xattrs", "--xattrs-include=*"] + cmd: list[PathString] = [tar_binary(), "-C", state.root, "-c", "--xattrs", "--xattrs-include=*"] if state.config.tar_strip_selinux_context: cmd += ["--xattrs-exclude=security.selinux"] @@ -941,7 +935,7 @@ def make_cpio(state: MkosiState) -> None: with complete_step("Creating archive…"), open(state.staging / state.config.output.name, "wb") as f: files = find_files(state.root) - cmd: List[PathString] = [ + cmd: list[PathString] = [ "cpio", "-o", "--reproducible", "--null", "-H", "newc", "--quiet", "-D", state.root ] @@ -963,7 +957,7 @@ def make_directory(state: MkosiState) -> None: os.rename(state.root, state.staging / state.config.output.name) -def gen_kernel_images(state: MkosiState) -> Iterator[Tuple[str, Path]]: +def gen_kernel_images(state: MkosiState) -> Iterator[tuple[str, Path]]: # Apparently openmandriva hasn't yet completed its usrmerge so we use lib here instead of usr/lib. if not state.root.joinpath("lib/modules").exists(): return @@ -1051,7 +1045,7 @@ def install_unified_kernel(state: MkosiState, label: Optional[str], root_hash: O option = "mount.usr" if usr_only else "root" boot_options = f"{boot_options} {option}=LABEL={label}" - cmd: List[PathString] = [ + cmd: list[PathString] = [ "ukify", "--cmdline", boot_options, "--os-release", f"@{state.root / 'usr/lib/os-release'}", @@ -1184,7 +1178,7 @@ def calculate_signature(state: MkosiState) -> None: return None with complete_step("Signing SHA256SUMS…"): - cmdline: List[PathString] = [ + cmdline: list[PathString] = [ "gpg", "--detach-sign", "-o", state.staging / state.config.output_signature.name, @@ -1205,7 +1199,7 @@ def calculate_bmap(state: MkosiState) -> None: return with complete_step("Creating BMAP file…"): - cmdline: List[PathString] = [ + cmdline: list[PathString] = [ "bmaptool", "create", "--output", state.staging / state.config.output_bmap.name, @@ -1277,7 +1271,7 @@ def setup_package_cache(config: MkosiConfig, workspace: Path) -> Path: return cache -def remove_duplicates(items: List[T]) -> List[T]: +def remove_duplicates(items: list[T]) -> list[T]: "Return list with any repetitions removed" # We use a dictionary to simulate an ordered set return list({x: None for x in items}) @@ -1470,7 +1464,7 @@ class CustomHelpFormatter(argparse.HelpFormatter): args_string = self._format_args(action, default) return ", ".join(action.option_strings) + " " + args_string - def _split_lines(self, text: str, width: int) -> List[str]: + def _split_lines(self, text: str, width: int) -> list[str]: """Wraps text to width, each line separately. If the first line of text ends in a colon, we assume that this is a list of option descriptions, and subindent them. @@ -1539,7 +1533,7 @@ class ArgumentParserMkosi(argparse.ArgumentParser): def _ini_key_to_cli_arg(cls, key: str) -> str: return cls.SPECIAL_MKOSI_DEFAULT_PARAMS.get(key) or ("--" + cls._camel_to_arg(key)) - def _read_args_from_files(self, arg_strings: List[str]) -> List[str]: + def _read_args_from_files(self, arg_strings: list[str]) -> list[str]: """Convert @-prefixed command line arguments with corresponding file content Regular arguments are just returned. Arguments prefixed with @ are considered @@ -1622,7 +1616,7 @@ def parse_base_packages(value: str) -> Union[str, bool]: return parse_boolean(value) -def parse_remove_files(value: str) -> List[str]: +def parse_remove_files(value: str) -> list[str]: """Normalize paths as relative to / to ensure we don't go outside of our root.""" # os.path.normpath() leaves leading '//' untouched, even though it normalizes '///'. @@ -2353,7 +2347,7 @@ def load_distribution(args: argparse.Namespace) -> argparse.Namespace: return args -def parse_args(argv: Optional[Sequence[str]] = None) -> Dict[str, argparse.Namespace]: +def parse_args(argv: Optional[Sequence[str]] = None) -> dict[str, argparse.Namespace]: """Load config values from files and parse command line arguments Do all about config files and command line arguments parsing. If --all argument is passed @@ -2440,7 +2434,7 @@ def parse_args(argv: Optional[Sequence[str]] = None) -> Dict[str, argparse.Names return args_all -def parse_args_file(argv: List[str], config_path: Path) -> argparse.Namespace: +def parse_args_file(argv: list[str], config_path: Path) -> argparse.Namespace: """Parse just one mkosi.* file (--all mode).""" # Parse all parameters handled by mkosi. @@ -2451,7 +2445,7 @@ def parse_args_file(argv: List[str], config_path: Path) -> argparse.Namespace: def parse_args_file_group( - argv: List[str], config_path: Path, distribution: Optional[Distribution] = None + argv: list[str], config_path: Path, distribution: Optional[Distribution] = None ) -> argparse.Namespace: """Parse a set of mkosi config files""" # Add the @ prefixed filenames to current argument list in inverse priority order. @@ -2510,7 +2504,7 @@ def parse_bytes(num_bytes: Optional[str], *, sector_size: int = 512) -> int: def remove_glob(*patterns: PathString) -> None: pathgen = (glob.glob(str(pattern)) for pattern in patterns) - paths: Set[str] = set(sum(pathgen, [])) # uniquify + paths: set[str] = set(sum(pathgen, [])) # uniquify for path in paths: unlink_try_hard(Path(path)) @@ -3449,11 +3443,11 @@ def invoke_repart( state: MkosiState, skip: Sequence[str] = [], split: bool = False, -) -> Tuple[Optional[str], Optional[str], bool]: +) -> tuple[Optional[str], Optional[str], bool]: if not state.config.output_format == OutputFormat.disk or state.for_cache or state.do_run_build_script: return (None, None, False) - cmdline: List[PathString] = [ + cmdline: list[PathString] = [ "systemd-repart", "--empty=allow", "--size=auto", @@ -3885,7 +3879,7 @@ def find_qemu_binary(config: MkosiConfig) -> str: die("Couldn't find QEMU/KVM binary") -def find_qemu_firmware(config: MkosiConfig) -> Tuple[Path, bool]: +def find_qemu_firmware(config: MkosiConfig) -> tuple[Path, bool]: FIRMWARE_LOCATIONS = { "x86_64": ["/usr/share/ovmf/x64/OVMF_CODE.secboot.fd"], "i386": [ @@ -4023,7 +4017,7 @@ def run_qemu(config: MkosiConfig) -> None: else: machine = f"type=q35,accel={accel},smm={smm}" - cmdline: List[PathString] = [ + cmdline: list[PathString] = [ find_qemu_binary(config), "-machine", machine, @@ -4126,7 +4120,7 @@ def interface_exists(dev: str) -> bool: return rc == 0 -def find_address(config: MkosiConfig) -> Tuple[str, str]: +def find_address(config: MkosiConfig) -> tuple[str, str]: if not ensure_networkd(config) and config.ssh_port != 22: return "", "127.0.0.1" @@ -4250,7 +4244,7 @@ def generate_secure_boot_key(config: MkosiConfig) -> None: ) ) - cmd: List[PathString] = [ + cmd: list[PathString] = [ "openssl", "req", "-new", @@ -4293,7 +4287,7 @@ def bump_image_version(config: MkosiConfig) -> None: Path("mkosi.version").write_text(new_version + "\n") -def expand_paths(paths: Sequence[str]) -> List[Path]: +def expand_paths(paths: Sequence[str]) -> list[Path]: if not paths: return [] diff --git a/mkosi/__main__.py b/mkosi/__main__.py index d67f9f67e..fd5d7482c 100644 --- a/mkosi/__main__.py +++ b/mkosi/__main__.py @@ -4,8 +4,8 @@ import contextlib import os import sys +from collections.abc import Iterator from subprocess import CalledProcessError -from typing import Iterator from mkosi import complete_step, parse_args, run_verb from mkosi.backend import MkosiException, die diff --git a/mkosi/backend.py b/mkosi/backend.py index 3f0847ecb..53f24e4df 100644 --- a/mkosi/backend.py +++ b/mkosi/backend.py @@ -20,6 +20,7 @@ import subprocess import sys import tarfile import uuid +from collections.abc import Iterable, Iterator, Mapping, Sequence from pathlib import Path from types import FrameType from typing import ( @@ -28,17 +29,8 @@ from typing import ( Any, Callable, Deque, - Dict, - Iterable, - Iterator, - List, - Mapping, NoReturn, Optional, - Sequence, - Set, - Tuple, - Type, TypeVar, Union, cast, @@ -95,7 +87,7 @@ class MkosiNotSupportedException(MkosiException): # This global should be initialized after parsing arguments -ARG_DEBUG: Set[str] = set() +ARG_DEBUG: set[str] = set() class Parseable: @@ -114,7 +106,7 @@ class Parseable: raise argparse.ArgumentTypeError(f"unknown Format: {name!r}") @classmethod - def parse_list(cls: Any, string: str) -> List[Any]: + def parse_list(cls: Any, string: str) -> list[Any]: return [cls.from_string(p) for p in string.split(",") if p] @@ -174,15 +166,15 @@ class Distribution(enum.Enum): return self.name -def dictify(f: Callable[..., Iterator[Tuple[T, V]]]) -> Callable[..., Dict[T, V]]: - def wrapper(*args: Any, **kwargs: Any) -> Dict[T, V]: +def dictify(f: Callable[..., Iterator[tuple[T, V]]]) -> Callable[..., dict[T, V]]: + def wrapper(*args: Any, **kwargs: Any) -> dict[T, V]: return dict(f(*args, **kwargs)) return functools.update_wrapper(wrapper, f) @dictify -def read_os_release() -> Iterator[Tuple[str, str]]: +def read_os_release() -> Iterator[tuple[str, str]]: try: filename = "/etc/os-release" f = open(filename) @@ -204,7 +196,7 @@ def read_os_release() -> Iterator[Tuple[str, str]]: print(f"{filename}:{line_number}: bad line {line!r}", file=sys.stderr) -def detect_distribution() -> Tuple[Optional[Distribution], Optional[str]]: +def detect_distribution() -> tuple[Optional[Distribution], Optional[str]]: try: os_release = read_os_release() except FileNotFoundError: @@ -280,7 +272,7 @@ class SourceFileTransfer(enum.Enum): return self.value @classmethod - def doc(cls) -> Dict["SourceFileTransfer", str]: + def doc(cls) -> dict["SourceFileTransfer", str]: return { cls.copy_all: "normal file copy", cls.copy_git_cached: "use git ls-files --cached, ignoring any file that git itself ignores", @@ -333,7 +325,7 @@ class MkosiConfig: """ verb: Verb - cmdline: List[str] + cmdline: list[str] force: int distribution: Distribution @@ -341,17 +333,17 @@ class MkosiConfig: mirror: Optional[str] local_mirror: Optional[str] repository_key_check: bool - repositories: List[str] + repositories: list[str] use_host_repositories: bool repos_dir: Optional[str] repart_dir: Optional[str] architecture: str output_format: OutputFormat - manifest_format: List[ManifestFormat] + manifest_format: list[ManifestFormat] output: Path output_dir: Optional[Path] bootable: bool - kernel_command_line: List[str] + kernel_command_line: list[str] secure_boot: bool secure_boot_key: Path secure_boot_certificate: Path @@ -369,21 +361,21 @@ class MkosiConfig: incremental: bool cache_initrd: bool base_packages: Union[str, bool] - packages: List[str] - remove_packages: List[str] + packages: list[str] + remove_packages: list[str] with_docs: bool with_tests: bool cache_path: Path - extra_trees: List[Path] - skeleton_trees: List[Path] + extra_trees: list[Path] + skeleton_trees: list[Path] clean_package_metadata: Union[bool, str] - remove_files: List[Path] - environment: Dict[str, str] + remove_files: list[Path] + environment: dict[str, str] build_sources: Path build_dir: Optional[Path] include_dir: Optional[Path] install_dir: Optional[Path] - build_packages: List[str] + build_packages: list[str] skip_final_phase: bool build_script: Optional[Path] prepare_script: Optional[Path] @@ -404,7 +396,7 @@ class MkosiConfig: password: Optional[str] password_is_hashed: bool autologin: bool - extra_search_paths: List[Path] + extra_search_paths: list[Path] netdev: bool ephemeral: bool ssh: bool @@ -412,12 +404,12 @@ class MkosiConfig: ssh_agent: Optional[Path] ssh_timeout: int ssh_port: int - credentials: Dict[str, str] + credentials: dict[str, str] directory: Optional[Path] config_path: Optional[Path] all: bool all_directory: Optional[Path] - debug: List[str] + debug: list[str] auto_bump: bool workspace_dir: Optional[Path] machine_id: Optional[str] @@ -469,7 +461,7 @@ class MkosiConfig: def output_changelog(self) -> Path: return build_auxiliary_output_path(self, ".changelog") - def output_paths(self) -> Tuple[Path, ...]: + def output_paths(self) -> tuple[Path, ...]: return ( self.output, self.output_split_kernel, @@ -498,7 +490,7 @@ class MkosiState: do_run_build_script: bool machine_id: str for_cache: bool - environment: Dict[str, str] = dataclasses.field(init=False) + environment: dict[str, str] = dataclasses.field(init=False) installer: DistributionInstaller = dataclasses.field(init=False) def __post_init__(self) -> None: @@ -584,7 +576,7 @@ def run_workspace_command( cmd: Sequence[PathString], network: bool = False, env: Optional[Mapping[str, str]] = None, - nspawn_params: Optional[List[str]] = None, + nspawn_params: Optional[list[str]] = None, capture_stdout: bool = False, check: bool = True, ) -> CompletedProcess: @@ -745,7 +737,7 @@ def path_relative_to_cwd(path: PathString) -> Path: return path -def die(message: str, exception: Type[MkosiException] = MkosiException) -> NoReturn: +def die(message: str, exception: type[MkosiException] = MkosiException) -> NoReturn: MkosiPrinter.warn(f"Error: {message}") raise exception(message) @@ -796,12 +788,12 @@ class MkosiPrinter: @classmethod @contextlib.contextmanager - def complete_step(cls, text: str, text2: Optional[str] = None) -> Iterator[List[Any]]: + def complete_step(cls, text: str, text2: Optional[str] = None) -> Iterator[list[Any]]: cls.print_step(text) cls.level += 1 try: - args: List[Any] = [] + args: list[Any] = [] yield args finally: cls.level -= 1 @@ -880,7 +872,7 @@ def disable_pam_securetty(root: Path) -> None: def add_packages( - config: MkosiConfig, packages: Set[str], *names: str, conditional: Optional[str] = None + config: MkosiConfig, packages: set[str], *names: str, conditional: Optional[str] = None ) -> None: """Add packages in @names to @packages, if enabled by --base-packages. @@ -896,7 +888,7 @@ def add_packages( packages.add(f"({name} if {conditional})" if conditional else name) -def sort_packages(packages: Iterable[str]) -> List[str]: +def sort_packages(packages: Iterable[str]) -> list[str]: """Sorts packages: normal first, paths second, conditional third""" m = {"(": 2, "/": 1} diff --git a/mkosi/distributions/__init__.py b/mkosi/distributions/__init__.py index ea1c6316c..aa87b7185 100644 --- a/mkosi/distributions/__init__.py +++ b/mkosi/distributions/__init__.py @@ -1,7 +1,7 @@ # SPDX-License-Identifier: LGPL-2.1+ from pathlib import Path -from typing import TYPE_CHECKING, List +from typing import TYPE_CHECKING if TYPE_CHECKING: from mkosi.backend import MkosiState @@ -19,9 +19,9 @@ class DistributionInstaller: return Path("lib/modules") / name / "vmlinuz" @classmethod - def cache_path(cls) -> List[str]: + def cache_path(cls) -> list[str]: raise NotImplementedError @classmethod - def remove_packages(cls, state: "MkosiState", remove: List[str]) -> None: + def remove_packages(cls, state: "MkosiState", remove: list[str]) -> None: raise NotImplementedError diff --git a/mkosi/distributions/alma.py b/mkosi/distributions/alma.py index 143a5aad9..59c39af1d 100644 --- a/mkosi/distributions/alma.py +++ b/mkosi/distributions/alma.py @@ -1,7 +1,6 @@ # SPDX-License-Identifier: LGPL-2.1+ from pathlib import Path -from typing import Tuple from mkosi.backend import MkosiConfig from mkosi.distributions.centos import CentosInstaller @@ -9,7 +8,7 @@ from mkosi.distributions.centos import CentosInstaller class AlmaInstaller(CentosInstaller): @staticmethod - def _gpg_locations(epel_release: int) -> Tuple[Path, str]: + def _gpg_locations(epel_release: int) -> tuple[Path, str]: return ( Path(f"/etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-{epel_release}"), f"https://repo.almalinux.org/almalinux/RPM-GPG-KEY-AlmaLinux-{epel_release}", diff --git a/mkosi/distributions/arch.py b/mkosi/distributions/arch.py index 881712b74..fa474204d 100644 --- a/mkosi/distributions/arch.py +++ b/mkosi/distributions/arch.py @@ -2,7 +2,6 @@ import os from textwrap import dedent -from typing import List, Set from mkosi.backend import ( MkosiPrinter, @@ -19,7 +18,7 @@ from mkosi.mounts import mount_api_vfs class ArchInstaller(DistributionInstaller): @classmethod - def cache_path(cls) -> List[str]: + def cache_path(cls) -> list[str]: return ["var/cache/pacman/pkg"] @classmethod @@ -135,7 +134,7 @@ def install_arch(state: MkosiState) -> None: ) ) - packages: Set[str] = set() + packages: set[str] = set() add_packages(state.config, packages, "base") if not state.do_run_build_script and state.config.bootable: diff --git a/mkosi/distributions/centos.py b/mkosi/distributions/centos.py index d5b59fe98..7c45a8a49 100644 --- a/mkosi/distributions/centos.py +++ b/mkosi/distributions/centos.py @@ -2,7 +2,6 @@ import shutil from pathlib import Path -from typing import List, Tuple from mkosi.backend import ( Distribution, @@ -35,7 +34,7 @@ def move_rpm_db(root: Path) -> None: class CentosInstaller(DistributionInstaller): @classmethod - def cache_path(cls) -> List[str]: + def cache_path(cls) -> list[str]: return ["var/cache/yum", "var/cache/dnf"] @classmethod @@ -89,7 +88,7 @@ class CentosInstaller(DistributionInstaller): run_workspace_command(state, cmdline) @classmethod - def remove_packages(cls, state: MkosiState, remove: List[str]) -> None: + def remove_packages(cls, state: MkosiState, remove: list[str]) -> None: invoke_dnf(state, 'remove', remove) @classmethod @@ -104,14 +103,14 @@ class CentosInstaller(DistributionInstaller): return int(fields[0].removesuffix("-stream")) @staticmethod - def _gpg_locations(epel_release: int) -> Tuple[Path, str]: + def _gpg_locations(epel_release: int) -> tuple[Path, str]: return ( Path("/etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial"), "https://www.centos.org/keys/RPM-GPG-KEY-CentOS-Official" ) @staticmethod - def _epel_gpg_locations(epel_release: int) -> Tuple[Path, str]: + def _epel_gpg_locations(epel_release: int) -> tuple[Path, str]: return ( Path(f"/etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-{epel_release}"), f"https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-{epel_release}", @@ -126,7 +125,7 @@ class CentosInstaller(DistributionInstaller): return f"http://mirrorlist.centos.org/?release={config.release}&arch=$basearch&repo={repo}" @classmethod - def _variant_repos(cls, config: MkosiConfig, epel_release: int) -> List[Repo]: + def _variant_repos(cls, config: MkosiConfig, epel_release: int) -> list[Repo]: # Repos for CentOS Linux 8, CentOS Stream 8 and CentOS variants directory = cls._mirror_directory() @@ -174,7 +173,7 @@ class CentosInstaller(DistributionInstaller): return repos @classmethod - def _stream_repos(cls, config: MkosiConfig, epel_release: int) -> List[Repo]: + def _stream_repos(cls, config: MkosiConfig, epel_release: int) -> list[Repo]: # Repos for CentOS Stream 9 and later gpgpath, gpgurl = cls._gpg_locations(epel_release) diff --git a/mkosi/distributions/debian.py b/mkosi/distributions/debian.py index 649784ab0..f813f9326 100644 --- a/mkosi/distributions/debian.py +++ b/mkosi/distributions/debian.py @@ -3,9 +3,10 @@ import contextlib import os import subprocess +from collections.abc import Iterable, Iterator from pathlib import Path from textwrap import dedent -from typing import TYPE_CHECKING, Any, Iterable, Iterator, List, Set +from typing import TYPE_CHECKING, Any from mkosi.backend import ( MkosiState, @@ -28,17 +29,17 @@ else: class DebianInstaller(DistributionInstaller): needs_skeletons_after_bootstrap = True - repositories_for_boot: Set[str] = set() + repositories_for_boot: set[str] = set() @classmethod - def _add_default_kernel_package(cls, state: MkosiState, extra_packages: Set[str]) -> None: + def _add_default_kernel_package(cls, state: MkosiState, extra_packages: set[str]) -> None: # Don't pull in a kernel if users specify one, but otherwise try to pick a default # one - try to infer from the architecture. if not any(package.startswith("linux-image") for package in extra_packages): add_packages(state.config, extra_packages, f"linux-image-{DEBIAN_KERNEL_ARCHITECTURES[state.config.architecture]}") @classmethod - def _fixup_resolved(cls, state: MkosiState, extra_packages: Set[str]) -> None: + def _fixup_resolved(cls, state: MkosiState, extra_packages: set[str]) -> None: if "systemd" in extra_packages and "systemd-resolved" not in extra_packages: # The default resolv.conf points to 127.0.0.1, and resolved is disabled, fix it in # the base image. @@ -47,7 +48,7 @@ class DebianInstaller(DistributionInstaller): run(["systemctl", "--root", state.root, "enable", "systemd-resolved"]) @classmethod - def cache_path(cls) -> List[str]: + def cache_path(cls) -> list[str]: return ["var/cache/apt/archives"] @staticmethod @@ -69,7 +70,7 @@ class DebianInstaller(DistributionInstaller): # debootstrap fails if a base image is used with an already populated root, so skip it. if state.config.base_image is None: - cmdline: List[PathString] = [ + cmdline: list[PathString] = [ "debootstrap", "--variant=minbase", "--include=ca-certificates", @@ -95,7 +96,7 @@ class DebianInstaller(DistributionInstaller): # Install extra packages via the secondary APT run, because it is smarter and can deal better with any # conflicts. dbus and libpam-systemd are optional dependencies for systemd in debian so we include them # explicitly. - extra_packages: Set[str] = set() + extra_packages: set[str] = set() add_packages(state.config, extra_packages, "systemd", "systemd-sysv", "dbus", "libpam-systemd") extra_packages.update(state.config.packages) @@ -190,7 +191,7 @@ class DebianInstaller(DistributionInstaller): state.root.joinpath("etc/default/locale").symlink_to("../locale.conf") @classmethod - def _add_apt_auxiliary_repos(cls, state: MkosiState, repos: Set[str]) -> None: + def _add_apt_auxiliary_repos(cls, state: MkosiState, repos: set[str]) -> None: if state.config.release in ("unstable", "sid"): return @@ -206,7 +207,7 @@ class DebianInstaller(DistributionInstaller): state.root.joinpath(f"etc/apt/sources.list.d/{state.config.release}-security.list").write_text(f"{security}\n") @classmethod - def remove_packages(cls, state: MkosiState, remove: List[str]) -> None: + def remove_packages(cls, state: MkosiState, remove: list[str]) -> None: invoke_apt(state, "get", "purge", ["--assume-yes", "--auto-remove", *remove]) @@ -308,6 +309,6 @@ def invoke_apt( return run(cmdline, env=env, text=True, **kwargs) -def add_apt_package_if_exists(state: MkosiState, extra_packages: Set[str], package: str) -> None: +def add_apt_package_if_exists(state: MkosiState, extra_packages: set[str], package: str) -> None: if invoke_apt(state, "cache", "search", ["--names-only", f"^{package}$"], stdout=subprocess.PIPE).stdout.strip(): add_packages(state.config, extra_packages, package) diff --git a/mkosi/distributions/fedora.py b/mkosi/distributions/fedora.py index db880959b..7adc1d9b5 100644 --- a/mkosi/distributions/fedora.py +++ b/mkosi/distributions/fedora.py @@ -3,9 +3,10 @@ import shutil import urllib.parse import urllib.request +from collections.abc import Iterable, Sequence from pathlib import Path from textwrap import dedent -from typing import Iterable, List, NamedTuple, Optional, Sequence, Set, Tuple +from typing import NamedTuple, Optional from mkosi.backend import ( Distribution, @@ -32,7 +33,7 @@ FEDORA_KEYS_MAP = { class FedoraInstaller(DistributionInstaller): @classmethod - def cache_path(cls) -> List[str]: + def cache_path(cls) -> list[str]: return ["var/cache/dnf"] @classmethod @@ -40,11 +41,11 @@ class FedoraInstaller(DistributionInstaller): return install_fedora(state) @classmethod - def remove_packages(cls, state: MkosiState, remove: List[str]) -> None: + def remove_packages(cls, state: MkosiState, remove: list[str]) -> None: invoke_dnf(state, 'remove', remove) -def parse_fedora_release(release: str) -> Tuple[str, str]: +def parse_fedora_release(release: str) -> tuple[str, str]: if release.startswith("rawhide-"): release, releasever = release.split("-") MkosiPrinter.info(f"Fedora rawhide — release version: {releasever}") @@ -120,7 +121,7 @@ def url_exists(url: str) -> bool: return False -def make_rpm_list(state: MkosiState, packages: Set[str]) -> Set[str]: +def make_rpm_list(state: MkosiState, packages: set[str]) -> set[str]: packages = packages.copy() if not state.do_run_build_script and state.config.ssh: @@ -129,7 +130,7 @@ def make_rpm_list(state: MkosiState, packages: Set[str]) -> Set[str]: return packages -def install_packages_dnf(state: MkosiState, packages: Set[str],) -> None: +def install_packages_dnf(state: MkosiState, packages: set[str],) -> None: packages = make_rpm_list(state, packages) invoke_dnf(state, 'install', packages) diff --git a/mkosi/distributions/gentoo.py b/mkosi/distributions/gentoo.py index 5d6eb8742..7ced46edb 100644 --- a/mkosi/distributions/gentoo.py +++ b/mkosi/distributions/gentoo.py @@ -7,9 +7,9 @@ import re import tarfile import urllib.parse import urllib.request +from collections.abc import Generator, Sequence from pathlib import Path from textwrap import dedent -from typing import Dict, Generator, List, Sequence from mkosi.backend import ( ARG_DEBUG, @@ -45,14 +45,14 @@ class Gentoo: arch_profile: Path arch: str custom_profile_path: Path - DEFAULT_NSPAWN_PARAMS: List[str] + DEFAULT_NSPAWN_PARAMS: list[str] ebuild_sh_env_dir: Path - emerge_default_opts: List[str] - emerge_vars: Dict[str, str] + emerge_default_opts: list[str] + emerge_vars: dict[str, str] portage_cfg_dir: Path profile_path: Path root: Path - pkgs: Dict[str, List[str]] = {} + pkgs: dict[str, list[str]] = {} dracut_atom = "sys-kernel/dracut" EMERGE_UPDATE_OPTS = [ @@ -90,7 +90,7 @@ class Gentoo: ] @staticmethod - def try_import_portage() -> Dict[str, str]: + def try_import_portage() -> dict[str, str]: NEED_PORTAGE_MSG = "You need portage(5) for Gentoo" PORTAGE_INSTALL_INSTRUCTIONS = """\ # Following is known to work on most systemd-based systems: @@ -363,7 +363,7 @@ class Gentoo: if not inside_stage3: from _emerge.main import emerge_main # type: ignore - PREFIX_OPTS: List[str] = [] + PREFIX_OPTS: list[str] = [] if "--sync" not in actions: PREFIX_OPTS = [ f"--config-root={self.root.resolve()}", @@ -393,7 +393,7 @@ class Gentoo: class GentooInstaller(DistributionInstaller): @classmethod - def cache_path(cls) -> List[str]: + def cache_path(cls) -> list[str]: return ["var/cache/binpkgs", "var/cache/distfiles"] @staticmethod diff --git a/mkosi/distributions/mageia.py b/mkosi/distributions/mageia.py index 0e61c242a..0a3dd383e 100644 --- a/mkosi/distributions/mageia.py +++ b/mkosi/distributions/mageia.py @@ -1,7 +1,6 @@ # SPDX-License-Identifier: LGPL-2.1+ from pathlib import Path -from typing import List from mkosi.backend import MkosiState, add_packages, complete_step, disable_pam_securetty from mkosi.distributions import DistributionInstaller @@ -10,7 +9,7 @@ from mkosi.distributions.fedora import Repo, install_packages_dnf, invoke_dnf, s class MageiaInstaller(DistributionInstaller): @classmethod - def cache_path(cls) -> List[str]: + def cache_path(cls) -> list[str]: return ["var/cache/dnf"] @classmethod @@ -18,7 +17,7 @@ class MageiaInstaller(DistributionInstaller): return install_mageia(state) @classmethod - def remove_packages(cls, state: MkosiState, remove: List[str]) -> None: + def remove_packages(cls, state: MkosiState, remove: list[str]) -> None: invoke_dnf(state, 'remove', remove) diff --git a/mkosi/distributions/openmandriva.py b/mkosi/distributions/openmandriva.py index 74de4eb15..8e0dfe0c4 100644 --- a/mkosi/distributions/openmandriva.py +++ b/mkosi/distributions/openmandriva.py @@ -1,7 +1,6 @@ # SPDX-License-Identifier: LGPL-2.1+ from pathlib import Path -from typing import List from mkosi.backend import MkosiState, add_packages, complete_step from mkosi.distributions import DistributionInstaller @@ -10,7 +9,7 @@ from mkosi.distributions.fedora import Repo, install_packages_dnf, invoke_dnf, s class OpenmandrivaInstaller(DistributionInstaller): @classmethod - def cache_path(cls) -> List[str]: + def cache_path(cls) -> list[str]: return ["var/cache/dnf"] @classmethod @@ -18,7 +17,7 @@ class OpenmandrivaInstaller(DistributionInstaller): return install_openmandriva(state) @classmethod - def remove_packages(cls, state: MkosiState, remove: List[str]) -> None: + def remove_packages(cls, state: MkosiState, remove: list[str]) -> None: invoke_dnf(state, 'remove', remove) diff --git a/mkosi/distributions/opensuse.py b/mkosi/distributions/opensuse.py index ab9239757..3642550a7 100644 --- a/mkosi/distributions/opensuse.py +++ b/mkosi/distributions/opensuse.py @@ -1,7 +1,6 @@ # SPDX-License-Identifier: LGPL-2.1+ import shutil -from typing import List from mkosi.backend import ( MkosiState, @@ -18,7 +17,7 @@ from mkosi.mounts import mount_api_vfs class OpensuseInstaller(DistributionInstaller): @classmethod - def cache_path(cls) -> List[str]: + def cache_path(cls) -> list[str]: return ["var/cache/zypp/packages"] @classmethod @@ -81,7 +80,7 @@ def install_opensuse(state: MkosiState) -> None: if not state.do_run_build_script and state.config.ssh: add_packages(state.config, packages, "openssh-server") - cmdline: List[PathString] = ["zypper"] + cmdline: list[PathString] = ["zypper"] # --reposd-dir needs to be before the verb if state.config.local_mirror: cmdline += ["--reposd-dir", state.workspace / "zypper-repos.d"] diff --git a/mkosi/distributions/rocky.py b/mkosi/distributions/rocky.py index 30d3385b8..b62b672b2 100644 --- a/mkosi/distributions/rocky.py +++ b/mkosi/distributions/rocky.py @@ -1,7 +1,6 @@ # SPDX-License-Identifier: LGPL-2.1+ from pathlib import Path -from typing import Tuple from mkosi.backend import MkosiConfig from mkosi.distributions.centos import CentosInstaller @@ -9,7 +8,7 @@ from mkosi.distributions.centos import CentosInstaller class RockyInstaller(CentosInstaller): @staticmethod - def _gpg_locations(epel_release: int) -> Tuple[Path, str]: + def _gpg_locations(epel_release: int) -> tuple[Path, str]: keyname = f"Rocky-{epel_release}" if epel_release >= 9 else "rockyofficial" return ( Path(f"/etc/pki/rpm-gpg/RPM-GPG-KEY-{keyname}"), diff --git a/mkosi/distributions/ubuntu.py b/mkosi/distributions/ubuntu.py index 26080d0bc..8bd59c8a3 100644 --- a/mkosi/distributions/ubuntu.py +++ b/mkosi/distributions/ubuntu.py @@ -1,7 +1,5 @@ # SPDX-License-Identifier: LGPL-2.1+ -from typing import Set - from mkosi.backend import MkosiState, add_packages from mkosi.distributions.debian import DebianInstaller @@ -10,14 +8,14 @@ class UbuntuInstaller(DebianInstaller): repositories_for_boot = {"universe"} @classmethod - def _add_default_kernel_package(cls, state: MkosiState, extra_packages: Set[str]) -> None: + def _add_default_kernel_package(cls, state: MkosiState, extra_packages: set[str]) -> None: # use the global metapckage linux-generic if the user didn't pick one if ("linux-generic" not in extra_packages and not any(package.startswith("linux-image") for package in extra_packages)): add_packages(state.config, extra_packages, "linux-generic") @classmethod - def _add_apt_auxiliary_repos(cls, state: MkosiState, repos: Set[str]) -> None: + def _add_apt_auxiliary_repos(cls, state: MkosiState, repos: set[str]) -> None: if state.config.release in ("unstable", "sid"): return @@ -30,5 +28,5 @@ class UbuntuInstaller(DebianInstaller): state.root.joinpath(f"etc/apt/sources.list.d/{state.config.release}-security.list").write_text(f"{security}\n") @classmethod - def _fixup_resolved(cls, state: MkosiState, extra_packages: Set[str]) -> None: + def _fixup_resolved(cls, state: MkosiState, extra_packages: set[str]) -> None: pass diff --git a/mkosi/install.py b/mkosi/install.py index df0597508..6a25f7326 100644 --- a/mkosi/install.py +++ b/mkosi/install.py @@ -7,9 +7,10 @@ import importlib.resources import os import shutil import stat +from collections.abc import Iterator from pathlib import Path from textwrap import dedent -from typing import Any, BinaryIO, Iterator, Optional, cast +from typing import Any, BinaryIO, Optional, cast from mkosi.backend import MkosiState, PathString, complete_step diff --git a/mkosi/manifest.py b/mkosi/manifest.py index d12a98690..ff867d3d6 100644 --- a/mkosi/manifest.py +++ b/mkosi/manifest.py @@ -6,7 +6,7 @@ from datetime import datetime from pathlib import Path from subprocess import DEVNULL, PIPE from textwrap import dedent -from typing import IO, Any, Dict, List, Optional, Tuple +from typing import IO, Any, Optional from mkosi.backend import Distribution, ManifestFormat, MkosiConfig, PackageType, run @@ -25,7 +25,7 @@ class PackageManifest: architecture: str size: int - def as_dict(self) -> Dict[str, str]: + def as_dict(self) -> dict[str, str]: return { "type": self.type, "name": self.name, @@ -38,7 +38,7 @@ class PackageManifest: class SourcePackageManifest: name: str changelog: Optional[str] - packages: List[PackageManifest] = dataclasses.field(default_factory=list) + packages: list[PackageManifest] = dataclasses.field(default_factory=list) def add(self, package: PackageManifest) -> None: self.packages.append(package) @@ -58,7 +58,7 @@ class SourcePackageManifest: return t -def parse_pkg_desc(f: Path) -> Tuple[str, str, str, str]: +def parse_pkg_desc(f: Path) -> tuple[str, str, str, str]: name = version = base = arch = "" with f.open() as desc: for line in desc: @@ -78,8 +78,8 @@ def parse_pkg_desc(f: Path) -> Tuple[str, str, str, str]: @dataclasses.dataclass class Manifest: config: MkosiConfig - packages: List[PackageManifest] = dataclasses.field(default_factory=list) - source_packages: Dict[str, SourcePackageManifest] = dataclasses.field(default_factory=dict) + packages: list[PackageManifest] = dataclasses.field(default_factory=list) + source_packages: dict[str, SourcePackageManifest] = dataclasses.field(default_factory=dict) _init_timestamp: datetime = dataclasses.field(init=False, default_factory=datetime.now) @@ -242,7 +242,7 @@ class Manifest: # We might add more data in the future return len(self.packages) > 0 - def as_dict(self) -> Dict[str, Any]: + def as_dict(self) -> dict[str, Any]: config = { "name": self.config.image_id or "image", "distribution": self.config.distribution.name, diff --git a/mkosi/mounts.py b/mkosi/mounts.py index 571c9228c..a2d5cc309 100644 --- a/mkosi/mounts.py +++ b/mkosi/mounts.py @@ -3,8 +3,9 @@ import contextlib import os import stat +from collections.abc import Iterator, Sequence from pathlib import Path -from typing import ContextManager, Iterator, List, Optional, Sequence, Union, cast +from typing import ContextManager, Optional, Union, cast from mkosi.backend import complete_step, run, scandir_recursive @@ -42,7 +43,7 @@ def mount( if read_only: options = ["ro", *options] - cmd: List[PathString] = ["mount", "--no-mtab"] + cmd: list[PathString] = ["mount", "--no-mtab"] if operation: cmd += [operation]