-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrun.py
More file actions
152 lines (122 loc) · 6.34 KB
/
Copy pathrun.py
File metadata and controls
152 lines (122 loc) · 6.34 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
"""
AutoBIDSify Executor
Runs a BIDS conversion using the package folder downloaded from AutoBIDSify
(contains _staging/BIDSPlan.yaml and trio files) against a local dataset folder.
"""
import sys
import threading
import io
from pathlib import Path
import tkinter as tk
from tkinter import filedialog, messagebox, scrolledtext
if getattr(sys, "frozen", False):
_root = Path(sys._MEIPASS)
else:
_root = Path(__file__).parent
sys.path.insert(0, str(_root))
from utils import read_yaml, info, warn
from converters.executor import execute_bids_plan
class StdoutRedirect(io.TextIOBase):
def __init__(self, widget: scrolledtext.ScrolledText):
self.widget = widget
def write(self, text: str) -> int:
self.widget.after(0, self._append, text)
return len(text)
def _append(self, text: str):
self.widget.configure(state="normal")
self.widget.insert("end", text)
self.widget.see("end")
self.widget.configure(state="disabled")
class App(tk.Tk):
def __init__(self):
super().__init__()
self.title("AutoBIDSify Executor")
self.resizable(True, True)
self.minsize(640, 500)
self._build_ui()
def _build_ui(self):
pad = {"padx": 12, "pady": 5}
tk.Label(self, text="AutoBIDSify Executor", font=("Helvetica", 16, "bold")).pack(**pad, anchor="w")
tk.Label(self, text="Convert your dataset to BIDS using the package downloaded from AutoBIDSify",
fg="gray").pack(padx=12, anchor="w")
tk.Frame(self, height=8).pack()
# ── Conversion package folder ──────────────────────────────────
tk.Label(self, text="Step 1 — Select the conversion package folder downloaded from AutoBIDSify:",
font=("Helvetica", 11, "bold")).pack(padx=12, anchor="w")
tk.Label(self, text="(The folder contains _staging/BIDSPlan.yaml, dataset_description.json, README.md, participants.tsv)",
fg="gray", font=("Helvetica", 9)).pack(padx=12, anchor="w")
frm1 = tk.Frame(self)
frm1.pack(fill="x", padx=12, pady=4)
self.pkg_var = tk.StringVar()
tk.Entry(frm1, textvariable=self.pkg_var, width=55).pack(side="left", expand=True, fill="x")
tk.Button(frm1, text="Browse", command=self._browse_pkg).pack(side="left", padx=(6, 0))
tk.Frame(self, height=6).pack()
# ── Raw data folder ────────────────────────────────────────────
tk.Label(self, text="Step 2 — Select your raw dataset folder:",
font=("Helvetica", 11, "bold")).pack(padx=12, anchor="w")
tk.Label(self, text="(The original folder containing your DICOM, SNIRF, .mat, or NIfTI files)",
fg="gray", font=("Helvetica", 9)).pack(padx=12, anchor="w")
frm2 = tk.Frame(self)
frm2.pack(fill="x", padx=12, pady=4)
self.input_var = tk.StringVar()
tk.Entry(frm2, textvariable=self.input_var, width=55).pack(side="left", expand=True, fill="x")
tk.Button(frm2, text="Browse", command=self._browse_input).pack(side="left", padx=(6, 0))
tk.Frame(self, height=8).pack()
# ── Run button ─────────────────────────────────────────────────
self.run_btn = tk.Button(self, text="Run Conversion",
font=("Helvetica", 12, "bold"),
padx=16, pady=6,
command=self._start_conversion)
self.run_btn.pack(padx=12, anchor="w")
# ── Log output ─────────────────────────────────────────────────
tk.Label(self, text="Output:", anchor="w").pack(padx=12, anchor="w", pady=(8, 0))
self.log = scrolledtext.ScrolledText(self, height=16, state="disabled",
bg="black", fg="lightgreen",
font=("Courier", 10))
self.log.pack(fill="both", expand=True, padx=12, pady=(0, 12))
redirect = StdoutRedirect(self.log)
sys.stdout = redirect
sys.stderr = redirect
def _browse_pkg(self):
path = filedialog.askdirectory(title="Select conversion package folder")
if path:
self.pkg_var.set(path)
def _browse_input(self):
path = filedialog.askdirectory(title="Select raw dataset folder")
if path:
self.input_var.set(path)
def _start_conversion(self):
pkg_path = self.pkg_var.get().strip()
input_path = self.input_var.get().strip()
if not pkg_path or not input_path:
messagebox.showerror("Missing fields", "Please fill in both fields.")
return
pkg_dir = Path(pkg_path)
input_root = Path(input_path)
plan_file = pkg_dir / "_staging" / "BIDSPlan.yaml"
if not plan_file.exists():
messagebox.showerror("Not found",
f"BIDSPlan.yaml not found inside the package folder.\n"
f"Expected: {plan_file}\n\n"
"Make sure you selected the folder downloaded from AutoBIDSify.")
return
if not input_root.is_dir():
messagebox.showerror("Not found", f"Raw dataset folder not found:\n{input_root}")
return
self.run_btn.configure(state="disabled", text="Running...")
threading.Thread(target=self._run, args=(plan_file, input_root, pkg_dir),
daemon=True).start()
def _run(self, plan_file: Path, input_root: Path, output_dir: Path):
try:
plan_dict = read_yaml(plan_file)
execute_bids_plan(input_root, output_dir, plan_dict, {})
bids_out = output_dir / "bids_compatible"
self.after(0, lambda: messagebox.showinfo(
"Done", f"Conversion complete!\nBIDS dataset: {bids_out}"))
except Exception as e:
self.after(0, lambda: messagebox.showerror("Error", str(e)))
finally:
self.after(0, lambda: self.run_btn.configure(state="normal", text="Run Conversion"))
if __name__ == "__main__":
app = App()
app.mainloop()