chore: improve type hinting

This commit is contained in:
Jordan ⌨️ 2023-06-09 20:46:57 +02:00
parent cc8aafb300
commit c3ead4092c
9 changed files with 55 additions and 40 deletions

View file

@ -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

View file

@ -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"])

View file

@ -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())))

View file

@ -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')

View file

@ -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))
}

View file

@ -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)
raise RuntimeError(
"No project.json found in this directory or any parent directory")
os.chdir(projectRoot)

View file

@ -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)

View file

@ -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:

View file

@ -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):