wafer-cli 0.2.23__py3-none-any.whl → 0.2.24__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- wafer/cli.py +49 -0
- wafer/evaluate.py +0 -9
- wafer/wevin_cli.py +13 -1
- wafer/workspaces.py +96 -0
- {wafer_cli-0.2.23.dist-info → wafer_cli-0.2.24.dist-info}/METADATA +1 -1
- {wafer_cli-0.2.23.dist-info → wafer_cli-0.2.24.dist-info}/RECORD +9 -9
- {wafer_cli-0.2.23.dist-info → wafer_cli-0.2.24.dist-info}/WHEEL +0 -0
- {wafer_cli-0.2.23.dist-info → wafer_cli-0.2.24.dist-info}/entry_points.txt +0 -0
- {wafer_cli-0.2.23.dist-info → wafer_cli-0.2.24.dist-info}/top_level.txt +0 -0
wafer/cli.py
CHANGED
|
@@ -4975,6 +4975,55 @@ def workspaces_sync(
|
|
|
4975
4975
|
raise typer.Exit(1) from None
|
|
4976
4976
|
|
|
4977
4977
|
|
|
4978
|
+
@workspaces_app.command("pull")
|
|
4979
|
+
def workspaces_pull(
|
|
4980
|
+
workspace: str = typer.Argument(..., help="Workspace name or ID"),
|
|
4981
|
+
remote_path: str = typer.Argument(..., help="Remote path in workspace (relative to /workspace or absolute)"),
|
|
4982
|
+
local_path: Path = typer.Argument(
|
|
4983
|
+
Path("."), help="Local destination path (default: current directory)"
|
|
4984
|
+
),
|
|
4985
|
+
verbose: bool = typer.Option(False, "--verbose", "-v", help="Show [wafer] status messages"),
|
|
4986
|
+
quiet: bool = typer.Option(False, "--quiet", "-q", help="Suppress [wafer] status messages"),
|
|
4987
|
+
) -> None:
|
|
4988
|
+
"""Pull files from workspace to local machine.
|
|
4989
|
+
|
|
4990
|
+
Uses rsync over SSH to download files from the workspace's /workspace directory.
|
|
4991
|
+
|
|
4992
|
+
Examples:
|
|
4993
|
+
wafer workspaces pull dev kernel.py ./ # Pull single file
|
|
4994
|
+
wafer workspaces pull dev kernel.py ./my_kernel.py # Pull and rename
|
|
4995
|
+
wafer workspaces pull dev /workspace/results ./ # Pull directory
|
|
4996
|
+
"""
|
|
4997
|
+
from .global_config import get_preferences
|
|
4998
|
+
from .workspaces import pull_files
|
|
4999
|
+
|
|
5000
|
+
# Determine verbosity based on mode
|
|
5001
|
+
prefs = get_preferences()
|
|
5002
|
+
if quiet:
|
|
5003
|
+
show_status = False
|
|
5004
|
+
elif verbose:
|
|
5005
|
+
show_status = True
|
|
5006
|
+
else:
|
|
5007
|
+
show_status = prefs.mode == "explicit"
|
|
5008
|
+
|
|
5009
|
+
if show_status:
|
|
5010
|
+
typer.echo(f"[wafer] Pulling {remote_path} from workspace {workspace}...", err=True)
|
|
5011
|
+
|
|
5012
|
+
def on_progress(msg: str) -> None:
|
|
5013
|
+
if show_status:
|
|
5014
|
+
typer.echo(f"[wafer] {msg}", err=True)
|
|
5015
|
+
|
|
5016
|
+
try:
|
|
5017
|
+
file_count = pull_files(
|
|
5018
|
+
workspace, remote_path, local_path.resolve(), on_progress=on_progress
|
|
5019
|
+
)
|
|
5020
|
+
if show_status:
|
|
5021
|
+
typer.echo(f"[wafer] Pulled {file_count} files to {local_path}", err=True)
|
|
5022
|
+
except RuntimeError as e:
|
|
5023
|
+
typer.echo(f"Error: {e}", err=True)
|
|
5024
|
+
raise typer.Exit(1) from None
|
|
5025
|
+
|
|
5026
|
+
|
|
4978
5027
|
# =============================================================================
|
|
4979
5028
|
# Target operations commands (exec/ssh/sync)
|
|
4980
5029
|
# =============================================================================
|
wafer/evaluate.py
CHANGED
|
@@ -2801,15 +2801,6 @@ if torch.cuda.is_available():
|
|
|
2801
2801
|
gc.collect()
|
|
2802
2802
|
torch.cuda.empty_cache()
|
|
2803
2803
|
torch.cuda.reset_peak_memory_stats()
|
|
2804
|
-
|
|
2805
|
-
# Enable TF32 for fair benchmarking against reference kernels.
|
|
2806
|
-
# PyTorch 1.12+ disables TF32 for matmul by default, which handicaps
|
|
2807
|
-
# reference kernels using cuBLAS. We enable it so reference kernels
|
|
2808
|
-
# run at their best performance (using tensor cores when applicable).
|
|
2809
|
-
# This ensures speedup comparisons are against optimized baselines.
|
|
2810
|
-
torch.backends.cuda.matmul.allow_tf32 = True
|
|
2811
|
-
torch.backends.cudnn.allow_tf32 = True
|
|
2812
|
-
print("[KernelBench] TF32 enabled for fair benchmarking")
|
|
2813
2804
|
|
|
2814
2805
|
|
|
2815
2806
|
def _calculate_timing_stats(times: list[float]) -> dict:
|
wafer/wevin_cli.py
CHANGED
|
@@ -205,10 +205,22 @@ def _get_session_preview(session: object) -> str:
|
|
|
205
205
|
return ""
|
|
206
206
|
|
|
207
207
|
|
|
208
|
+
def _get_log_file_path() -> Path:
|
|
209
|
+
"""Get user-specific log file path, creating directory if needed.
|
|
210
|
+
|
|
211
|
+
Uses ~/.wafer/logs/ to avoid permission issues with shared /tmp.
|
|
212
|
+
"""
|
|
213
|
+
log_dir = Path.home() / ".wafer" / "logs"
|
|
214
|
+
log_dir.mkdir(parents=True, exist_ok=True)
|
|
215
|
+
return log_dir / "wevin_debug.log"
|
|
216
|
+
|
|
217
|
+
|
|
208
218
|
def _setup_logging() -> None:
|
|
209
219
|
"""Configure logging to file only (no console spam)."""
|
|
210
220
|
import logging.config
|
|
211
221
|
|
|
222
|
+
log_file = _get_log_file_path()
|
|
223
|
+
|
|
212
224
|
logging.config.dictConfig({
|
|
213
225
|
"version": 1,
|
|
214
226
|
"disable_existing_loggers": False,
|
|
@@ -220,7 +232,7 @@ def _setup_logging() -> None:
|
|
|
220
232
|
"handlers": {
|
|
221
233
|
"file": {
|
|
222
234
|
"class": "logging.handlers.RotatingFileHandler",
|
|
223
|
-
"filename":
|
|
235
|
+
"filename": str(log_file),
|
|
224
236
|
"maxBytes": 10_000_000,
|
|
225
237
|
"backupCount": 3,
|
|
226
238
|
"formatter": "json",
|
wafer/workspaces.py
CHANGED
|
@@ -542,6 +542,102 @@ def sync_files(
|
|
|
542
542
|
return file_count, warning
|
|
543
543
|
|
|
544
544
|
|
|
545
|
+
def pull_files(
|
|
546
|
+
workspace_id: str,
|
|
547
|
+
remote_path: str,
|
|
548
|
+
local_path: Path,
|
|
549
|
+
on_progress: Callable[[str], None] | None = None,
|
|
550
|
+
) -> int:
|
|
551
|
+
"""Pull files from workspace to local via rsync over SSH.
|
|
552
|
+
|
|
553
|
+
Args:
|
|
554
|
+
workspace_id: Workspace ID or name
|
|
555
|
+
remote_path: Remote path in workspace (relative to /workspace or absolute)
|
|
556
|
+
local_path: Local destination path
|
|
557
|
+
on_progress: Optional callback for progress messages
|
|
558
|
+
|
|
559
|
+
Returns:
|
|
560
|
+
Number of files transferred
|
|
561
|
+
|
|
562
|
+
Raises:
|
|
563
|
+
RuntimeError: If rsync fails or workspace not accessible
|
|
564
|
+
"""
|
|
565
|
+
import subprocess
|
|
566
|
+
|
|
567
|
+
def emit(msg: str) -> None:
|
|
568
|
+
if on_progress:
|
|
569
|
+
on_progress(msg)
|
|
570
|
+
|
|
571
|
+
assert workspace_id, "Workspace ID must be non-empty"
|
|
572
|
+
|
|
573
|
+
ws = get_workspace_raw(workspace_id)
|
|
574
|
+
workspace_status = ws.get("status")
|
|
575
|
+
assert workspace_status in VALID_STATUSES, (
|
|
576
|
+
f"Workspace {workspace_id} has invalid status '{workspace_status}'. "
|
|
577
|
+
f"Valid statuses: {VALID_STATUSES}"
|
|
578
|
+
)
|
|
579
|
+
if workspace_status == "error":
|
|
580
|
+
raise RuntimeError(
|
|
581
|
+
f"Workspace provisioning failed. Delete and recreate:\n"
|
|
582
|
+
f" wafer workspaces delete {workspace_id}\n"
|
|
583
|
+
f" wafer workspaces create {ws.get('name', workspace_id)} --wait"
|
|
584
|
+
)
|
|
585
|
+
if workspace_status != "running":
|
|
586
|
+
raise RuntimeError(
|
|
587
|
+
f"Workspace is {workspace_status}. Wait for it to be running before pulling files."
|
|
588
|
+
)
|
|
589
|
+
ssh_host = ws.get("ssh_host")
|
|
590
|
+
ssh_port = ws.get("ssh_port")
|
|
591
|
+
ssh_user = ws.get("ssh_user")
|
|
592
|
+
if not ssh_host or not ssh_port or not ssh_user:
|
|
593
|
+
raise RuntimeError(
|
|
594
|
+
f"Workspace is running but SSH not ready.\n"
|
|
595
|
+
f" Delete and recreate: wafer workspaces delete {workspace_id}\n"
|
|
596
|
+
f" Then: wafer workspaces create {ws.get('name', workspace_id)} --wait"
|
|
597
|
+
)
|
|
598
|
+
assert isinstance(ssh_port, int) and ssh_port > 0, "Workspace missing valid ssh_port"
|
|
599
|
+
|
|
600
|
+
# Normalize remote path - if not absolute, assume relative to /workspace
|
|
601
|
+
if not remote_path.startswith("/"):
|
|
602
|
+
remote_path = f"/workspace/{remote_path}"
|
|
603
|
+
|
|
604
|
+
# Build SSH command for rsync
|
|
605
|
+
ssh_opts = f"-p {ssh_port} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
|
|
606
|
+
|
|
607
|
+
# Build rsync command (reverse of sync - from remote to local)
|
|
608
|
+
rsync_cmd = [
|
|
609
|
+
"rsync",
|
|
610
|
+
"-avz",
|
|
611
|
+
"-e",
|
|
612
|
+
f"ssh {ssh_opts}",
|
|
613
|
+
f"{ssh_user}@{ssh_host}:{remote_path}",
|
|
614
|
+
str(local_path),
|
|
615
|
+
]
|
|
616
|
+
|
|
617
|
+
emit(f"Pulling {remote_path} from workspace...")
|
|
618
|
+
|
|
619
|
+
try:
|
|
620
|
+
result = subprocess.run(rsync_cmd, capture_output=True, text=True)
|
|
621
|
+
if result.returncode != 0:
|
|
622
|
+
raise RuntimeError(f"rsync failed: {result.stderr}")
|
|
623
|
+
|
|
624
|
+
# Count files from rsync output
|
|
625
|
+
lines = result.stdout.strip().split("\n")
|
|
626
|
+
file_count = sum(
|
|
627
|
+
1
|
|
628
|
+
for line in lines
|
|
629
|
+
if line and not line.startswith((" ", "sent", "total", "receiving", "building"))
|
|
630
|
+
)
|
|
631
|
+
|
|
632
|
+
except FileNotFoundError:
|
|
633
|
+
raise RuntimeError("rsync not found. Install rsync to use pull feature.") from None
|
|
634
|
+
except subprocess.SubprocessError as e:
|
|
635
|
+
raise RuntimeError(f"Pull failed: {e}") from e
|
|
636
|
+
|
|
637
|
+
emit(f"Pulled {file_count} files")
|
|
638
|
+
return file_count
|
|
639
|
+
|
|
640
|
+
|
|
545
641
|
def _init_sync_state(workspace_id: str) -> str | None:
|
|
546
642
|
"""Tell API to sync files from bare metal to Modal volume.
|
|
547
643
|
|
|
@@ -5,10 +5,10 @@ wafer/api_client.py,sha256=i_Az2b2llC3DSW8yOL-BKqa7LSKuxOr8hSN40s-oQXY,6313
|
|
|
5
5
|
wafer/auth.py,sha256=dwss_se5P-FFc9IN38q4kh_dBrA6k-CguDBkivgcdj0,14003
|
|
6
6
|
wafer/autotuner.py,sha256=41WYP41pTDvMijv2h42vm89bcHtDMJXObDlWmn6xpFU,44416
|
|
7
7
|
wafer/billing.py,sha256=jbLB2lI4_9f2KD8uEFDi_ixLlowe5hasC0TIZJyIXRg,7163
|
|
8
|
-
wafer/cli.py,sha256=
|
|
8
|
+
wafer/cli.py,sha256=tk7wnmwZiqlOT39E3EVVwgD-2Y0eAfLSAbif7IpLijY,263288
|
|
9
9
|
wafer/config.py,sha256=h5Eo9_yfWqWGoPNdVQikI9GoZVUeysunSYiixf1mKcw,3411
|
|
10
10
|
wafer/corpus.py,sha256=oQegXA43MuyRvYxOsWhmqeP5vMb5IKFHOvM-1RcahPA,22301
|
|
11
|
-
wafer/evaluate.py,sha256=
|
|
11
|
+
wafer/evaluate.py,sha256=I0JwipvkkOIiiYaIyqe-HMSfYdTPkUtJXvs_1w_gJSQ,190413
|
|
12
12
|
wafer/global_config.py,sha256=fhaR_RU3ufMksDmOohH1OLeQ0JT0SDW1hEip_zaP75k,11345
|
|
13
13
|
wafer/gpu_run.py,sha256=TwqXy72T7f2I7e6n5WWod3xgxCPnDhU0BgLsB4CUoQY,9716
|
|
14
14
|
wafer/inference.py,sha256=tZCO5i05FKY27ewis3CSBHFBeFbXY3xwj0DSjdoMY9s,4314
|
|
@@ -26,16 +26,16 @@ wafer/target_lock.py,sha256=SDKhNzv2N7gsphGflcNni9FE5YYuAMuEthngAJEo4Gs,7809
|
|
|
26
26
|
wafer/targets.py,sha256=9r-iRWoKSH5cQl1LcamaX-T7cNVOg99ngIm_hlRk-qU,26922
|
|
27
27
|
wafer/targets_ops.py,sha256=jN1oIBx0mutxRNE9xpIc7SaBxPkVmOyus2eqn0kEKNI,21475
|
|
28
28
|
wafer/tracelens.py,sha256=g9ZIeFyNojZn4uTd3skPqIrRiL7aMJOz_-GOd3aiyy4,7998
|
|
29
|
-
wafer/wevin_cli.py,sha256=
|
|
30
|
-
wafer/workspaces.py,sha256=
|
|
29
|
+
wafer/wevin_cli.py,sha256=UwRibTYmIR99EjDupoyFm8gjhMs0vHXTkS4wQuiskho,23537
|
|
30
|
+
wafer/workspaces.py,sha256=k_iCZ-mOrG2KiTXqqcZ5_VifSIXsFGaZM4hjnxBnBmc,35666
|
|
31
31
|
wafer/skills/wafer-guide/SKILL.md,sha256=KWetJw2TVTbz11_nzqazqOJWWRlbHRFShs4sOoreiWo,3255
|
|
32
32
|
wafer/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
33
33
|
wafer/templates/ask_docs.py,sha256=Lxs-faz9v5m4Qa4NjF2X_lE8KwM9ES9MNJkxo7ep56o,2256
|
|
34
34
|
wafer/templates/optimize_kernel.py,sha256=OvZgN5tm_OymO3lK8Dr0VO48e-5PfNVIIoACrPxpmqk,2446
|
|
35
35
|
wafer/templates/optimize_kernelbench.py,sha256=aoOA13zWEl89r6QW03xF9NKxQ7j4mWe9rwua6-mlr4Y,4780
|
|
36
36
|
wafer/templates/trace_analyze.py,sha256=XE1VqzVkIUsZbXF8EzQdDYgg-AZEYAOFpr6B_vnRELc,2880
|
|
37
|
-
wafer_cli-0.2.
|
|
38
|
-
wafer_cli-0.2.
|
|
39
|
-
wafer_cli-0.2.
|
|
40
|
-
wafer_cli-0.2.
|
|
41
|
-
wafer_cli-0.2.
|
|
37
|
+
wafer_cli-0.2.24.dist-info/METADATA,sha256=zoGLJsbN_xgLNwaGRnUll2HY545hFXoBYwYtzeGmlvo,560
|
|
38
|
+
wafer_cli-0.2.24.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
39
|
+
wafer_cli-0.2.24.dist-info/entry_points.txt,sha256=WqB7hB__WhtPY8y1cO2sZiUz7fCq6Ik-usAigpeFvWE,41
|
|
40
|
+
wafer_cli-0.2.24.dist-info/top_level.txt,sha256=2MK1IVMWfpLL8BZCQ3E9aG6L6L666gSA_teYlwan4fs,6
|
|
41
|
+
wafer_cli-0.2.24.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|