scitex 2.16.1__py3-none-any.whl → 2.17.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.
- scitex/_mcp_resources/_cheatsheet.py +1 -1
- scitex/_mcp_resources/_modules.py +1 -1
- scitex/_mcp_tools/__init__.py +2 -0
- scitex/_mcp_tools/verify.py +256 -0
- scitex/cli/main.py +2 -0
- scitex/cli/verify.py +476 -0
- scitex/dev/plt/__init__.py +1 -1
- scitex/dev/plt/mpl/get_dir_ax.py +1 -1
- scitex/dev/plt/mpl/get_signatures.py +1 -1
- scitex/dev/plt/mpl/get_signatures_details.py +1 -1
- scitex/io/_load.py +8 -1
- scitex/io/_save.py +12 -0
- scitex/session/README.md +2 -2
- scitex/session/__init__.py +1 -0
- scitex/session/_decorator.py +57 -33
- scitex/session/_lifecycle/__init__.py +23 -0
- scitex/session/_lifecycle/_close.py +225 -0
- scitex/session/_lifecycle/_config.py +112 -0
- scitex/session/_lifecycle/_matplotlib.py +83 -0
- scitex/session/_lifecycle/_start.py +246 -0
- scitex/session/_lifecycle/_utils.py +186 -0
- scitex/session/_manager.py +40 -3
- scitex/session/template.py +1 -1
- scitex/template/_templates/plt.py +1 -1
- scitex/template/_templates/session.py +1 -1
- scitex/verify/README.md +312 -0
- scitex/verify/__init__.py +212 -0
- scitex/verify/_chain.py +369 -0
- scitex/verify/_db.py +600 -0
- scitex/verify/_hash.py +187 -0
- scitex/verify/_integration.py +127 -0
- scitex/verify/_rerun.py +253 -0
- scitex/verify/_tracker.py +330 -0
- scitex/verify/_visualize.py +48 -0
- scitex/verify/_viz/__init__.py +56 -0
- scitex/verify/_viz/_colors.py +84 -0
- scitex/verify/_viz/_format.py +302 -0
- scitex/verify/_viz/_json.py +192 -0
- scitex/verify/_viz/_mermaid.py +440 -0
- scitex/verify/_viz/_plotly.py +193 -0
- scitex/verify/_viz/_templates.py +246 -0
- scitex/verify/_viz/_utils.py +56 -0
- {scitex-2.16.1.dist-info → scitex-2.17.0.dist-info}/METADATA +1 -1
- {scitex-2.16.1.dist-info → scitex-2.17.0.dist-info}/RECORD +47 -23
- scitex/session/_lifecycle.py +0 -827
- {scitex-2.16.1.dist-info → scitex-2.17.0.dist-info}/WHEEL +0 -0
- {scitex-2.16.1.dist-info → scitex-2.17.0.dist-info}/entry_points.txt +0 -0
- {scitex-2.16.1.dist-info → scitex-2.17.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -32,7 +32,7 @@ def main(
|
|
|
32
32
|
CONFIG=stx.INJECTED, # Session config with ID, paths
|
|
33
33
|
plt=stx.INJECTED, # Pre-configured matplotlib
|
|
34
34
|
COLORS=stx.INJECTED, # Color palette
|
|
35
|
-
|
|
35
|
+
rngg=stx.INJECTED, # Seeded random generator
|
|
36
36
|
logger=stx.INJECTED, # Session logger
|
|
37
37
|
):
|
|
38
38
|
\"\"\"This docstring becomes --help description.\"\"\"
|
|
@@ -223,7 +223,7 @@ def main(
|
|
|
223
223
|
CONFIG=stx.INJECTED, # Session config
|
|
224
224
|
plt=stx.INJECTED, # matplotlib
|
|
225
225
|
COLORS=stx.INJECTED, # Color palette
|
|
226
|
-
|
|
226
|
+
rngg=stx.INJECTED, # Random generator
|
|
227
227
|
logger=stx.INJECTED, # Logger
|
|
228
228
|
):
|
|
229
229
|
\"\"\"Docstring becomes --help.\"\"\"
|
scitex/_mcp_tools/__init__.py
CHANGED
|
@@ -17,6 +17,7 @@ from .social import register_social_tools
|
|
|
17
17
|
from .stats import register_stats_tools
|
|
18
18
|
from .template import register_template_tools
|
|
19
19
|
from .ui import register_ui_tools
|
|
20
|
+
from .verify import register_verify_tools
|
|
20
21
|
from .writer import register_writer_tools
|
|
21
22
|
|
|
22
23
|
__all__ = ["register_all_tools"]
|
|
@@ -36,6 +37,7 @@ def register_all_tools(mcp) -> None:
|
|
|
36
37
|
register_stats_tools(mcp)
|
|
37
38
|
register_template_tools(mcp)
|
|
38
39
|
register_ui_tools(mcp)
|
|
40
|
+
register_verify_tools(mcp)
|
|
39
41
|
register_writer_tools(mcp)
|
|
40
42
|
|
|
41
43
|
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# Timestamp: "2026-02-01 (ywatanabe)"
|
|
3
|
+
# File: /home/ywatanabe/proj/scitex-python/src/scitex/_mcp_tools/verify.py
|
|
4
|
+
"""Verify module tools for FastMCP unified server."""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
from typing import Optional
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _json(data: dict) -> str:
|
|
13
|
+
return json.dumps(data, indent=2, default=str)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def register_verify_tools(mcp) -> None:
|
|
17
|
+
"""Register verify tools with FastMCP server."""
|
|
18
|
+
|
|
19
|
+
@mcp.tool()
|
|
20
|
+
async def verify_list(
|
|
21
|
+
limit: int = 50,
|
|
22
|
+
status_filter: Optional[str] = None,
|
|
23
|
+
) -> str:
|
|
24
|
+
"""[verify] List all tracked runs with verification status.
|
|
25
|
+
|
|
26
|
+
Parameters
|
|
27
|
+
----------
|
|
28
|
+
limit : int, optional
|
|
29
|
+
Maximum number of runs to return (default: 50)
|
|
30
|
+
status_filter : str, optional
|
|
31
|
+
Filter by status: 'success', 'failed', 'running', or None for all
|
|
32
|
+
|
|
33
|
+
Returns
|
|
34
|
+
-------
|
|
35
|
+
str
|
|
36
|
+
JSON with list of runs and their verification status
|
|
37
|
+
"""
|
|
38
|
+
from scitex.verify import get_db, verify_run
|
|
39
|
+
|
|
40
|
+
db = get_db()
|
|
41
|
+
runs = db.list_runs(status=status_filter, limit=limit)
|
|
42
|
+
|
|
43
|
+
results = []
|
|
44
|
+
for run in runs:
|
|
45
|
+
verification = verify_run(run["session_id"])
|
|
46
|
+
results.append(
|
|
47
|
+
{
|
|
48
|
+
"session_id": run["session_id"],
|
|
49
|
+
"script_path": run.get("script_path"),
|
|
50
|
+
"db_status": run.get("status"),
|
|
51
|
+
"verification_status": verification.status.value,
|
|
52
|
+
"is_verified": verification.is_verified,
|
|
53
|
+
"started_at": run.get("started_at"),
|
|
54
|
+
"finished_at": run.get("finished_at"),
|
|
55
|
+
}
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
return _json(
|
|
59
|
+
{
|
|
60
|
+
"count": len(results),
|
|
61
|
+
"runs": results,
|
|
62
|
+
}
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
@mcp.tool()
|
|
66
|
+
async def verify_run(
|
|
67
|
+
session_or_path: str,
|
|
68
|
+
) -> str:
|
|
69
|
+
"""[verify] Verify a specific session run by checking all file hashes.
|
|
70
|
+
|
|
71
|
+
Parameters
|
|
72
|
+
----------
|
|
73
|
+
session_or_path : str
|
|
74
|
+
Session ID (e.g., '2025Y-11M-18D-09h12m03s_HmH5') or
|
|
75
|
+
path to a file to find its associated session
|
|
76
|
+
|
|
77
|
+
Returns
|
|
78
|
+
-------
|
|
79
|
+
str
|
|
80
|
+
JSON with verification results including file-level details
|
|
81
|
+
"""
|
|
82
|
+
from pathlib import Path
|
|
83
|
+
|
|
84
|
+
from scitex.verify import get_db
|
|
85
|
+
from scitex.verify import verify_run as do_verify_run
|
|
86
|
+
|
|
87
|
+
db = get_db()
|
|
88
|
+
|
|
89
|
+
# Check if it's a file path
|
|
90
|
+
path = Path(session_or_path)
|
|
91
|
+
if path.exists():
|
|
92
|
+
sessions = db.find_session_by_file(str(path.resolve()), role="output")
|
|
93
|
+
if not sessions:
|
|
94
|
+
sessions = db.find_session_by_file(str(path.resolve()), role="input")
|
|
95
|
+
|
|
96
|
+
if not sessions:
|
|
97
|
+
return _json(
|
|
98
|
+
{
|
|
99
|
+
"error": f"No session found for file: {session_or_path}",
|
|
100
|
+
"session_id": None,
|
|
101
|
+
}
|
|
102
|
+
)
|
|
103
|
+
session_id = sessions[0]
|
|
104
|
+
else:
|
|
105
|
+
session_id = session_or_path
|
|
106
|
+
|
|
107
|
+
verification = do_verify_run(session_id)
|
|
108
|
+
|
|
109
|
+
return _json(
|
|
110
|
+
{
|
|
111
|
+
"session_id": verification.session_id,
|
|
112
|
+
"script_path": verification.script_path,
|
|
113
|
+
"status": verification.status.value,
|
|
114
|
+
"is_verified": verification.is_verified,
|
|
115
|
+
"combined_hash_expected": verification.combined_hash_expected,
|
|
116
|
+
"files": [
|
|
117
|
+
{
|
|
118
|
+
"path": f.path,
|
|
119
|
+
"role": f.role,
|
|
120
|
+
"status": f.status.value,
|
|
121
|
+
"expected_hash": f.expected_hash,
|
|
122
|
+
"current_hash": f.current_hash,
|
|
123
|
+
"is_verified": f.is_verified,
|
|
124
|
+
}
|
|
125
|
+
for f in verification.files
|
|
126
|
+
],
|
|
127
|
+
"mismatched_count": len(verification.mismatched_files),
|
|
128
|
+
"missing_count": len(verification.missing_files),
|
|
129
|
+
}
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
@mcp.tool()
|
|
133
|
+
async def verify_chain(
|
|
134
|
+
target_file: str,
|
|
135
|
+
) -> str:
|
|
136
|
+
"""[verify] Verify the dependency chain for a target file.
|
|
137
|
+
|
|
138
|
+
Traces back through all sessions that contributed to producing
|
|
139
|
+
the target file and verifies each one.
|
|
140
|
+
|
|
141
|
+
Parameters
|
|
142
|
+
----------
|
|
143
|
+
target_file : str
|
|
144
|
+
Path to the target file to trace
|
|
145
|
+
|
|
146
|
+
Returns
|
|
147
|
+
-------
|
|
148
|
+
str
|
|
149
|
+
JSON with chain verification results
|
|
150
|
+
"""
|
|
151
|
+
from pathlib import Path
|
|
152
|
+
|
|
153
|
+
from scitex.verify import verify_chain as do_verify_chain
|
|
154
|
+
|
|
155
|
+
path = Path(target_file)
|
|
156
|
+
if not path.exists():
|
|
157
|
+
return _json(
|
|
158
|
+
{
|
|
159
|
+
"error": f"File not found: {target_file}",
|
|
160
|
+
"target_file": target_file,
|
|
161
|
+
}
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
chain = do_verify_chain(str(path.resolve()))
|
|
165
|
+
|
|
166
|
+
return _json(
|
|
167
|
+
{
|
|
168
|
+
"target_file": chain.target_file,
|
|
169
|
+
"status": chain.status.value,
|
|
170
|
+
"is_verified": chain.is_verified,
|
|
171
|
+
"chain_length": len(chain.runs),
|
|
172
|
+
"failed_runs_count": len(chain.failed_runs),
|
|
173
|
+
"runs": [
|
|
174
|
+
{
|
|
175
|
+
"session_id": r.session_id,
|
|
176
|
+
"script_path": r.script_path,
|
|
177
|
+
"status": r.status.value,
|
|
178
|
+
"is_verified": r.is_verified,
|
|
179
|
+
"mismatched_files": [f.path for f in r.mismatched_files],
|
|
180
|
+
"missing_files": [f.path for f in r.missing_files],
|
|
181
|
+
}
|
|
182
|
+
for r in chain.runs
|
|
183
|
+
],
|
|
184
|
+
}
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
@mcp.tool()
|
|
188
|
+
async def verify_status() -> str:
|
|
189
|
+
"""[verify] Show verification status summary (like git status).
|
|
190
|
+
|
|
191
|
+
Returns
|
|
192
|
+
-------
|
|
193
|
+
str
|
|
194
|
+
JSON with counts of verified, mismatched, and missing runs
|
|
195
|
+
"""
|
|
196
|
+
from scitex.verify import get_status
|
|
197
|
+
|
|
198
|
+
status = get_status()
|
|
199
|
+
return _json(status)
|
|
200
|
+
|
|
201
|
+
@mcp.tool()
|
|
202
|
+
async def verify_stats() -> str:
|
|
203
|
+
"""[verify] Show verification database statistics.
|
|
204
|
+
|
|
205
|
+
Returns
|
|
206
|
+
-------
|
|
207
|
+
str
|
|
208
|
+
JSON with database statistics
|
|
209
|
+
"""
|
|
210
|
+
from scitex.verify import get_db
|
|
211
|
+
|
|
212
|
+
db = get_db()
|
|
213
|
+
stats = db.stats()
|
|
214
|
+
return _json(stats)
|
|
215
|
+
|
|
216
|
+
@mcp.tool()
|
|
217
|
+
async def verify_mermaid(
|
|
218
|
+
session_id: Optional[str] = None,
|
|
219
|
+
target_file: Optional[str] = None,
|
|
220
|
+
) -> str:
|
|
221
|
+
"""[verify] Generate Mermaid diagram for verification DAG.
|
|
222
|
+
|
|
223
|
+
Parameters
|
|
224
|
+
----------
|
|
225
|
+
session_id : str, optional
|
|
226
|
+
Start from this session
|
|
227
|
+
target_file : str, optional
|
|
228
|
+
Start from session that produced this file
|
|
229
|
+
|
|
230
|
+
Returns
|
|
231
|
+
-------
|
|
232
|
+
str
|
|
233
|
+
Mermaid diagram code
|
|
234
|
+
"""
|
|
235
|
+
from pathlib import Path
|
|
236
|
+
|
|
237
|
+
from scitex.verify import generate_mermaid_dag
|
|
238
|
+
|
|
239
|
+
if target_file:
|
|
240
|
+
target_file = str(Path(target_file).resolve())
|
|
241
|
+
|
|
242
|
+
mermaid_code = generate_mermaid_dag(
|
|
243
|
+
session_id=session_id,
|
|
244
|
+
target_file=target_file,
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
return _json(
|
|
248
|
+
{
|
|
249
|
+
"mermaid": mermaid_code,
|
|
250
|
+
"session_id": session_id,
|
|
251
|
+
"target_file": target_file,
|
|
252
|
+
}
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
# EOF
|
scitex/cli/main.py
CHANGED
|
@@ -41,6 +41,7 @@ from . import (
|
|
|
41
41
|
stats,
|
|
42
42
|
template,
|
|
43
43
|
tex,
|
|
44
|
+
verify,
|
|
44
45
|
web,
|
|
45
46
|
writer,
|
|
46
47
|
)
|
|
@@ -97,6 +98,7 @@ cli.add_command(social.social)
|
|
|
97
98
|
cli.add_command(stats.stats)
|
|
98
99
|
cli.add_command(template.template)
|
|
99
100
|
cli.add_command(tex.tex)
|
|
101
|
+
cli.add_command(verify.verify)
|
|
100
102
|
cli.add_command(web.web)
|
|
101
103
|
cli.add_command(writer.writer)
|
|
102
104
|
|