Skip to content

Commit 92b4d1d

Browse files
committed
feat: move runtime check rule zips to external repo
Remove zip files from git tracking and host them in gim-home/ModelKitArtifacts. Add download script and README with setup instructions for developers. - .gitignore: exclude runtime_check_rules/*.zip - scripts/download_rules.py: sparse checkout from source repo - runtime_check_rules/README.md: setup and manual copy instructions - runtime_checker_query.py: improved warning when zips are missing
1 parent fd43a2f commit 92b4d1d

5 files changed

Lines changed: 142 additions & 1 deletion

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,3 +261,6 @@ specs/
261261
/settings.local.json
262262
.claude/settings.local.json
263263
/sa_eval_results/
264+
265+
# Runtime check rule zips (hosted in external repo)
266+
src/winml/modelkit/analyze/rules/runtime_check_rules/*.zip

pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,8 @@ lint.per-file-ignores."__init__.py" = [ "D104", "E402", "F401", "F403" ]
256256
lint.per-file-ignores."examples/**" = [ "ANN", "D100", "D103", "S101", "T20" ]
257257
# E2E eval scripts: Allow print, long lines in HTML templates, try-except in loops
258258
lint.per-file-ignores."scripts/e2e_eval/**" = [ "ANN", "D103", "E501", "PERF203", "T20" ]
259+
# Download scripts: Allow subprocess, print, missing docstrings
260+
lint.per-file-ignores."scripts/download_rules.py" = [ "D103", "E501", "PERF401", "S603", "S607", "SIM108", "T20" ]
259261
# CLI: Allow print statements
260262
lint.per-file-ignores."src/winml/modelkit/cli.py" = [ "T20", "T201" ]
261263
lint.per-file-ignores."src/winml/modelkit/commands/**" = [ "T20", "T201" ]

scripts/download_rules.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# -------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Corporation. All rights reserved.
3+
# Licensed under the MIT License.
4+
# --------------------------------------------------------------------------
5+
"""Download runtime check rule zips from gim-home/ModelKitArtifacts.
6+
7+
Usage:
8+
uv run python scripts/download_rules.py # download missing zips
9+
uv run python scripts/download_rules.py --force # re-download all zips
10+
"""
11+
12+
import argparse
13+
import shutil
14+
import subprocess
15+
import sys
16+
import tempfile
17+
from pathlib import Path
18+
19+
20+
SOURCE_REPO = "gim-home/ModelKitArtifacts"
21+
SOURCE_URL = f"https://github.com/{SOURCE_REPO}.git"
22+
SOURCE_PATH = "op_check_results/rules"
23+
RULES_DIR = (
24+
Path(__file__).resolve().parent.parent
25+
/ "src"
26+
/ "winml"
27+
/ "modelkit"
28+
/ "analyze"
29+
/ "rules"
30+
/ "runtime_check_rules"
31+
)
32+
33+
34+
def _sparse_clone(clone_url: str, dest: Path) -> bool:
35+
"""Sparse-clone only the rules folder. Returns True on success."""
36+
result = subprocess.run(
37+
[
38+
"git",
39+
"clone",
40+
"--depth",
41+
"1",
42+
"--filter=blob:none",
43+
"--sparse",
44+
clone_url,
45+
str(dest),
46+
],
47+
capture_output=True,
48+
text=True,
49+
)
50+
if result.returncode != 0:
51+
return False
52+
result = subprocess.run(
53+
["git", "sparse-checkout", "set", SOURCE_PATH],
54+
cwd=dest,
55+
capture_output=True,
56+
text=True,
57+
)
58+
return result.returncode == 0
59+
60+
61+
def main() -> None:
62+
parser = argparse.ArgumentParser(description="Download runtime check rule zips")
63+
parser.add_argument("--force", action="store_true", help="Re-download all zips")
64+
args = parser.parse_args()
65+
66+
existing = set() if args.force else {f.name for f in RULES_DIR.glob("*.zip")}
67+
68+
with tempfile.TemporaryDirectory() as tmp:
69+
tmp_path = Path(tmp) / "repo"
70+
print(f"Cloning {SOURCE_REPO} (sparse: {SOURCE_PATH})...")
71+
72+
if not _sparse_clone(SOURCE_URL, tmp_path):
73+
print(
74+
f"ERROR: Failed to clone {SOURCE_REPO}.\n"
75+
"Make sure git credentials are configured for the gim-home org.",
76+
file=sys.stderr,
77+
)
78+
sys.exit(1)
79+
80+
src_dir = tmp_path / SOURCE_PATH
81+
zips = list(src_dir.glob("*.zip"))
82+
83+
if not zips:
84+
print(f"No zip files found in {SOURCE_REPO}/{SOURCE_PATH}")
85+
sys.exit(1)
86+
87+
RULES_DIR.mkdir(parents=True, exist_ok=True)
88+
copied = 0
89+
for zip_file in zips:
90+
if zip_file.name in existing:
91+
continue
92+
shutil.copy2(zip_file, RULES_DIR / zip_file.name)
93+
copied += 1
94+
95+
total = len(zips)
96+
skipped = total - copied
97+
size_mb = sum((RULES_DIR / z.name).stat().st_size for z in zips) / 1024 / 1024
98+
print(f"Done. Copied: {copied}, skipped: {skipped}, total: {total} ({size_mb:.0f} MB)")
99+
100+
101+
if __name__ == "__main__":
102+
main()

src/winml/modelkit/analyze/core/runtime_checker_query.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,10 @@ def _ensure_loaded(self) -> None:
138138
import zipfile
139139

140140
if not self._zip_path.exists():
141+
logger.debug(
142+
"Rule zip not found: %s. Copy rule zips from gim-home/ModelKitArtifacts.",
143+
self._zip_path,
144+
)
141145
return
142146
try:
143147
with zipfile.ZipFile(self._zip_path, "r") as zf:
@@ -211,7 +215,12 @@ def _load(self) -> None:
211215
if self._set_error_on_missing:
212216
self[EG_RULE_ERROR_KEY] = "rules_zip_not_found"
213217
self[EG_RULE_DEBUG_DETAILS_KEY] = str(self._zip_path)
214-
logger.warning(f"Rule zip file not found: {self._zip_path}")
218+
logger.warning(
219+
"Rule zip file not found: %s. "
220+
"Copy rule zips from gim-home/ModelKitArtifacts to "
221+
"src/winml/modelkit/analyze/rules/runtime_check_rules/",
222+
self._zip_path,
223+
)
215224
return
216225

217226
with zipfile.ZipFile(self._zip_path, "r") as zf:
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Runtime Check Rules
2+
3+
This directory contains zip files with runtime check rules (negative rules and tables) used by the static analyzer. Each zip corresponds to a specific `{EP}_{Device}_{Domain}_opset{N}` combination.
4+
5+
The zip files are **not tracked by git**. They are hosted in a separate repo.
6+
7+
## Setup
8+
9+
### Option 1: Download script (recommended)
10+
11+
```bash
12+
uv run python scripts/download_rules.py
13+
```
14+
15+
The script does a sparse checkout (downloads only the zip folder, not the full repo) and copies files here. Requires git credentials configured for the `gim-home` org.
16+
17+
Use `--force` to re-download all files even if they already exist locally.
18+
19+
### Option 2: Manual copy
20+
21+
Copy all `*.zip` files from [`gim-home/ModelKitArtifacts/op_check_results/rules/`](https://github.com/gim-home/ModelKitArtifacts/tree/main/op_check_results/rules) into this directory.
22+
23+
## What happens if zips are missing
24+
25+
The analyzer will log a warning and treat affected operators as unknown. Analysis results will be incomplete but will not crash.

0 commit comments

Comments
 (0)