-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCellACDC.py
More file actions
256 lines (216 loc) · 9.4 KB
/
CellACDC.py
File metadata and controls
256 lines (216 loc) · 9.4 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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
try:
import pathlib
import os
import subprocess
import argparse
import json
import datetime
import sys
import traceback
import platform
except ImportError as e:
print(f"❌ Import error: {e}")
print("Please ensure all required modules are installed.")
sys.exit(1)
def run_subprocess_with_logging(cmd):
"""Run subprocess and capture all output to log file with real-time streaming"""
if isinstance(cmd, str):
cmd = [cmd]
print("-" * 40)
print(f"🔧 Running command: {' '.join(cmd)}")
print(f" Working Directory: {os.getcwd()}")
print(f" Timestamp: {datetime.datetime.now().strftime('%H:%M:%S')}")
print("📤 Command output (streaming):")
try:
start_time = datetime.datetime.now()
# Start the process with pipes for real-time output
process = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, # Merge stderr into stdout for unified output
text=True,
encoding='utf-8',
errors='replace',
bufsize=1,
universal_newlines=True
)
# Stream output in real-time
output_lines = []
while True:
output = process.stdout.readline()
if output == '' and process.poll() is not None:
break
if output:
# Print to console (and thus to log via Tee)
print(output.rstrip())
output_lines.append(output)
# Wait for process to complete and get return code
return_code = process.poll()
end_time = datetime.datetime.now()
duration = (end_time - start_time).total_seconds()
if return_code == 0:
print(f" ✅ Command completed successfully in {duration:.2f} seconds")
else:
print(f"❌ Command failed with return code {return_code} after {duration:.2f} seconds")
raise subprocess.CalledProcessError(return_code, cmd, output=''.join(output_lines))
print("-" * 40)
except subprocess.CalledProcessError as e:
print(f"❌ Command failed with return code {e.returncode}")
print("-" * 40)
raise e
except Exception as e:
print(f"❌ Error running subprocess: {e}")
print("-" * 40)
raise e
class Tee:
def __init__(self, *files):
self.files = files
def write(self, obj):
for f in self.files:
try:
# Ensure we're writing strings and handle encoding
if isinstance(obj, bytes):
obj = obj.decode('utf-8', errors='replace')
f.write(obj)
f.flush()
except (UnicodeEncodeError, ValueError):
# Fallback for encoding issues - write to console only
if f != sys.__stdout__ and f != sys.__stderr__:
try:
sys.__stdout__.write(obj)
sys.__stdout__.flush()
except:
pass
def flush(self):
for f in self.files:
try:
f.flush()
except (ValueError, AttributeError):
pass
def setup_logging():
# Set up logging at the beginning of your script
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
log_filename = f"{timestamp}_cellacdc_launch.log"
user_home_path = str(pathlib.Path.home())
user_profile_path = os.path.join(user_home_path, 'acdc-appdata')
log_path = os.path.join(user_profile_path, ".acdc-logs", log_filename)
os.makedirs(os.path.dirname(log_path), exist_ok=True)
# Open log file with UTF-8 encoding
log_file = open(log_path, 'w', encoding='utf-8', errors='replace')
# Store original stdout/stderr
original_stdout = sys.stdout
original_stderr = sys.stderr
# Redirect stdout and stderr to both console and log file
sys.stdout = Tee(original_stdout, log_file)
sys.stderr = Tee(original_stderr, log_file)
# Log session header with system information
print("=" * 80)
print(f"Cell-ACDC Session - {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print("=" * 80)
print(f"System Information:")
print(f" Platform: {platform.platform()}")
print(f" Python Version: {sys.version}")
print(f" Working Directory: {os.getcwd()}")
print(f" Log File: {log_path}")
print("=" * 80)
print()
print(f"📄 Launch log will be saved to: {log_path}")
return log_file, original_stdout, original_stderr, log_path
def print_closing_logging(target_dir, install_configs):
print()
print("=" * 80)
print("RUN SUMMARY")
print("=" * 80)
print(f"Target Directory: {target_dir}")
print(f"Using install details from: {install_configs}")
print(f"Session End: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print("=" * 80)
print("✅ Run completed successfully!")
if __name__ == "__main__":
try:
# Set up logging at the beginning of your script
log_file, original_stdout, original_stderr, log_path = setup_logging()
start_time = datetime.datetime.now()
parser = argparse.ArgumentParser()
parser.add_argument('--target', help='Target install path')
args = parser.parse_args()
target_dir = args.target if args.target else os.getcwd()
install_configs = os.path.join(target_dir, "install_details.json")
if not os.path.exists(install_configs):
raise FileNotFoundError(f"""Install details file not found: {install_configs},
please either use the --target argument to specify the correct path,
or ensure that the file exists in the current working directory.""")
repo_url = "https://github.com/SchmollerLab/Cell_ACDC"
with open(install_configs, 'r', encoding='utf-8', errors='replace') as f:
install_details = json.load(f)
venv_path = install_details.get("venv_path", "")
venv_path =venv_path.strip('"')
is_conda = install_details.get("conda", False)
conda_path = install_details.get("conda_path", "")
conda_path = conda_path.strip('"')
print("🚀 Launching CellACDC...")
is_windows = platform.system().lower() == "windows"
# Open PowerShell in the same terminal
if not is_conda:
if is_windows:
acdc_exec_path = os.path.join(venv_path, "Scripts", "acdc.exe")
else:
acdc_exec_path = os.path.join(venv_path, "bin", "acdc")
subprocess.run([acdc_exec_path,
"--install_details", os.path.join(target_dir, "install_details.json")])
else:
condarc_path = os.path.join(target_dir, ".condarc")
if os.path.exists(condarc_path):
env = os.environ.copy()
env["CONDARC"] = condarc_path
else:
env = None
if is_windows:
acdc_exec_path = os.path.join(venv_path, "Scripts", "acdc.exe")
else:
acdc_exec_path = os.path.join(venv_path, "bin", "acdc")
subprocess.run([acdc_exec_path,
"--install_details", os.path.join(target_dir, "install_details.json")], env=env)
elapsed_time = datetime.datetime.now() - start_time
print(f"Thanks for using CellACDC, you spend {elapsed_time.total_seconds():.2f} seconds on this session!")
# Log final session summary
print_closing_logging(target_dir, install_configs)
except Exception as e:
# Restore original stdout/stderr for error handling
sys.stdout = original_stdout
sys.stderr = original_stderr
print()
print("=" * 80)
print("ERROR")
print("=" * 80)
print("❌ An error occurred.")
print(f"Error: {str(e)}")
print(f"Error Time: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
traceback.print_exc()
# Save error to log file
try:
with open(log_path, 'a', encoding='utf-8', errors='replace') as f:
f.write(f"\n\n{'='*80}\n")
f.write(f"ERROR - {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
f.write(f"{'='*80}\n")
f.write(f"❌ ERROR: {str(e)}\n")
f.write(f"Traceback:\n{traceback.format_exc()}\n")
f.write(f"{'='*80}\n")
print(f"📄 Full log saved to: {log_path}")
print("=" * 80)
except:
print("⚠️ Could not save error log.")
print("Log files are saved in the following directory:")
print(os.path.dirname(log_path))
print("Please copy the two newest log files, and report this issue to the CellACDC team at:")
print(repo_url)
input("❌!!!CELL-ACDC IS IN ERROR STATE!!!❌ Press Enter to close this window...")
finally:
# Safely close log file and restore stdout/stderr
try:
sys.stdout = original_stdout
sys.stderr = original_stderr
if 'log_file' in locals() and not log_file.closed:
log_file.close()
except:
pass