From eabbcfe7c643733e49c16de4537452451d3ecb24 Mon Sep 17 00:00:00 2001 From: keyboard-slayer Date: Fri, 9 Jun 2023 20:46:57 +0200 Subject: [PATCH] chore: improve type hinting --- cutekit/args.py | 9 ++++++--- cutekit/cmds.py | 18 ++++++++++-------- cutekit/context.py | 13 +++++++------ cutekit/graph.py | 3 ++- cutekit/jexpr.py | 4 ++-- cutekit/project.py | 11 +++++++---- cutekit/rules.py | 28 ++++++++++++++++------------ cutekit/shell.py | 3 ++- cutekit/utils.py | 6 +++--- 9 files changed, 55 insertions(+), 40 deletions(-) diff --git a/cutekit/args.py b/cutekit/args.py index f2a73f8..6982366 100644 --- a/cutekit/args.py +++ b/cutekit/args.py @@ -1,4 +1,7 @@ -Value = str | bool | int +from typing import Optional, Union + + +Value = Union[str, bool, int] class Args: @@ -24,14 +27,14 @@ class Args: return result return default - def tryConsumeOpt(self, key: str) -> Value | None: + def tryConsumeOpt(self, key: str) -> Optional[Value]: if key in self.opts: result = self.opts[key] del self.opts[key] return result return None - def consumeArg(self) -> str | None: + def consumeArg(self) -> Optional[str]: if len(self.args) == 0: return None diff --git a/cutekit/cmds.py b/cutekit/cmds.py index c6fe588..28f666b 100644 --- a/cutekit/cmds.py +++ b/cutekit/cmds.py @@ -4,10 +4,11 @@ import tempfile import requests import sys -from typing import Callable, cast +from typing import Callable, cast, Optional, NoReturn from cutekit import context, shell, const, vt100, builder, graph, project from cutekit.args import Args +from cutekit.jexpr import Json from cutekit.model import Extern from cutekit.context import contextFor @@ -17,13 +18,13 @@ logger = logging.getLogger(__name__) class Cmd: - shortName: str | None + shortName: Optional[str] longName: str helpText: str - callback: Callable[[Args], None] + callback: Callable[[Args], NoReturn] isPlugin: bool = False - def __init__(self, shortName: str | None, longName: str, helpText: str, callback: Callable[[Args], None]): + def __init__(self, shortName: Optional[str], longName: str, helpText: str, callback: Callable[[Args], NoReturn]): self.shortName = shortName self.longName = longName self.helpText = helpText @@ -197,7 +198,7 @@ def graphCmd(args: Args): targetSpec = cast(str, args.consumeOpt( "target", "host-" + shell.uname().machine)) - scope: str | None = cast(str | None, args.tryConsumeOpt("scope")) + scope: Optional[str] = cast(Optional[str], args.tryConsumeOpt("scope")) onlyLibs: bool = args.consumeOpt("only-libs", False) == True showDisabled: bool = args.consumeOpt("show-disabled", False) == True @@ -221,7 +222,7 @@ def grabExtern(extern: dict[str, Extern]): print(f"Installing {extSpec}-{ext.tag} from {ext.git}...") shell.popen("git", "clone", "--depth", "1", "--branch", ext.tag, ext.git, extPath) - + if os.path.exists(os.path.join(extPath, "project.json")): grabExtern(context.loadProject(extPath).extern) @@ -259,9 +260,10 @@ def initCmd(args: Args): print('\n'.join( f"* {entry['id']} - {entry['description']}" for entry in registry)) else: - if not any(filter(lambda t: t['id'] == template, registry)): + template_match: Callable[[Json], str] = lambda t: t['id'] == template + if not any(filter(template_match, registry)): raise RuntimeError(f"Unknown template {template}") - + with tempfile.TemporaryDirectory() as tmp: shell.exec(*["git", "clone", "-n", "--depth=1", "--filter=tree:0", f"https://github.com/{repo}", tmp, "-q"]) diff --git a/cutekit/context.py b/cutekit/context.py index a3baad1..10e98c2 100644 --- a/cutekit/context.py +++ b/cutekit/context.py @@ -1,4 +1,4 @@ -from typing import cast, Protocol, Iterable +from typing import cast, Optional, Protocol, Iterable from itertools import chain from pathlib import Path import os @@ -95,7 +95,7 @@ class Context(IContext): self.instances = instances self.tools = tools - def componentByName(self, name: str) -> ComponentInstance | None: + def componentByName(self, name: str) -> Optional[ComponentInstance]: result = list(filter(lambda x: x.manifest.id == name, self.instances)) if len(result) == 0: return None @@ -120,10 +120,11 @@ def loadAllTargets() -> list[TargetManifest]: projectRoot = project.root() if projectRoot is None: return [] - + pj = loadProject(projectRoot) paths = list( - map(lambda e: os.path.join(const.EXTERN_DIR, e, const.TARGETS_DIR), pj.extern.keys()) + map(lambda e: os.path.join(const.EXTERN_DIR, + e, const.TARGETS_DIR), pj.extern.keys()) ) + [const.TARGETS_DIR] ret = [] @@ -161,7 +162,7 @@ def filterDisabled(components: list[ComponentManifest], target: TargetManifest) list(filter(lambda c: not c.isEnabled(target)[0], components)) -def providerFor(what: str, components: list[ComponentManifest]) -> tuple[str | None, str]: +def providerFor(what: str, components: list[ComponentManifest]) -> tuple[Optional[str], str]: result: list[ComponentManifest] = list( filter(lambda c: c.id == what, components)) @@ -217,7 +218,7 @@ def resolveDeps(componentSpec: str, components: list[ComponentManifest], target: return enabled, unresolvedReason, resolved -def instanciate(componentSpec: str, components: list[ComponentManifest], target: TargetManifest) -> ComponentInstance | None: +def instanciate(componentSpec: str, components: list[ComponentManifest], target: TargetManifest) -> Optional[ComponentInstance]: manifest = next(filter(lambda c: c.id == componentSpec, components)) wildcards = set( chain(*map(lambda rule: rule.fileIn, rules.rules.values()))) diff --git a/cutekit/graph.py b/cutekit/graph.py index ab4d65e..6fc380d 100644 --- a/cutekit/graph.py +++ b/cutekit/graph.py @@ -1,10 +1,11 @@ import os +from typing import Optional from cutekit.context import Context from cutekit import vt100 -def view(context: Context, scope: str | None = None, showExe: bool = True, showDisabled: bool = False): +def view(context: Context, scope: Optional[str] = None, showExe: bool = True, showDisabled: bool = False): from graphviz import Digraph g = Digraph(context.target.id, filename='graph.gv') diff --git a/cutekit/jexpr.py b/cutekit/jexpr.py index 623ccdd..c223680 100644 --- a/cutekit/jexpr.py +++ b/cutekit/jexpr.py @@ -14,11 +14,11 @@ BUILTINS: Final[dict[str, Builtin]] = { "evalRead": lambda arg, ctx: evalRead(arg), "join": lambda lhs, rhs, ctx: cast(Json, {**lhs, **rhs} if isinstance(lhs, dict) else lhs + rhs), "concat": lambda *args, ctx: "".join(args), - "eval": lambda arg, ctx: eval(arg), + "eval": lambda arg, ctx: eval(arg, ctx["filepath"]), "read": lambda arg, ctx: read(arg), "exec": lambda *args, ctx: shell.popen(*args).splitlines(), "latest": lambda arg, ctx: shell.latest(arg), - "abspath": lambda *args, ctx: os.path.normpath(os.path.join(os.path.dirname(ctx["filepath"]), *args)) + "abspath": lambda *args, ctx: os.path.normpath(os.path.join(os.path.dirname(ctx["filepath"]), *args)) } diff --git a/cutekit/project.py b/cutekit/project.py index 979fb7b..f27242b 100644 --- a/cutekit/project.py +++ b/cutekit/project.py @@ -1,6 +1,8 @@ import os +from typing import Optional -def root() -> str | None: + +def root() -> Optional[str]: cwd = os.getcwd() while cwd != "/": if os.path.isfile(os.path.join(cwd, "project.json")): @@ -12,6 +14,7 @@ def root() -> str | None: def chdir() -> None: projectRoot = root() if projectRoot is None: - raise RuntimeError("No project.json found in this directory or any parent directory") - - os.chdir(projectRoot) \ No newline at end of file + raise RuntimeError( + "No project.json found in this directory or any parent directory") + + os.chdir(projectRoot) diff --git a/cutekit/rules.py b/cutekit/rules.py index 33681ea..a2ef6ba 100644 --- a/cutekit/rules.py +++ b/cutekit/rules.py @@ -1,12 +1,15 @@ +from typing import Optional + + class Rule: id: str fileIn: list[str] fileOut: list[str] rule: str args: list[str] - deps: str | None = None + deps: Optional[str] = None - def __init__(self, id: str, fileIn: list[str], fileOut: list[str], rule: str, args: list[str] = [], deps: str | None = None): + def __init__(self, id: str, fileIn: list[str], fileOut: list[str], rule: str, args: list[str] = [], deps: Optional[str] = None): self.id = id self.fileIn = fileIn self.fileOut = fileOut @@ -14,17 +17,18 @@ class Rule: self.args = args self.deps = deps + rules: dict[str, Rule] = { "cc": Rule("cc", ["*.c"], ["*.o"], "-c -o $out $in -MD -MF $out.d $flags $cincs $cdefs", ["-std=gnu2x", - "-Wall", - "-Wextra", - "-Werror"], "$out.d"), + "-Wall", + "-Wextra", + "-Werror"], "$out.d"), "cxx": Rule("cxx", ["*.cpp", "*.cc", "*.cxx"], ["*.o"], "-c -o $out $in -MD -MF $out.d $flags $cincs $cdefs", ["-std=gnu++2b", - "-Wall", - "-Wextra", - "-Werror", - "-fno-exceptions", - "-fno-rtti"], "$out.d"), + "-Wall", + "-Wextra", + "-Werror", + "-fno-exceptions", + "-fno-rtti"], "$out.d"), "as": Rule("as", ["*.s", "*.asm", "*.S"], ["*.o"], "-o $out $in $flags"), "ar": Rule("ar", ["*.o"], ["*.a"], "$flags $out $in"), "ld": Rule("ld", ["*.o", "*.a"], ["*.out"], "-o $out $in $flags"), @@ -35,7 +39,7 @@ def append(rule: Rule): rules[rule.id] = rule -def byFileIn(fileIn: str) -> Rule | None: +def byFileIn(fileIn: str) -> Optional[Rule]: for key in rules: rule = rules[key] for ext in rule.fileIn: @@ -44,5 +48,5 @@ def byFileIn(fileIn: str) -> Rule | None: return None -def byId(id: str) -> Rule | None: +def byId(id: str) -> Optional[Rule]: return rules.get(id, None) diff --git a/cutekit/shell.py b/cutekit/shell.py index 012e49b..c9d5946 100644 --- a/cutekit/shell.py +++ b/cutekit/shell.py @@ -10,6 +10,7 @@ import fnmatch import platform import logging +from typing import Optional from cutekit import const logger = logging.getLogger(__name__) @@ -100,7 +101,7 @@ def rmrf(path: str) -> bool: return True -def wget(url: str, path: str | None = None) -> str: +def wget(url: str, path: Optional[str] = None) -> str: import requests if path is None: diff --git a/cutekit/utils.py b/cutekit/utils.py index b1374de..0923eef 100644 --- a/cutekit/utils.py +++ b/cutekit/utils.py @@ -1,4 +1,4 @@ -from typing import Any, TypeVar, cast +from typing import Any, TypeVar, cast, Optional, Union import json import hashlib @@ -14,7 +14,7 @@ def uniq(l: list[str]) -> list[str]: return result -def hash(obj: Any, keys: list[str] = [], cls: type[json.JSONEncoder] | None = None) -> str: +def hash(obj: Any, keys: list[str] = [], cls: Optional[type[json.JSONEncoder]] = None) -> str: toHash = {} if len(keys) == 0: toHash = obj @@ -50,7 +50,7 @@ def key(obj: Any, keys: list[str] = []) -> str: return "-".join(k) -def asList(i: T | list[T] | None) -> list[T]: +def asList(i: Optional[Union[T, list[T]]]) -> list[T]: if i is None: return [] if isinstance(i, list):