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
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# Timestamp: "2026-02-01 (ywatanabe)"
|
|
3
|
+
# File: /home/ywatanabe/proj/scitex-python/src/scitex/session/_lifecycle/_start.py
|
|
4
|
+
"""Session start function."""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import inspect
|
|
9
|
+
import logging
|
|
10
|
+
import os as _os
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Any, Dict, Optional, Tuple, Union
|
|
13
|
+
|
|
14
|
+
from scitex.dict import DotDict
|
|
15
|
+
from scitex.logging import getLogger
|
|
16
|
+
from scitex.repro import RandomStateManager
|
|
17
|
+
from scitex.str._clean_path import clean_path
|
|
18
|
+
|
|
19
|
+
from .._manager import get_global_session_manager
|
|
20
|
+
from ._config import setup_configs
|
|
21
|
+
from ._matplotlib import setup_matplotlib
|
|
22
|
+
from ._utils import (
|
|
23
|
+
clear_python_log_dir,
|
|
24
|
+
get_debug_mode,
|
|
25
|
+
initialize_env,
|
|
26
|
+
print_header,
|
|
27
|
+
simplify_relative_path,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
logger = getLogger(__name__)
|
|
31
|
+
|
|
32
|
+
# For development code flow analysis
|
|
33
|
+
try:
|
|
34
|
+
from scitex.dev._analyze_code_flow import analyze_code_flow
|
|
35
|
+
except ImportError:
|
|
36
|
+
|
|
37
|
+
def analyze_code_flow(file):
|
|
38
|
+
return "Code flow analysis not available"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def start(
|
|
42
|
+
sys=None,
|
|
43
|
+
plt=None,
|
|
44
|
+
file: Optional[str] = None,
|
|
45
|
+
sdir: Optional[Union[str, Path]] = None,
|
|
46
|
+
sdir_suffix: Optional[str] = None,
|
|
47
|
+
args: Optional[Any] = None,
|
|
48
|
+
os: Optional[Any] = None,
|
|
49
|
+
random: Optional[Any] = None,
|
|
50
|
+
np: Optional[Any] = None,
|
|
51
|
+
torch: Optional[Any] = None,
|
|
52
|
+
seed: int = 42,
|
|
53
|
+
agg: bool = False,
|
|
54
|
+
fig_size_mm: Tuple[int, int] = (160, 100),
|
|
55
|
+
fig_scale: float = 1.0,
|
|
56
|
+
dpi_display: int = 100,
|
|
57
|
+
dpi_save: int = 300,
|
|
58
|
+
fontsize="small",
|
|
59
|
+
autolayout=True,
|
|
60
|
+
show_execution_flow=False,
|
|
61
|
+
hide_top_right_spines: bool = True,
|
|
62
|
+
alpha: float = 0.9,
|
|
63
|
+
line_width: float = 1.0,
|
|
64
|
+
clear_logs: bool = False,
|
|
65
|
+
verbose: bool = True,
|
|
66
|
+
) -> Tuple[DotDict, Any, Any, Any, Optional[Dict[str, Any]], Any]:
|
|
67
|
+
"""Initialize experiment session with reproducibility settings.
|
|
68
|
+
|
|
69
|
+
Parameters
|
|
70
|
+
----------
|
|
71
|
+
sys : module, optional
|
|
72
|
+
Python sys module for I/O redirection
|
|
73
|
+
plt : module, optional
|
|
74
|
+
Matplotlib pyplot module for plotting configuration
|
|
75
|
+
file : str, optional
|
|
76
|
+
Script file path. If None, automatically detected
|
|
77
|
+
sdir : Union[str, Path], optional
|
|
78
|
+
Save directory path
|
|
79
|
+
sdir_suffix : str, optional
|
|
80
|
+
Suffix to append to save directory
|
|
81
|
+
args : object, optional
|
|
82
|
+
Command line arguments or configuration object
|
|
83
|
+
seed : int, default=42
|
|
84
|
+
Random seed for reproducibility
|
|
85
|
+
agg : bool, default=False
|
|
86
|
+
Whether to use matplotlib Agg backend
|
|
87
|
+
verbose : bool, default=True
|
|
88
|
+
Whether to print detailed information
|
|
89
|
+
|
|
90
|
+
Returns
|
|
91
|
+
-------
|
|
92
|
+
tuple
|
|
93
|
+
(CONFIGS, stdout, stderr, plt, COLORS, rng)
|
|
94
|
+
"""
|
|
95
|
+
IS_DEBUG = get_debug_mode()
|
|
96
|
+
ID, PID = initialize_env(IS_DEBUG)
|
|
97
|
+
|
|
98
|
+
# Convert Path objects to strings for internal processing
|
|
99
|
+
if sdir is not None and isinstance(sdir, Path):
|
|
100
|
+
sdir = str(sdir)
|
|
101
|
+
|
|
102
|
+
# Defines SDIR
|
|
103
|
+
if sdir is None:
|
|
104
|
+
# Define __file__
|
|
105
|
+
if file:
|
|
106
|
+
caller_file = file
|
|
107
|
+
else:
|
|
108
|
+
caller_file = inspect.stack()[1].filename
|
|
109
|
+
if "ipython" in caller_file:
|
|
110
|
+
caller_file = f"/tmp/{_os.getenv('USER')}.py"
|
|
111
|
+
|
|
112
|
+
# Convert to absolute path if relative and resolve symlinks
|
|
113
|
+
if not _os.path.isabs(caller_file):
|
|
114
|
+
caller_file = _os.path.realpath(_os.path.abspath(caller_file))
|
|
115
|
+
else:
|
|
116
|
+
caller_file = _os.path.realpath(caller_file)
|
|
117
|
+
|
|
118
|
+
# Define sdir
|
|
119
|
+
sdir = clean_path(_os.path.splitext(caller_file)[0] + f"_out/RUNNING/{ID}/")
|
|
120
|
+
|
|
121
|
+
# Optional
|
|
122
|
+
if sdir_suffix:
|
|
123
|
+
sdir = sdir[:-1] + f"-{sdir_suffix}/"
|
|
124
|
+
else:
|
|
125
|
+
caller_file = file
|
|
126
|
+
|
|
127
|
+
if clear_logs and caller_file:
|
|
128
|
+
clear_python_log_dir(sdir + caller_file + "/")
|
|
129
|
+
_os.makedirs(sdir, exist_ok=True)
|
|
130
|
+
relative_sdir = simplify_relative_path(sdir)
|
|
131
|
+
|
|
132
|
+
# Setup configs - use caller_file (computed) instead of file (parameter)
|
|
133
|
+
CONFIGS = setup_configs(
|
|
134
|
+
IS_DEBUG, ID, PID, caller_file, sdir, relative_sdir, verbose
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
# Logging
|
|
138
|
+
if sys is not None:
|
|
139
|
+
from scitex.io._flush import flush
|
|
140
|
+
from scitex.logging._Tee import tee
|
|
141
|
+
|
|
142
|
+
flush(sys)
|
|
143
|
+
sys.stdout, sys.stderr = tee(sys, sdir=sdir, verbose=verbose)
|
|
144
|
+
CONFIGS["_sys"] = sys
|
|
145
|
+
|
|
146
|
+
# Redirect logging handlers to use the tee-wrapped streams
|
|
147
|
+
_redirect_logging_handlers(sys)
|
|
148
|
+
|
|
149
|
+
# Initialize RandomStateManager
|
|
150
|
+
rng = RandomStateManager(seed=seed, verbose=verbose)
|
|
151
|
+
if verbose:
|
|
152
|
+
logger.info(f"Initialized RandomStateManager with seed {seed}")
|
|
153
|
+
|
|
154
|
+
# Matplotlib configurations
|
|
155
|
+
plt, COLORS = setup_matplotlib(
|
|
156
|
+
plt,
|
|
157
|
+
agg,
|
|
158
|
+
fig_size_mm=fig_size_mm,
|
|
159
|
+
fig_scale=fig_scale,
|
|
160
|
+
dpi_display=dpi_display,
|
|
161
|
+
dpi_save=dpi_save,
|
|
162
|
+
hide_top_right_spines=hide_top_right_spines,
|
|
163
|
+
alpha=alpha,
|
|
164
|
+
line_width=line_width,
|
|
165
|
+
fontsize=fontsize,
|
|
166
|
+
autolayout=autolayout,
|
|
167
|
+
verbose=verbose,
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
# Adds argument-parsed variables
|
|
171
|
+
if args is not None:
|
|
172
|
+
CONFIGS["ARGS"] = vars(args) if hasattr(args, "__dict__") else args
|
|
173
|
+
|
|
174
|
+
CONFIGS = DotDict(CONFIGS)
|
|
175
|
+
|
|
176
|
+
# Register session
|
|
177
|
+
session_manager = get_global_session_manager()
|
|
178
|
+
session_manager.create_session(ID, CONFIGS)
|
|
179
|
+
|
|
180
|
+
print_header(ID, PID, caller_file, args, CONFIGS, verbose)
|
|
181
|
+
|
|
182
|
+
if show_execution_flow:
|
|
183
|
+
from scitex.str._printc import printc as _printc
|
|
184
|
+
|
|
185
|
+
structure = analyze_code_flow(caller_file)
|
|
186
|
+
_printc(structure)
|
|
187
|
+
|
|
188
|
+
# Start verification tracking
|
|
189
|
+
_start_verification(CONFIGS)
|
|
190
|
+
|
|
191
|
+
# Return appropriate values based on whether sys was provided
|
|
192
|
+
if sys is not None:
|
|
193
|
+
return CONFIGS, sys.stdout, sys.stderr, plt, COLORS, rng
|
|
194
|
+
else:
|
|
195
|
+
return CONFIGS, None, None, plt, COLORS, rng
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def _redirect_logging_handlers(sys) -> None:
|
|
199
|
+
"""Redirect logging handlers to use tee-wrapped streams."""
|
|
200
|
+
# Update all existing StreamHandler instances
|
|
201
|
+
for logger_name in list(logging.Logger.manager.loggerDict.keys()):
|
|
202
|
+
try:
|
|
203
|
+
lgr = logging.getLogger(logger_name)
|
|
204
|
+
for handler in lgr.handlers:
|
|
205
|
+
if isinstance(handler, logging.StreamHandler):
|
|
206
|
+
if not hasattr(handler, "stream"):
|
|
207
|
+
continue
|
|
208
|
+
if handler.stream in (sys.__stderr__, sys.__stdout__):
|
|
209
|
+
handler.stream = (
|
|
210
|
+
sys.stderr
|
|
211
|
+
if handler.stream == sys.__stderr__
|
|
212
|
+
else sys.stdout
|
|
213
|
+
)
|
|
214
|
+
except Exception:
|
|
215
|
+
pass
|
|
216
|
+
|
|
217
|
+
# Also update the root logger handlers
|
|
218
|
+
try:
|
|
219
|
+
root_logger = logging.getLogger()
|
|
220
|
+
for handler in root_logger.handlers:
|
|
221
|
+
if isinstance(handler, logging.StreamHandler):
|
|
222
|
+
if not hasattr(handler, "stream"):
|
|
223
|
+
continue
|
|
224
|
+
if handler.stream in (sys.__stderr__, sys.__stdout__):
|
|
225
|
+
handler.stream = (
|
|
226
|
+
sys.stderr if handler.stream == sys.__stderr__ else sys.stdout
|
|
227
|
+
)
|
|
228
|
+
except Exception:
|
|
229
|
+
pass
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def _start_verification(CONFIG) -> None:
|
|
233
|
+
"""Start verification tracking for this session."""
|
|
234
|
+
try:
|
|
235
|
+
from scitex.verify import on_session_start
|
|
236
|
+
|
|
237
|
+
session_id = CONFIG.get("ID", "unknown")
|
|
238
|
+
file_path = CONFIG.get("FILE")
|
|
239
|
+
if file_path is not None:
|
|
240
|
+
file_path = str(file_path)
|
|
241
|
+
on_session_start(session_id=session_id, script_path=file_path)
|
|
242
|
+
except Exception:
|
|
243
|
+
pass
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
# EOF
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# Timestamp: "2026-02-01 (ywatanabe)"
|
|
3
|
+
# File: /home/ywatanabe/proj/scitex-python/src/scitex/session/_lifecycle/_utils.py
|
|
4
|
+
"""Utility functions for session lifecycle."""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import os as _os
|
|
9
|
+
import re
|
|
10
|
+
from datetime import datetime
|
|
11
|
+
from time import sleep
|
|
12
|
+
from typing import Any, Dict, Tuple
|
|
13
|
+
|
|
14
|
+
from scitex.logging import getLogger
|
|
15
|
+
from scitex.repro._gen_ID import gen_ID
|
|
16
|
+
from scitex.str._printc import printc as _printc
|
|
17
|
+
|
|
18
|
+
logger = getLogger(__name__)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def get_scitex_version() -> str:
|
|
22
|
+
"""Gets scitex version."""
|
|
23
|
+
try:
|
|
24
|
+
import scitex
|
|
25
|
+
|
|
26
|
+
return scitex.__version__
|
|
27
|
+
except Exception as e:
|
|
28
|
+
print(e)
|
|
29
|
+
return "(not found)"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def get_debug_mode() -> bool:
|
|
33
|
+
"""Get debug mode from configuration."""
|
|
34
|
+
try:
|
|
35
|
+
from scitex.io._load import load
|
|
36
|
+
|
|
37
|
+
IS_DEBUG_PATH = "./config/IS_DEBUG.yaml"
|
|
38
|
+
if _os.path.exists(IS_DEBUG_PATH):
|
|
39
|
+
IS_DEBUG = load(IS_DEBUG_PATH).get("IS_DEBUG", False)
|
|
40
|
+
if IS_DEBUG == "true":
|
|
41
|
+
IS_DEBUG = True
|
|
42
|
+
else:
|
|
43
|
+
IS_DEBUG = False
|
|
44
|
+
|
|
45
|
+
except Exception as e:
|
|
46
|
+
print(e)
|
|
47
|
+
IS_DEBUG = False
|
|
48
|
+
return IS_DEBUG
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def initialize_env(IS_DEBUG: bool) -> Tuple[str, int]:
|
|
52
|
+
"""Initialize environment with ID and PID.
|
|
53
|
+
|
|
54
|
+
Parameters
|
|
55
|
+
----------
|
|
56
|
+
IS_DEBUG : bool
|
|
57
|
+
Debug mode flag
|
|
58
|
+
|
|
59
|
+
Returns
|
|
60
|
+
-------
|
|
61
|
+
tuple
|
|
62
|
+
(ID, PID) - Unique identifier and Process ID
|
|
63
|
+
"""
|
|
64
|
+
ID = gen_ID(N=4) if not IS_DEBUG else "DEBUG_" + gen_ID(N=4)
|
|
65
|
+
PID = _os.getpid()
|
|
66
|
+
return ID, PID
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def simplify_relative_path(sdir: str) -> str:
|
|
70
|
+
"""Simplify the relative path by removing specific patterns.
|
|
71
|
+
|
|
72
|
+
Parameters
|
|
73
|
+
----------
|
|
74
|
+
sdir : str
|
|
75
|
+
The directory path to simplify
|
|
76
|
+
|
|
77
|
+
Returns
|
|
78
|
+
-------
|
|
79
|
+
str
|
|
80
|
+
Simplified relative path
|
|
81
|
+
"""
|
|
82
|
+
base_path = _os.getcwd()
|
|
83
|
+
relative_sdir = _os.path.relpath(sdir, base_path) if base_path else sdir
|
|
84
|
+
simplified_path = relative_sdir.replace("scripts/", "./scripts/").replace(
|
|
85
|
+
"RUNNING/", ""
|
|
86
|
+
)
|
|
87
|
+
# Remove date-time pattern and random string
|
|
88
|
+
simplified_path = re.sub(
|
|
89
|
+
r"\d{4}Y-\d{2}M-\d{2}D-\d{2}h\d{2}m\d{2}s_\w+/?$", "", simplified_path
|
|
90
|
+
)
|
|
91
|
+
return simplified_path
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def clear_python_log_dir(log_dir: str) -> None:
|
|
95
|
+
"""Clear Python log directory."""
|
|
96
|
+
try:
|
|
97
|
+
if _os.path.exists(log_dir):
|
|
98
|
+
_os.system(f"rm -rf {log_dir}")
|
|
99
|
+
except Exception as e:
|
|
100
|
+
print(f"Failed to clear directory {log_dir}: {e}")
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def print_header(
|
|
104
|
+
ID: str,
|
|
105
|
+
PID: int,
|
|
106
|
+
file: str,
|
|
107
|
+
args: Any,
|
|
108
|
+
configs: Dict[str, Any],
|
|
109
|
+
verbose: bool = True,
|
|
110
|
+
) -> None:
|
|
111
|
+
"""Prints formatted header with scitex version, ID, and PID information."""
|
|
112
|
+
if args is not None and hasattr(args, "_get_kwargs"):
|
|
113
|
+
args_str = "Arguments:"
|
|
114
|
+
for arg, value in args._get_kwargs():
|
|
115
|
+
args_str += f"\n {arg}: {value}"
|
|
116
|
+
else:
|
|
117
|
+
args_str = "Arguments: None"
|
|
118
|
+
|
|
119
|
+
_printc(
|
|
120
|
+
(f"SciTeX v{get_scitex_version()} | {ID} (PID: {PID})\n\n{file}\n\n{args_str}"),
|
|
121
|
+
char="=",
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
sleep(1)
|
|
125
|
+
if verbose:
|
|
126
|
+
from pprint import pformat
|
|
127
|
+
|
|
128
|
+
config_str = pformat(configs.to_dict())
|
|
129
|
+
logger.info(f"\n{'-' * 40}\n\n{config_str}\n\n{'-' * 40}\n")
|
|
130
|
+
sleep(1)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def format_diff_time(diff_time) -> str:
|
|
134
|
+
"""Format time difference as HH:MM:SS."""
|
|
135
|
+
total_seconds = int(diff_time.total_seconds())
|
|
136
|
+
hours = total_seconds // 3600
|
|
137
|
+
minutes = (total_seconds % 3600) // 60
|
|
138
|
+
seconds = total_seconds % 60
|
|
139
|
+
return f"{hours:02d}:{minutes:02d}:{seconds:02d}"
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def process_timestamp(CONFIG, verbose=True):
|
|
143
|
+
"""Process session timestamps."""
|
|
144
|
+
try:
|
|
145
|
+
CONFIG["END_DATETIME"] = datetime.now()
|
|
146
|
+
CONFIG["RUN_DURATION"] = format_diff_time(
|
|
147
|
+
CONFIG["END_DATETIME"] - CONFIG["START_DATETIME"]
|
|
148
|
+
)
|
|
149
|
+
if verbose:
|
|
150
|
+
logger.info(
|
|
151
|
+
f"\nSTART TIME: {CONFIG['START_DATETIME']}\n"
|
|
152
|
+
f"END TIME: {CONFIG['END_DATETIME']}\n"
|
|
153
|
+
f"RUN DURATION: {CONFIG['RUN_DURATION']}\n"
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
except Exception as e:
|
|
157
|
+
print(e)
|
|
158
|
+
|
|
159
|
+
return CONFIG
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def args_to_str(args_dict) -> str:
|
|
163
|
+
"""Convert args dictionary to formatted string."""
|
|
164
|
+
if args_dict:
|
|
165
|
+
max_key_length = max(len(str(k)) for k in args_dict.keys())
|
|
166
|
+
return "\n".join(
|
|
167
|
+
f"{str(k):<{max_key_length}} : {str(v)}"
|
|
168
|
+
for k, v in sorted(args_dict.items())
|
|
169
|
+
)
|
|
170
|
+
else:
|
|
171
|
+
return ""
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def escape_ansi_from_log_files(log_files) -> None:
|
|
175
|
+
"""Remove ANSI escape sequences from log files."""
|
|
176
|
+
ansi_escape = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])")
|
|
177
|
+
|
|
178
|
+
for f in log_files:
|
|
179
|
+
with open(f, encoding="utf-8") as file:
|
|
180
|
+
content = file.read()
|
|
181
|
+
cleaned_content = ansi_escape.sub("", content)
|
|
182
|
+
with open(f, "w", encoding="utf-8") as file:
|
|
183
|
+
file.write(cleaned_content)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
# EOF
|
scitex/session/_manager.py
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
2
|
# Timestamp: "2025-08-21 20:36:50 (ywatanabe)"
|
|
4
3
|
# File: /home/ywatanabe/proj/SciTeX-Code/src/scitex/session/_manager.py
|
|
5
4
|
# ----------------------------------------
|
|
6
5
|
from __future__ import annotations
|
|
6
|
+
|
|
7
7
|
import os
|
|
8
8
|
|
|
9
9
|
__FILE__ = __file__
|
|
@@ -22,7 +22,12 @@ class SessionManager:
|
|
|
22
22
|
def __init__(self):
|
|
23
23
|
self.active_sessions = {}
|
|
24
24
|
|
|
25
|
-
def create_session(
|
|
25
|
+
def create_session(
|
|
26
|
+
self,
|
|
27
|
+
session_id: str,
|
|
28
|
+
config: Dict[str, Any],
|
|
29
|
+
script_path: str = None,
|
|
30
|
+
) -> None:
|
|
26
31
|
"""Register a new session.
|
|
27
32
|
|
|
28
33
|
Parameters
|
|
@@ -31,24 +36,56 @@ class SessionManager:
|
|
|
31
36
|
Unique identifier for the session
|
|
32
37
|
config : Dict[str, Any]
|
|
33
38
|
Session configuration dictionary
|
|
39
|
+
script_path : str, optional
|
|
40
|
+
Path to the script being run
|
|
34
41
|
"""
|
|
35
42
|
self.active_sessions[session_id] = {
|
|
36
43
|
"config": config,
|
|
37
44
|
"start_time": datetime.now(),
|
|
38
45
|
"status": "running",
|
|
46
|
+
"script_path": script_path,
|
|
39
47
|
}
|
|
40
48
|
|
|
41
|
-
|
|
49
|
+
# Start verification tracking (silent fail)
|
|
50
|
+
try:
|
|
51
|
+
from scitex.verify import on_session_start
|
|
52
|
+
|
|
53
|
+
on_session_start(
|
|
54
|
+
session_id=session_id,
|
|
55
|
+
script_path=script_path,
|
|
56
|
+
)
|
|
57
|
+
except Exception:
|
|
58
|
+
pass
|
|
59
|
+
|
|
60
|
+
def close_session(
|
|
61
|
+
self,
|
|
62
|
+
session_id: str,
|
|
63
|
+
status: str = "success",
|
|
64
|
+
exit_code: int = 0,
|
|
65
|
+
) -> None:
|
|
42
66
|
"""Mark a session as closed.
|
|
43
67
|
|
|
44
68
|
Parameters
|
|
45
69
|
----------
|
|
46
70
|
session_id : str
|
|
47
71
|
Unique identifier for the session to close
|
|
72
|
+
status : str, optional
|
|
73
|
+
Final status (success, failed, error)
|
|
74
|
+
exit_code : int, optional
|
|
75
|
+
Exit code of the session
|
|
48
76
|
"""
|
|
49
77
|
if session_id in self.active_sessions:
|
|
50
78
|
self.active_sessions[session_id]["status"] = "closed"
|
|
51
79
|
self.active_sessions[session_id]["end_time"] = datetime.now()
|
|
80
|
+
self.active_sessions[session_id]["exit_code"] = exit_code
|
|
81
|
+
|
|
82
|
+
# Stop verification tracking (silent fail)
|
|
83
|
+
try:
|
|
84
|
+
from scitex.verify import on_session_close
|
|
85
|
+
|
|
86
|
+
on_session_close(status=status, exit_code=exit_code)
|
|
87
|
+
except Exception:
|
|
88
|
+
pass
|
|
52
89
|
|
|
53
90
|
def get_active_sessions(self) -> Dict[str, Any]:
|
|
54
91
|
"""Get all active sessions.
|
scitex/session/template.py
CHANGED
|
@@ -74,7 +74,7 @@ def main(
|
|
|
74
74
|
CONFIG=stx.INJECTED, # Session config
|
|
75
75
|
plt=stx.INJECTED, # Pre-configured matplotlib
|
|
76
76
|
COLORS=stx.INJECTED, # Color palette
|
|
77
|
-
|
|
77
|
+
rngg=stx.INJECTED, # Random generator
|
|
78
78
|
logger=stx.INJECTED, # Logger
|
|
79
79
|
):
|
|
80
80
|
"""Example plotting with session management."""
|
|
@@ -91,7 +91,7 @@ def main(
|
|
|
91
91
|
CONFIG=stx.INJECTED, # Auto-injected from ./config/*.yaml
|
|
92
92
|
plt=stx.INJECTED, # Pre-configured matplotlib
|
|
93
93
|
COLORS=stx.INJECTED, # Color palette
|
|
94
|
-
|
|
94
|
+
rngg=stx.INJECTED, # Random number generator
|
|
95
95
|
logger=stx.INJECTED, # Session logger
|
|
96
96
|
):
|
|
97
97
|
"""
|