generic-ml-cache-cli 0.2.0__tar.gz → 0.3.0__tar.gz
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.
- {generic_ml_cache_cli-0.2.0 → generic_ml_cache_cli-0.3.0}/PKG-INFO +2 -2
- {generic_ml_cache_cli-0.2.0 → generic_ml_cache_cli-0.3.0}/pyproject.toml +2 -2
- {generic_ml_cache_cli-0.2.0 → generic_ml_cache_cli-0.3.0}/src/generic_ml_cache_cli/cli.py +26 -1
- {generic_ml_cache_cli-0.2.0 → generic_ml_cache_cli-0.3.0}/tests/test_cli.py +45 -0
- {generic_ml_cache_cli-0.2.0 → generic_ml_cache_cli-0.3.0}/.gitignore +0 -0
- {generic_ml_cache_cli-0.2.0 → generic_ml_cache_cli-0.3.0}/LICENSE +0 -0
- {generic_ml_cache_cli-0.2.0 → generic_ml_cache_cli-0.3.0}/NOTICE +0 -0
- {generic_ml_cache_cli-0.2.0 → generic_ml_cache_cli-0.3.0}/README.md +0 -0
- {generic_ml_cache_cli-0.2.0 → generic_ml_cache_cli-0.3.0}/src/generic_ml_cache_cli/__init__.py +0 -0
- {generic_ml_cache_cli-0.2.0 → generic_ml_cache_cli-0.3.0}/src/generic_ml_cache_cli/__main__.py +0 -0
- {generic_ml_cache_cli-0.2.0 → generic_ml_cache_cli-0.3.0}/src/generic_ml_cache_cli/config.py +0 -0
- {generic_ml_cache_cli-0.2.0 → generic_ml_cache_cli-0.3.0}/tests/conftest.py +0 -0
- {generic_ml_cache_cli-0.2.0 → generic_ml_cache_cli-0.3.0}/tests/fake_client.py +0 -0
- {generic_ml_cache_cli-0.2.0 → generic_ml_cache_cli-0.3.0}/tests/test_config.py +0 -0
- {generic_ml_cache_cli-0.2.0 → generic_ml_cache_cli-0.3.0}/tests/test_discover.py +0 -0
- {generic_ml_cache_cli-0.2.0 → generic_ml_cache_cli-0.3.0}/tests/test_effort.py +0 -0
- {generic_ml_cache_cli-0.2.0 → generic_ml_cache_cli-0.3.0}/tests/test_interrupt.py +0 -0
- {generic_ml_cache_cli-0.2.0 → generic_ml_cache_cli-0.3.0}/tests/test_models.py +0 -0
- {generic_ml_cache_cli-0.2.0 → generic_ml_cache_cli-0.3.0}/tests/test_passthrough.py +0 -0
- {generic_ml_cache_cli-0.2.0 → generic_ml_cache_cli-0.3.0}/tests/test_robustness.py +0 -0
- {generic_ml_cache_cli-0.2.0 → generic_ml_cache_cli-0.3.0}/tests/test_stdin_delivery.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: generic-ml-cache-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Terminal UI for generic-ml-cache: the gmlcache command. A thin inbound driver over generic-ml-cache-core -- reads config, provides the data source, maps commands onto the core library.
|
|
5
5
|
Project-URL: Homepage, https://github.com/danielslobozian/generic-ml-cache
|
|
6
6
|
Project-URL: Repository, https://github.com/danielslobozian/generic-ml-cache
|
|
@@ -24,7 +24,7 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
24
24
|
Classifier: Topic :: Utilities
|
|
25
25
|
Requires-Python: >=3.9
|
|
26
26
|
Requires-Dist: argcomplete<4,>=3
|
|
27
|
-
Requires-Dist: generic-ml-cache-core>=0.
|
|
27
|
+
Requires-Dist: generic-ml-cache-core>=0.3.0
|
|
28
28
|
Provides-Extra: dev
|
|
29
29
|
Requires-Dist: coverage>=7; extra == 'dev'
|
|
30
30
|
Requires-Dist: pytest-cov; extra == 'dev'
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "generic-ml-cache-cli"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.3.0"
|
|
8
8
|
description = "Terminal UI for generic-ml-cache: the gmlcache command. A thin inbound driver over generic-ml-cache-core -- reads config, provides the data source, maps commands onto the core library."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -25,7 +25,7 @@ classifiers = [
|
|
|
25
25
|
"Programming Language :: Python :: 3.13",
|
|
26
26
|
"Topic :: Utilities",
|
|
27
27
|
]
|
|
28
|
-
dependencies = ["generic-ml-cache-core>=0.
|
|
28
|
+
dependencies = ["generic-ml-cache-core>=0.3.0", "argcomplete>=3,<4"]
|
|
29
29
|
|
|
30
30
|
[project.urls]
|
|
31
31
|
Homepage = "https://github.com/danielslobozian/generic-ml-cache"
|
|
@@ -172,6 +172,7 @@ def _cmd_run(args: argparse.Namespace) -> int:
|
|
|
172
172
|
grants=list(getattr(args, "grant", None) or []),
|
|
173
173
|
cache_mode=cache_mode,
|
|
174
174
|
record_on_error=args.record_on_error,
|
|
175
|
+
tags=list(getattr(args, "tag", None) or []),
|
|
175
176
|
)
|
|
176
177
|
|
|
177
178
|
def executable_override(client: str):
|
|
@@ -550,11 +551,15 @@ def _cmd_list(args: argparse.Namespace) -> int:
|
|
|
550
551
|
"kind": summary.kind,
|
|
551
552
|
"key": summary.execution_key,
|
|
552
553
|
"hits": hit_counts.get(summary.execution_key, 0),
|
|
554
|
+
"tags": wired.repository.tags_for(summary.execution_key),
|
|
553
555
|
}
|
|
554
556
|
for summary in wired.repository.current_execution_summaries()
|
|
555
557
|
if (not args.client or summary.client == args.client)
|
|
556
558
|
and (not args.model or summary.model == args.model)
|
|
557
559
|
]
|
|
560
|
+
wanted_tags = set(getattr(args, "tag", None) or [])
|
|
561
|
+
if wanted_tags:
|
|
562
|
+
entries = [entry for entry in entries if wanted_tags & set(entry["tags"])]
|
|
558
563
|
|
|
559
564
|
if args.json:
|
|
560
565
|
print(json.dumps({"executions": entries}, indent=2))
|
|
@@ -568,10 +573,13 @@ def _cmd_list(args: argparse.Namespace) -> int:
|
|
|
568
573
|
for entry in sorted(entries, key=lambda item: (item["client"], item["model"], item["key"])):
|
|
569
574
|
hits = entry["hits"]
|
|
570
575
|
hits_text = _paint(str(hits), _GREEN) if hits else _paint(str(hits), _GREY)
|
|
571
|
-
|
|
576
|
+
line = (
|
|
572
577
|
f" {entry['client']:<8} {entry['model']:<20} {entry['kind']:<18} "
|
|
573
578
|
f"{_paint(entry['key'][:12], _GREY)} hits:{hits_text}"
|
|
574
579
|
)
|
|
580
|
+
if entry["tags"]:
|
|
581
|
+
line += " tags:" + _paint(",".join(entry["tags"]), _TEAL)
|
|
582
|
+
print(line)
|
|
575
583
|
return 0
|
|
576
584
|
|
|
577
585
|
|
|
@@ -709,6 +717,16 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
709
717
|
choices=GRANT_CHOICES,
|
|
710
718
|
help=_GRANT_HELP,
|
|
711
719
|
)
|
|
720
|
+
run.add_argument(
|
|
721
|
+
"--tag",
|
|
722
|
+
action="append",
|
|
723
|
+
dest="tag",
|
|
724
|
+
metavar="TAG",
|
|
725
|
+
help=(
|
|
726
|
+
"label this execution with a tag for later grouping/queries (repeatable; "
|
|
727
|
+
"metadata only -- never part of the cache key). A relabel on a hit accumulates."
|
|
728
|
+
),
|
|
729
|
+
)
|
|
712
730
|
run.add_argument(
|
|
713
731
|
"--json",
|
|
714
732
|
action="store_true",
|
|
@@ -840,6 +858,13 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
840
858
|
)
|
|
841
859
|
listp.add_argument("--client", help="only executions recorded for this client")
|
|
842
860
|
listp.add_argument("--model", help="only executions recorded for this model")
|
|
861
|
+
listp.add_argument(
|
|
862
|
+
"--tag",
|
|
863
|
+
action="append",
|
|
864
|
+
dest="tag",
|
|
865
|
+
metavar="TAG",
|
|
866
|
+
help="only executions carrying any of these tags (repeatable; match-any)",
|
|
867
|
+
)
|
|
843
868
|
listp.add_argument("--json", action="store_true", help="emit machine-readable JSON")
|
|
844
869
|
listp.set_defaults(func=_cmd_list)
|
|
845
870
|
|
|
@@ -324,3 +324,48 @@ def test_check_reports_hit_after_a_run(tmp_path, monkeypatch, capsys):
|
|
|
324
324
|
out = capsys.readouterr().out
|
|
325
325
|
assert rc == 0
|
|
326
326
|
assert "status : hit" in out
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
def test_run_tag_stores_tags_through_the_cli(tmp_path):
|
|
330
|
+
import glob
|
|
331
|
+
import sqlite3
|
|
332
|
+
|
|
333
|
+
rc = run_cli(
|
|
334
|
+
[
|
|
335
|
+
"run",
|
|
336
|
+
"--client",
|
|
337
|
+
"fake",
|
|
338
|
+
"--model",
|
|
339
|
+
"m1",
|
|
340
|
+
"--effort",
|
|
341
|
+
"high",
|
|
342
|
+
"--prompt",
|
|
343
|
+
"STDOUT hi",
|
|
344
|
+
"--tag",
|
|
345
|
+
"ticket",
|
|
346
|
+
"--tag",
|
|
347
|
+
"id-scan",
|
|
348
|
+
]
|
|
349
|
+
)
|
|
350
|
+
assert rc == 0
|
|
351
|
+
stores = glob.glob(str(tmp_path / "**" / "executions.sqlite3"), recursive=True)
|
|
352
|
+
assert stores, "no executions store was written"
|
|
353
|
+
connection = sqlite3.connect(stores[0])
|
|
354
|
+
stored = sorted(tag for (tag,) in connection.execute("SELECT tag FROM execution_tags"))
|
|
355
|
+
connection.close()
|
|
356
|
+
assert stored == ["id-scan", "ticket"]
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
def test_list_filters_by_tag_and_shows_tags(capsys):
|
|
360
|
+
import json
|
|
361
|
+
|
|
362
|
+
base = ["run", "--client", "fake", "--model", "m1", "--effort", "high"]
|
|
363
|
+
run_cli(base + ["--prompt", "STDOUT a", "--tag", "alpha"])
|
|
364
|
+
run_cli(base + ["--prompt", "STDOUT b", "--tag", "beta"])
|
|
365
|
+
capsys.readouterr()
|
|
366
|
+
|
|
367
|
+
rc = main(["list", "--tag", "alpha", "--json"])
|
|
368
|
+
assert rc == 0
|
|
369
|
+
listed = json.loads(capsys.readouterr().out)["executions"]
|
|
370
|
+
assert len(listed) == 1 # match-any filter keeps only the alpha-tagged entry
|
|
371
|
+
assert listed[0]["tags"] == ["alpha"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{generic_ml_cache_cli-0.2.0 → generic_ml_cache_cli-0.3.0}/src/generic_ml_cache_cli/__init__.py
RENAMED
|
File without changes
|
{generic_ml_cache_cli-0.2.0 → generic_ml_cache_cli-0.3.0}/src/generic_ml_cache_cli/__main__.py
RENAMED
|
File without changes
|
{generic_ml_cache_cli-0.2.0 → generic_ml_cache_cli-0.3.0}/src/generic_ml_cache_cli/config.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|