rosetta-sql 1.0.0__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.
- benchmark/generate_csv_data.py +83 -0
- benchmark/import_data.py +168 -0
- rosetta/__init__.py +3 -0
- rosetta/__main__.py +8 -0
- rosetta/benchmark.py +1678 -0
- rosetta/buglist.py +108 -0
- rosetta/cli/__init__.py +11 -0
- rosetta/cli/config_cmd.py +243 -0
- rosetta/cli/exec.py +219 -0
- rosetta/cli/interactive_cmd.py +124 -0
- rosetta/cli/list_cmd.py +215 -0
- rosetta/cli/main.py +617 -0
- rosetta/cli/output.py +545 -0
- rosetta/cli/result.py +61 -0
- rosetta/cli/result_cmd.py +247 -0
- rosetta/cli/run.py +625 -0
- rosetta/cli/status.py +161 -0
- rosetta/comparator.py +205 -0
- rosetta/config.py +139 -0
- rosetta/executor.py +403 -0
- rosetta/flamegraph.py +630 -0
- rosetta/interactive.py +1790 -0
- rosetta/models.py +197 -0
- rosetta/parser.py +308 -0
- rosetta/reporter/__init__.py +1 -0
- rosetta/reporter/bench_html.py +1457 -0
- rosetta/reporter/bench_text.py +162 -0
- rosetta/reporter/history.py +1686 -0
- rosetta/reporter/html.py +644 -0
- rosetta/reporter/text.py +110 -0
- rosetta/runner.py +3089 -0
- rosetta/ui.py +736 -0
- rosetta/whitelist.py +161 -0
- rosetta_sql-1.0.0.dist-info/LICENSE +21 -0
- rosetta_sql-1.0.0.dist-info/METADATA +379 -0
- rosetta_sql-1.0.0.dist-info/RECORD +42 -0
- rosetta_sql-1.0.0.dist-info/WHEEL +5 -0
- rosetta_sql-1.0.0.dist-info/entry_points.txt +2 -0
- rosetta_sql-1.0.0.dist-info/top_level.txt +4 -0
- skills/rosetta/scripts/install_rosetta.py +469 -0
- skills/rosetta/scripts/rosetta_wrapper.py +377 -0
- tests/test_cli.py +749 -0
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Handler for the 'result' subcommand — list / show / export historical runs.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
7
|
+
import re
|
|
8
|
+
from typing import TYPE_CHECKING, List, Dict, Any, Optional
|
|
9
|
+
|
|
10
|
+
from .result import CommandResult
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from .output import OutputFormatter
|
|
14
|
+
|
|
15
|
+
# ---------------------------------------------------------------------------
|
|
16
|
+
# Pattern for run directory names produced by rosetta
|
|
17
|
+
# bench_json_mv_ddl_20260326_141650
|
|
18
|
+
# array_index_20260313_144633
|
|
19
|
+
# ---------------------------------------------------------------------------
|
|
20
|
+
_TIMESTAMP_RE = re.compile(r"(\d{8}_\d{6})$")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def handle_result(args, output: "OutputFormatter") -> CommandResult:
|
|
24
|
+
"""Dispatch result sub-actions."""
|
|
25
|
+
action = getattr(args, "result_action", None)
|
|
26
|
+
|
|
27
|
+
# ``rosetta result`` with no sub-action → default to list
|
|
28
|
+
if not action:
|
|
29
|
+
action = "list"
|
|
30
|
+
|
|
31
|
+
if action == "list":
|
|
32
|
+
return _handle_list(args, output)
|
|
33
|
+
elif action == "show":
|
|
34
|
+
return _handle_show(args, output)
|
|
35
|
+
else:
|
|
36
|
+
return CommandResult.failure(f"Unknown result action: {action}")
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# ---------------------------------------------------------------------------
|
|
40
|
+
# Helpers
|
|
41
|
+
# ---------------------------------------------------------------------------
|
|
42
|
+
|
|
43
|
+
def _scan_runs(output_dir: str) -> List[Dict[str, Any]]:
|
|
44
|
+
"""Scan the output directory and return a list of run metadata dicts,
|
|
45
|
+
sorted newest-first."""
|
|
46
|
+
runs: List[Dict[str, Any]] = []
|
|
47
|
+
if not os.path.isdir(output_dir):
|
|
48
|
+
return runs
|
|
49
|
+
|
|
50
|
+
for name in os.listdir(output_dir):
|
|
51
|
+
full = os.path.join(output_dir, name)
|
|
52
|
+
if not os.path.isdir(full) or name in ("latest", "__pycache__"):
|
|
53
|
+
continue
|
|
54
|
+
|
|
55
|
+
run: Dict[str, Any] = {
|
|
56
|
+
"id": name,
|
|
57
|
+
"path": full,
|
|
58
|
+
"type": "unknown",
|
|
59
|
+
"timestamp": "",
|
|
60
|
+
"workload": "",
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
# Extract timestamp from directory name
|
|
64
|
+
m = _TIMESTAMP_RE.search(name)
|
|
65
|
+
if m:
|
|
66
|
+
raw = m.group(1) # e.g. 20260326_141650
|
|
67
|
+
run["timestamp"] = (
|
|
68
|
+
f"{raw[:4]}-{raw[4:6]}-{raw[6:8]} "
|
|
69
|
+
f"{raw[9:11]}:{raw[11:13]}:{raw[13:15]}"
|
|
70
|
+
)
|
|
71
|
+
# Workload = everything before the timestamp part
|
|
72
|
+
prefix = name[: m.start()].rstrip("_")
|
|
73
|
+
run["workload"] = prefix
|
|
74
|
+
|
|
75
|
+
# Detect run type
|
|
76
|
+
if os.path.isfile(os.path.join(full, "bench_result.json")):
|
|
77
|
+
run["type"] = "bench"
|
|
78
|
+
else:
|
|
79
|
+
result_files = [f for f in os.listdir(full) if f.endswith(".result")]
|
|
80
|
+
if result_files:
|
|
81
|
+
run["type"] = "mtr"
|
|
82
|
+
|
|
83
|
+
# Extra metadata for bench
|
|
84
|
+
if run["type"] == "bench":
|
|
85
|
+
try:
|
|
86
|
+
with open(os.path.join(full, "bench_result.json"), "r") as f:
|
|
87
|
+
bdata = json.load(f)
|
|
88
|
+
run["mode"] = bdata.get("mode", "")
|
|
89
|
+
run["dbms_targets"] = [
|
|
90
|
+
d.get("dbms_name", "") for d in bdata.get("dbms_results", [])
|
|
91
|
+
]
|
|
92
|
+
except Exception:
|
|
93
|
+
pass
|
|
94
|
+
|
|
95
|
+
# For MTR, list result files
|
|
96
|
+
if run["type"] == "mtr":
|
|
97
|
+
run["result_files"] = sorted(
|
|
98
|
+
f for f in os.listdir(full) if f.endswith(".result")
|
|
99
|
+
)
|
|
100
|
+
# Infer dbms targets from .result filenames (e.g. test.mysql.result)
|
|
101
|
+
targets = []
|
|
102
|
+
for rf in run.get("result_files", []):
|
|
103
|
+
parts = rf.rsplit(".", 2)
|
|
104
|
+
if len(parts) == 3:
|
|
105
|
+
targets.append(parts[1])
|
|
106
|
+
run["dbms_targets"] = targets
|
|
107
|
+
|
|
108
|
+
# Count report files
|
|
109
|
+
report_files = [
|
|
110
|
+
f for f in os.listdir(full)
|
|
111
|
+
if f.endswith((".html", ".report.txt", ".json", ".diff"))
|
|
112
|
+
]
|
|
113
|
+
run["report_files"] = sorted(report_files)
|
|
114
|
+
|
|
115
|
+
runs.append(run)
|
|
116
|
+
|
|
117
|
+
# Sort newest first
|
|
118
|
+
runs.sort(key=lambda r: r.get("timestamp", ""), reverse=True)
|
|
119
|
+
return runs
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _resolve_run(run_id: Optional[str], output_dir: str) -> Optional[Dict[str, Any]]:
|
|
123
|
+
"""Resolve a run_id (exact, prefix, or 'latest') to a run metadata dict."""
|
|
124
|
+
runs = _scan_runs(output_dir)
|
|
125
|
+
if not runs:
|
|
126
|
+
return None
|
|
127
|
+
|
|
128
|
+
if not run_id:
|
|
129
|
+
# Default: latest
|
|
130
|
+
return runs[0] if runs else None
|
|
131
|
+
|
|
132
|
+
# Exact match
|
|
133
|
+
for r in runs:
|
|
134
|
+
if r["id"] == run_id:
|
|
135
|
+
return r
|
|
136
|
+
|
|
137
|
+
# Direct path
|
|
138
|
+
if os.path.isdir(run_id):
|
|
139
|
+
return {"id": os.path.basename(run_id), "path": run_id, "type": "unknown"}
|
|
140
|
+
|
|
141
|
+
# Prefix match
|
|
142
|
+
candidates = [r for r in runs if r["id"].startswith(run_id)]
|
|
143
|
+
if len(candidates) == 1:
|
|
144
|
+
return candidates[0]
|
|
145
|
+
|
|
146
|
+
return None
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
# ---------------------------------------------------------------------------
|
|
150
|
+
# Sub-actions
|
|
151
|
+
# ---------------------------------------------------------------------------
|
|
152
|
+
|
|
153
|
+
def _handle_list(args, output: "OutputFormatter") -> CommandResult:
|
|
154
|
+
"""List historical runs with pagination."""
|
|
155
|
+
output_dir = getattr(args, "output_dir", "results")
|
|
156
|
+
limit = getattr(args, "limit", 20)
|
|
157
|
+
page = max(1, getattr(args, "page", 1))
|
|
158
|
+
type_filter = getattr(args, "type", "all")
|
|
159
|
+
|
|
160
|
+
runs = _scan_runs(output_dir)
|
|
161
|
+
|
|
162
|
+
if type_filter != "all":
|
|
163
|
+
runs = [r for r in runs if r["type"] == type_filter]
|
|
164
|
+
|
|
165
|
+
total = len(runs)
|
|
166
|
+
total_pages = max(1, (total + limit - 1) // limit)
|
|
167
|
+
page = min(page, total_pages)
|
|
168
|
+
|
|
169
|
+
start = (page - 1) * limit
|
|
170
|
+
display_runs = runs[start:start + limit]
|
|
171
|
+
|
|
172
|
+
# Slim down for output
|
|
173
|
+
rows = []
|
|
174
|
+
for i, r in enumerate(display_runs, start + 1):
|
|
175
|
+
rows.append({
|
|
176
|
+
"idx": i,
|
|
177
|
+
"id": r["id"],
|
|
178
|
+
"type": r["type"],
|
|
179
|
+
"workload": r.get("workload", ""),
|
|
180
|
+
"timestamp": r.get("timestamp", ""),
|
|
181
|
+
"dbms": ", ".join(r.get("dbms_targets", [])),
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
return CommandResult.success(
|
|
185
|
+
"result list",
|
|
186
|
+
{
|
|
187
|
+
"total": total,
|
|
188
|
+
"page": page,
|
|
189
|
+
"total_pages": total_pages,
|
|
190
|
+
"per_page": limit,
|
|
191
|
+
"showing": len(rows),
|
|
192
|
+
"output_dir": output_dir,
|
|
193
|
+
"runs": rows,
|
|
194
|
+
},
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def _handle_show(args, output: "OutputFormatter") -> CommandResult:
|
|
199
|
+
"""Show details of a specific run."""
|
|
200
|
+
output_dir = getattr(args, "output_dir", "results")
|
|
201
|
+
run_id = getattr(args, "run_id", None)
|
|
202
|
+
|
|
203
|
+
run = _resolve_run(run_id, output_dir)
|
|
204
|
+
if not run:
|
|
205
|
+
if run_id:
|
|
206
|
+
return CommandResult.failure(f"Run not found: {run_id}")
|
|
207
|
+
return CommandResult.failure("No runs found in results directory")
|
|
208
|
+
|
|
209
|
+
abs_path = os.path.abspath(run.get("path", ""))
|
|
210
|
+
|
|
211
|
+
data: Dict[str, Any] = {
|
|
212
|
+
"run_id": run["id"],
|
|
213
|
+
"type": run.get("type", "unknown"),
|
|
214
|
+
"timestamp": run.get("timestamp", ""),
|
|
215
|
+
"workload": run.get("workload", ""),
|
|
216
|
+
"path": abs_path,
|
|
217
|
+
"dbms": run.get("dbms_targets", []),
|
|
218
|
+
"report_files": [
|
|
219
|
+
os.path.join(abs_path, f) for f in run.get("report_files", [])
|
|
220
|
+
],
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
# Bench: include summary stats
|
|
224
|
+
if run.get("type") == "bench":
|
|
225
|
+
bench_json = os.path.join(run["path"], "bench_result.json")
|
|
226
|
+
if os.path.isfile(bench_json):
|
|
227
|
+
try:
|
|
228
|
+
with open(bench_json, "r", encoding="utf-8") as f:
|
|
229
|
+
bdata = json.load(f)
|
|
230
|
+
data["mode"] = bdata.get("mode", "")
|
|
231
|
+
data["bench_summary"] = []
|
|
232
|
+
for dr in bdata.get("dbms_results", []):
|
|
233
|
+
data["bench_summary"].append({
|
|
234
|
+
"dbms": dr.get("dbms_name", ""),
|
|
235
|
+
"qps": round(dr.get("overall_qps", 0), 2),
|
|
236
|
+
"duration_s": round(dr.get("total_duration_s", 0), 2),
|
|
237
|
+
"queries": dr.get("total_queries", 0),
|
|
238
|
+
"errors": dr.get("total_errors", 0),
|
|
239
|
+
})
|
|
240
|
+
except Exception:
|
|
241
|
+
pass
|
|
242
|
+
|
|
243
|
+
# MTR: list result files
|
|
244
|
+
if run.get("type") == "mtr":
|
|
245
|
+
data["result_files"] = run.get("result_files", [])
|
|
246
|
+
|
|
247
|
+
return CommandResult.success("result show", data)
|