-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsetup_project.py
More file actions
131 lines (106 loc) · 3.71 KB
/
Copy pathsetup_project.py
File metadata and controls
131 lines (106 loc) · 3.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#!/usr/bin/env python3
"""
Project bootstrapper for the Tri-Channel OECT molecular communication simulator.
What it does
------------
- Verifies Python and required third-party packages
- Creates the expected results/ tree (data/, figures/, tables/, cache/, logs/, figures/notebook_replicas/)
- Optionally resets cached results via --reset {cache|all}
Usage
-----
python setup_project.py # check environment & create folders
python setup_project.py --reset all # wipe results/ completely (careful)
python setup_project.py --reset cache # just clear caches/state
This script is safe to run multiple times.
"""
from __future__ import annotations
import argparse
import importlib
import sys
from pathlib import Path
REQUIRED = [
("numpy", None),
("scipy", None),
("pandas", None),
("matplotlib", None),
("yaml", "PyYAML"),
("tqdm", None),
("rich", None),
("psutil", None),
("joblib", None),
("statsmodels", None),
]
def _check_python() -> None:
if sys.version_info < (3, 11):
raise SystemExit(
"Python 3.11+ is required (SciPy>=1.16 and NumPy>=2.x). "
f"Found {sys.version.split()[0]}"
)
def _check_packages() -> None:
missing: list[str] = []
versions: dict[str, str] = {}
for module_name, pip_name in REQUIRED:
try:
module = importlib.import_module(module_name)
except Exception:
missing.append(pip_name or module_name)
continue
version = getattr(module, "__version__", "unknown")
versions[module_name] = version
if missing:
print("Missing packages:", ", ".join(sorted(missing)))
print("Install them with: pip install -e .[dev]")
raise SystemExit(1)
print("Detected package versions:")
for name in sorted(versions):
print(f" {name:>10s} : {versions[name]}")
def _mkdirs(root: Path) -> None:
for sub in (
"results/data",
"results/figures",
"results/figures/notebook_replicas",
"results/tables",
"results/cache",
"results/logs",
):
path = root / sub
path.mkdir(parents=True, exist_ok=True)
print(f"Ensured results/ tree under {root.resolve()}")
def _safe_rmtree(path: Path) -> None:
import os
import shutil
import stat
root = (Path(__file__).parent / "results").resolve()
target = path.resolve()
if not str(target).startswith(str(root)):
raise RuntimeError(f"Refusing to delete outside results/: {target}")
if target.exists():
def _on_rm_error(func, p, exc_info):
try:
os.chmod(p, stat.S_IWUSR)
func(p)
except Exception:
pass
shutil.rmtree(target, onerror=_on_rm_error)
def main() -> None:
parser = argparse.ArgumentParser(description="Bootstrap environment and folders")
parser.add_argument("--reset", choices=["cache", "all"], help="Delete results cache or full results/*")
args = parser.parse_args()
_check_python()
_check_packages()
root = Path(__file__).parent
results = root / "results"
results.mkdir(exist_ok=True)
if args.reset:
if args.reset == "all":
_safe_rmtree(results)
else:
_safe_rmtree(results / "cache")
print(f"Reset completed: {args.reset}")
_mkdirs(root)
print("All good. Try a quick sanity run, for example:")
print(" python analysis/run_final_analysis.py --mode CSK --num-seeds 4 --sequence-length 200 --recalibrate --resume --progress tqdm")
print("\nOr test parallel execution:")
print(" python analysis/run_master.py --modes all --parallel-modes 3 --resume --progress rich")
if __name__ == "__main__":
main()