chore: improve type hinting

This commit is contained in:
Jordan ⌨️ 2023-06-09 20:46:57 +02:00 committed by Sleepy Monax
parent 1fac2fbbfb
commit eabbcfe7c6
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: class Args:
@ -24,14 +27,14 @@ class Args:
return result return result
return default return default
def tryConsumeOpt(self, key: str) -> Value | None: def tryConsumeOpt(self, key: str) -> Optional[Value]:
if key in self.opts: if key in self.opts:
result = self.opts[key] result = self.opts[key]
del self.opts[key] del self.opts[key]
return result return result
return None return None
def consumeArg(self) -> str | None: def consumeArg(self) -> Optional[str]:
if len(self.args) == 0: if len(self.args) == 0:
return None return None

View file

@ -4,10 +4,11 @@ import tempfile
import requests import requests
import sys 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 import context, shell, const, vt100, builder, graph, project
from cutekit.args import Args from cutekit.args import Args
from cutekit.jexpr import Json
from cutekit.model import Extern from cutekit.model import Extern
from cutekit.context import contextFor from cutekit.context import contextFor
@ -17,13 +18,13 @@ logger = logging.getLogger(__name__)
class Cmd: class Cmd:
shortName: str | None shortName: Optional[str]
longName: str longName: str
helpText: str helpText: str
callback: Callable[[Args], None] callback: Callable[[Args], NoReturn]
isPlugin: bool = False 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.shortName = shortName
self.longName = longName self.longName = longName
self.helpText = helpText self.helpText = helpText
@ -197,7 +198,7 @@ def graphCmd(args: Args):
targetSpec = cast(str, args.consumeOpt( targetSpec = cast(str, args.consumeOpt(
"target", "host-" + shell.uname().machine)) "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 onlyLibs: bool = args.consumeOpt("only-libs", False) == True
showDisabled: bool = args.consumeOpt("show-disabled", 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}...") print(f"Installing {extSpec}-{ext.tag} from {ext.git}...")
shell.popen("git", "clone", "--depth", "1", "--branch", shell.popen("git", "clone", "--depth", "1", "--branch",
ext.tag, ext.git, extPath) ext.tag, ext.git, extPath)
if os.path.exists(os.path.join(extPath, "project.json")): if os.path.exists(os.path.join(extPath, "project.json")):
grabExtern(context.loadProject(extPath).extern) grabExtern(context.loadProject(extPath).extern)
@ -259,9 +260,10 @@ def initCmd(args: Args):
print('\n'.join( print('\n'.join(
f"* {entry['id']} - {entry['description']}" for entry in registry)) f"* {entry['id']} - {entry['description']}" for entry in registry))
else: 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}") raise RuntimeError(f"Unknown template {template}")
with tempfile.TemporaryDirectory() as tmp: with tempfile.TemporaryDirectory() as tmp:
shell.exec(*["git", "clone", "-n", "--depth=1", shell.exec(*["git", "clone", "-n", "--depth=1",
"--filter=tree:0", f"https://github.com/{repo}", tmp, "-q"]) "--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 itertools import chain
from pathlib import Path from pathlib import Path
import os import os
@ -95,7 +95,7 @@ class Context(IContext):
self.instances = instances self.instances = instances
self.tools = tools 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)) result = list(filter(lambda x: x.manifest.id == name, self.instances))
if len(result) == 0: if len(result) == 0:
return None return None
@ -120,10 +120,11 @@ def loadAllTargets() -> list[TargetManifest]:
projectRoot = project.root() projectRoot = project.root()
if projectRoot is None: if projectRoot is None:
return [] return []
pj = loadProject(projectRoot) pj = loadProject(projectRoot)
paths = list( 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] ) + [const.TARGETS_DIR]
ret = [] ret = []
@ -161,7 +162,7 @@ def filterDisabled(components: list[ComponentManifest], target: TargetManifest)
list(filter(lambda c: not c.isEnabled(target)[0], components)) 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( result: list[ComponentManifest] = list(
filter(lambda c: c.id == what, components)) filter(lambda c: c.id == what, components))
@ -217,7 +218,7 @@ def resolveDeps(componentSpec: str, components: list[ComponentManifest], target:
return enabled, unresolvedReason, resolved 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)) manifest = next(filter(lambda c: c.id == componentSpec, components))
wildcards = set( wildcards = set(
chain(*map(lambda rule: rule.fileIn, rules.rules.values()))) chain(*map(lambda rule: rule.fileIn, rules.rules.values())))

View file

@ -1,10 +1,11 @@
import os import os
from typing import Optional
from cutekit.context import Context from cutekit.context import Context
from cutekit import vt100 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 from graphviz import Digraph
g = Digraph(context.target.id, filename='graph.gv') 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), "evalRead": lambda arg, ctx: evalRead(arg),
"join": lambda lhs, rhs, ctx: cast(Json, {**lhs, **rhs} if isinstance(lhs, dict) else lhs + rhs), "join": lambda lhs, rhs, ctx: cast(Json, {**lhs, **rhs} if isinstance(lhs, dict) else lhs + rhs),
"concat": lambda *args, ctx: "".join(args), "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), "read": lambda arg, ctx: read(arg),
"exec": lambda *args, ctx: shell.popen(*args).splitlines(), "exec": lambda *args, ctx: shell.popen(*args).splitlines(),
"latest": lambda arg, ctx: shell.latest(arg), "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 import os
from typing import Optional
def root() -> str | None:
def root() -> Optional[str]:
cwd = os.getcwd() cwd = os.getcwd()
while cwd != "/": while cwd != "/":
if os.path.isfile(os.path.join(cwd, "project.json")): if os.path.isfile(os.path.join(cwd, "project.json")):
@ -12,6 +14,7 @@ def root() -> str | None:
def chdir() -> None: def chdir() -> None:
projectRoot = root() projectRoot = root()
if projectRoot is None: if projectRoot is None:
raise RuntimeError("No project.json found in this directory or any parent directory") raise RuntimeError(
"No project.json found in this directory or any parent directory")
os.chdir(projectRoot)
os.chdir(projectRoot)

View file

@ -1,12 +1,15 @@
from typing import Optional
class Rule: class Rule:
id: str id: str
fileIn: list[str] fileIn: list[str]
fileOut: list[str] fileOut: list[str]
rule: str rule: str
args: list[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.id = id
self.fileIn = fileIn self.fileIn = fileIn
self.fileOut = fileOut self.fileOut = fileOut
@ -14,17 +17,18 @@ class Rule:
self.args = args self.args = args
self.deps = deps self.deps = deps
rules: dict[str, Rule] = { rules: dict[str, Rule] = {
"cc": Rule("cc", ["*.c"], ["*.o"], "-c -o $out $in -MD -MF $out.d $flags $cincs $cdefs", ["-std=gnu2x", "cc": Rule("cc", ["*.c"], ["*.o"], "-c -o $out $in -MD -MF $out.d $flags $cincs $cdefs", ["-std=gnu2x",
"-Wall", "-Wall",
"-Wextra", "-Wextra",
"-Werror"], "$out.d"), "-Werror"], "$out.d"),
"cxx": Rule("cxx", ["*.cpp", "*.cc", "*.cxx"], ["*.o"], "-c -o $out $in -MD -MF $out.d $flags $cincs $cdefs", ["-std=gnu++2b", "cxx": Rule("cxx", ["*.cpp", "*.cc", "*.cxx"], ["*.o"], "-c -o $out $in -MD -MF $out.d $flags $cincs $cdefs", ["-std=gnu++2b",
"-Wall", "-Wall",
"-Wextra", "-Wextra",
"-Werror", "-Werror",
"-fno-exceptions", "-fno-exceptions",
"-fno-rtti"], "$out.d"), "-fno-rtti"], "$out.d"),
"as": Rule("as", ["*.s", "*.asm", "*.S"], ["*.o"], "-o $out $in $flags"), "as": Rule("as", ["*.s", "*.asm", "*.S"], ["*.o"], "-o $out $in $flags"),
"ar": Rule("ar", ["*.o"], ["*.a"], "$flags $out $in"), "ar": Rule("ar", ["*.o"], ["*.a"], "$flags $out $in"),
"ld": Rule("ld", ["*.o", "*.a"], ["*.out"], "-o $out $in $flags"), "ld": Rule("ld", ["*.o", "*.a"], ["*.out"], "-o $out $in $flags"),
@ -35,7 +39,7 @@ def append(rule: Rule):
rules[rule.id] = rule rules[rule.id] = rule
def byFileIn(fileIn: str) -> Rule | None: def byFileIn(fileIn: str) -> Optional[Rule]:
for key in rules: for key in rules:
rule = rules[key] rule = rules[key]
for ext in rule.fileIn: for ext in rule.fileIn:
@ -44,5 +48,5 @@ def byFileIn(fileIn: str) -> Rule | None:
return None return None
def byId(id: str) -> Rule | None: def byId(id: str) -> Optional[Rule]:
return rules.get(id, None) return rules.get(id, None)

View file

@ -10,6 +10,7 @@ import fnmatch
import platform import platform
import logging import logging
from typing import Optional
from cutekit import const from cutekit import const
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -100,7 +101,7 @@ def rmrf(path: str) -> bool:
return True return True
def wget(url: str, path: str | None = None) -> str: def wget(url: str, path: Optional[str] = None) -> str:
import requests import requests
if path is None: 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 json
import hashlib import hashlib
@ -14,7 +14,7 @@ def uniq(l: list[str]) -> list[str]:
return result 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 = {} toHash = {}
if len(keys) == 0: if len(keys) == 0:
toHash = obj toHash = obj
@ -50,7 +50,7 @@ def key(obj: Any, keys: list[str] = []) -> str:
return "-".join(k) 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: if i is None:
return [] return []
if isinstance(i, list): if isinstance(i, list):