Skip to content

Commit 7a6ec3f

Browse files
authored
Merge pull request #4 from BeastByteAI/stdio_handler
spec 0.0.3, python v0.0.6
2 parents dafa63c + fbade8d commit 7a6ec3f

14 files changed

Lines changed: 904 additions & 6 deletions

File tree

spec/schemas/combined.json

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"version": "0.0.2",
2+
"version": "0.0.3",
33
"manifest": {
44
"$defs": {
55
"JSON": {
@@ -500,6 +500,21 @@
500500
},
501501
"title": "Dependencies",
502502
"type": "array"
503+
},
504+
"conda_channels": {
505+
"anyOf": [
506+
{
507+
"items": {
508+
"type": "string"
509+
},
510+
"type": "array"
511+
},
512+
{
513+
"type": "null"
514+
}
515+
],
516+
"default": null,
517+
"title": "Conda Channels"
503518
}
504519
},
505520
"required": [

spec/schemas/src/generate.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from pydantic_models.meta import MetaEntry
99
from pydantic_models.envs import Python3_CondaPip
1010

11-
SPEC_VERSION = "0.0.2"
11+
SPEC_VERSION = "0.0.3"
1212

1313
manifest_json_schema = Manifest.model_json_schema()
1414
ops_json_schema = OpInstances.model_json_schema()

spec/schemas/src/pydantic_models/envs.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ class Python3_CondaPip(BaseModel):
1818
python_version: str
1919
build_dependencies: list[str]
2020
dependencies: list[PipDependency]
21+
conda_channels: list[str] | None = None

src/python/fnnx/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "0.0.5"
1+
__version__ = "0.0.6"

src/python/fnnx/console.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
from __future__ import annotations
2+
3+
import shlex
4+
import shutil
5+
from contextlib import contextmanager
6+
7+
8+
class SimpleConsole:
9+
def __init__(self):
10+
self.is_tty = False
11+
self.use_unicode = False
12+
13+
def icon(self, kind: str) -> str:
14+
return {
15+
"info": "i",
16+
"ok": "+",
17+
"warn": "!",
18+
"err": "x",
19+
"run": ">",
20+
"spark": "*",
21+
}.get(kind, "*")
22+
23+
def rule(self, title: str = "") -> None:
24+
width = 80
25+
try:
26+
width = shutil.get_terminal_size((80, 20)).columns
27+
except Exception:
28+
pass
29+
line = "-" * max(1, width)
30+
if title:
31+
print(line)
32+
print(title)
33+
print(line)
34+
35+
def info(self, msg: str) -> None:
36+
print(f"{self.icon('info')} {msg}")
37+
38+
def success(self, msg: str) -> None:
39+
print(f"{self.icon('ok')} {msg}")
40+
41+
def warn(self, msg: str) -> None:
42+
print(f"{self.icon('warn')} {msg}")
43+
44+
def error(self, msg: str) -> None:
45+
print(f"{self.icon('err')} {msg}")
46+
47+
def cmd(self, argv: list[str], label: str = "run") -> None:
48+
try:
49+
joined = shlex.join(argv)
50+
except Exception:
51+
joined = " ".join(argv)
52+
print(f"{self.icon('run')} {label}: {joined}")
53+
54+
@contextmanager
55+
def spinner(self, text: str, detail: str | None = None):
56+
print(f"{self.icon('spark')} {text}" + (f" — {detail}" if detail else ""))
57+
try:
58+
yield
59+
except Exception as e:
60+
self.error(f"{text} failed: {e}")
61+
raise
62+
else:
63+
self.success(f"{text} done")
64+
65+
66+
# TODO
67+
# class AnsiConsole()
68+
69+
console = SimpleConsole()

src/python/fnnx/envs/_common.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import platform
2+
import subprocess
3+
import os
4+
5+
def select_pip_deps(raw_deps: list[dict], accelerator: str) -> list[dict]:
6+
sys_os = platform.system().lower() # 'linux', 'darwin', 'windows'
7+
machine = platform.machine().lower() # 'x86_64', 'arm64', ...
8+
accel = (accelerator or "cpu").lower()
9+
10+
out: list[dict] = []
11+
for d in raw_deps:
12+
cond = d.get("condition") or {}
13+
ok = True
14+
if cond.get("os"):
15+
ok = ok and sys_os in [o.lower() for o in cond["os"]]
16+
if cond.get("platform"):
17+
ok = ok and any(p.lower() in machine for p in cond["platform"])
18+
if cond.get("accelerator"):
19+
ok = ok and accel in [a.lower() for a in cond["accelerator"]]
20+
if ok:
21+
out.append(
22+
{"package": d["package"], "extra_pip_args": d.get("extra_pip_args")}
23+
)
24+
return out
25+
26+
27+
def run_cmd(
28+
cmd: list[str], *, env: dict[str, str] | None = None, capture: bool = True
29+
) -> str:
30+
if capture:
31+
proc = subprocess.run(cmd, env=env, text=True, capture_output=True)
32+
if proc.returncode != 0:
33+
raise RuntimeError(
34+
f"Command failed: {' '.join(cmd)}\n"
35+
f"STDOUT:\n{proc.stdout}\n\nSTDERR:\n{proc.stderr}"
36+
)
37+
return proc.stdout
38+
else:
39+
proc = subprocess.run(cmd, env=env, text=True)
40+
if proc.returncode != 0:
41+
raise RuntimeError(f"Command failed: {' '.join(cmd)}")
42+
return ""
43+
44+
45+
def which(exe: str):
46+
for path in os.environ.get("PATH", "").split(os.pathsep):
47+
cand = os.path.join(path, exe)
48+
if os.path.isfile(cand) and os.access(cand, os.X_OK):
49+
return cand
50+
return None

0 commit comments

Comments
 (0)