From b84d2202db6a98d101c22a1b712ce54e19541361 Mon Sep 17 00:00:00 2001 From: InsanePrawn Date: Sun, 16 Apr 2023 20:48:48 +0000 Subject: [PATCH] python 3.9 compat: introduce typehelpers.py for NoneType, UnionType, TypeAlias --- config/scheme.py | 11 +---------- constants.py | 2 +- dataclass.py | 10 +++------- devices/device.py | 3 +-- distro/package.py | 6 +++--- distro/repo_config.py | 4 ++-- exec/cmd.py | 4 +++- packages/pkgbuild.py | 3 ++- typehelpers.py | 18 ++++++++++++++++++ 9 files changed, 34 insertions(+), 27 deletions(-) create mode 100644 typehelpers.py diff --git a/config/scheme.py b/config/scheme.py index a0554ad..9409661 100644 --- a/config/scheme.py +++ b/config/scheme.py @@ -3,11 +3,10 @@ from __future__ import annotations from munch import Munch from typing import Any, Optional, Mapping, Union -from dataclass import DataClass, munchclass +from dataclass import DataClass from constants import Arch -@munchclass() class SparseProfile(DataClass): parent: Optional[str] device: Optional[str] @@ -23,7 +22,6 @@ class SparseProfile(DataClass): return f'{type(self)}{dict.__repr__(self.toDict())}' -@munchclass() class Profile(SparseProfile): parent: Optional[str] device: str @@ -36,12 +34,10 @@ class Profile(SparseProfile): size_extra_mb: Union[str, int] -@munchclass() class WrapperSection(DataClass): type: str # NOTE: rename to 'wrapper_type' if this causes problems -@munchclass() class BuildSection(DataClass): ccache: bool clean_mode: bool @@ -50,20 +46,17 @@ class BuildSection(DataClass): threads: int -@munchclass() class PkgbuildsSection(DataClass): git_repo: str git_branch: str -@munchclass() class PacmanSection(DataClass): parallel_downloads: int check_space: bool repo_branch: str -@munchclass() class PathsSection(DataClass): cache_dir: str chroots: str @@ -101,7 +94,6 @@ class ProfilesSection(DataClass): return f'{type(self)}{dict.__repr__(self.toDict())}' -@munchclass() class Config(DataClass): wrapper: WrapperSection build: BuildSection @@ -138,7 +130,6 @@ class Config(DataClass): return Config(_vals, validate=validate) -@munchclass() class RuntimeConfiguration(DataClass): verbose: bool no_wrap: bool diff --git a/constants.py b/constants.py index 62fb230..d881b9f 100644 --- a/constants.py +++ b/constants.py @@ -1,4 +1,4 @@ -from typing_extensions import TypeAlias +from typehelpers import TypeAlias FASTBOOT = 'fastboot' FLASH_PARTS = { diff --git a/dataclass.py b/dataclass.py index 8ad9035..6bd19df 100644 --- a/dataclass.py +++ b/dataclass.py @@ -3,15 +3,11 @@ from __future__ import annotations import logging import toml -from dataclasses import dataclass from munch import Munch from toml.encoder import TomlEncoder, TomlPreserveInlineDictEncoder from typing import ClassVar, Generator, Optional, Union, Mapping, Any, get_type_hints, get_origin, get_args, Iterable -from types import UnionType, NoneType - -def munchclass(*args, init=False, **kwargs): - return dataclass(*args, init=init, slots=True, **kwargs) +from typehelpers import UnionType, NoneType def resolve_type_hint(hint: type, ignore_origins: list[type] = []) -> Iterable[type]: @@ -73,12 +69,12 @@ class DataClass(Munch): type_hints = cls._type_hints if type_hints is None else type_hints if key in type_hints: _classes = tuple[type](resolve_type_hint(type_hints[key])) - optional = NoneType in _classes + optional = bool(set([NoneType, None]).intersection(_classes)) if optional and value is None: results[key] = None continue if issubclass(_classes[0], dict): - assert isinstance(value, dict) or optional + assert isinstance(value, dict) or (optional and value is None), f'{key=} is not dict: {value!r}, {_classes=}' target_class = _classes[0] if target_class in [None, NoneType, Optional]: for target in _classes[1:]: diff --git a/devices/device.py b/devices/device.py index 05041b3..9780a86 100644 --- a/devices/device.py +++ b/devices/device.py @@ -5,7 +5,7 @@ from typing import Optional from config.state import config from constants import Arch, ARCHES -from config.scheme import DataClass, munchclass +from dataclass import DataClass from distro.distro import get_kupfer_local from distro.package import LocalPackage from packages.pkgbuild import Pkgbuild, _pkgbuilds_cache, discover_pkgbuilds, get_pkgbuild_by_path, init_pkgbuilds @@ -43,7 +43,6 @@ class DeviceSummary(DataClass): return separator.join([f"{color_str(name, bold=True, use_colors=colors)}: {value}" for name, value in fields.items()]) -@munchclass() class Device(DataClass): name: str arch: Arch diff --git a/distro/package.py b/distro/package.py index 18c48c1..4a5b5a6 100644 --- a/distro/package.py +++ b/distro/package.py @@ -2,7 +2,7 @@ import logging import os from shutil import copyfileobj -from typing import Optional +from typing import Optional, Union from urllib.request import urlopen from exec.file import get_temp_dir, makedir @@ -17,7 +17,7 @@ class BinaryPackage(PackageInfo): arch: str filename: str resolved_url: Optional[str] - _desc: Optional[dict[str, str | list[str]]] + _desc: Optional[dict[str, Union[str, list[str]]]] def __init__( self, @@ -39,7 +39,7 @@ class BinaryPackage(PackageInfo): @classmethod def parse_desc(clss, desc_str: str, resolved_repo_url=None): """Parses a desc file, returning a PackageInfo""" - desc: dict[str, str | list[str]] = {} + desc: dict[str, Union[str, list[str]]] = {} for segment in f'\n{desc_str}'.split('\n%'): if not segment.strip(): continue diff --git a/distro/repo_config.py b/distro/repo_config.py index 6bcaa26..34c55e6 100644 --- a/distro/repo_config.py +++ b/distro/repo_config.py @@ -6,7 +6,7 @@ import toml import yaml from copy import deepcopy -from typing import ClassVar, Optional, Mapping +from typing import ClassVar, Optional, Mapping, Union from config.state import config from constants import Arch, BASE_DISTROS, KUPFER_HTTPS, REPOS_CONFIG_FILE, REPOSITORIES @@ -33,7 +33,7 @@ class BaseDistroRepo(AbstrRepoConfig): class RepoConfig(AbstrRepoConfig): - remote_url: Optional[str | dict[Arch, str]] + remote_url: Optional[Union[str, dict[Arch, str]]] local_only: Optional[bool] diff --git a/exec/cmd.py b/exec/cmd.py index be8218b..d653d05 100644 --- a/exec/cmd.py +++ b/exec/cmd.py @@ -5,7 +5,9 @@ import subprocess from subprocess import CompletedProcess # make it easy for users of this module from shlex import quote as shell_quote -from typing import IO, Optional, Union, TypeAlias +from typing import IO, Optional, Union + +from typehelpers import TypeAlias ElevationMethod: TypeAlias = str diff --git a/packages/pkgbuild.py b/packages/pkgbuild.py index a2d13e5..b61884a 100644 --- a/packages/pkgbuild.py +++ b/packages/pkgbuild.py @@ -6,7 +6,7 @@ import multiprocessing import os from joblib import Parallel, delayed -from typing import Iterable, Optional, TypeAlias +from typing import Iterable, Optional from config.state import config, ConfigStateHolder from constants import Arch @@ -16,6 +16,7 @@ from exec.file import remove_file from logger import setup_logging from utils import git, git_get_branch from wrapper import check_programs_wrap +from typehelpers import TypeAlias from .srcinfo_cache import SrcinfoMetaFile diff --git a/typehelpers.py b/typehelpers.py new file mode 100644 index 0000000..f43d96e --- /dev/null +++ b/typehelpers.py @@ -0,0 +1,18 @@ +from typing import Union + +try: + from typing import TypeAlias # type: ignore[attr-defined] +except ImportError: + from typing_extensions import TypeAlias + +TypeAlias = TypeAlias + +try: + from types import UnionType +except ImportError: + UnionType: TypeAlias = Union # type: ignore[no-redef] + +try: + from types import NoneType +except ImportError: + NoneType: TypeAlias = type(None) # type: ignore[no-redef]