start threading

This commit is contained in:
Ross Kruger
2024-06-21 11:27:40 +01:00
parent e52349ab46
commit 30f8d040c8
+109 -19
View File
@@ -77,11 +77,74 @@ import time
import datetime
import contextlib
import threading
# import watchdog.observers
__VERSION__ = "0.1"
__APP_NAME__ = "Uploader"
# Define notification event for thread completion
EVT_RESULT_ID = wx.NewId()
def EVT_RESULT(win, func):
"""Define Result Event."""
win.Connect(-1, -1, EVT_RESULT_ID, func)
class ResultEvent(wx.PyEvent):
"""Simple event to carry arbitrary result data."""
def __init__(self, data):
"""Init Result Event."""
wx.PyEvent.__init__(self)
self.SetEventType(EVT_RESULT_ID)
self.data = data
# Thread class that executes processing
class WorkerThread(threading.Thread):
"""Worker Thread Class."""
def __init__(self, notify_window):
"""Init Worker Thread Class."""
threading.Thread.__init__(self)
self._notify_window = notify_window
self._want_abort = 0
# This starts the thread running on creation, but you could
# also make the GUI thread responsible for calling this
self.start()
def run(self):
"""Run Worker Thread."""
# This is the code executing in the new thread. Simulation of
# a long process (well, 10s here) as a simple loop - you will
# need to structure your processing so that you periodically
# peek at the abort variable
for i in range(10):
time.sleep(1)
if self._want_abort:
# Use a result of None to acknowledge the abort (of
# course you can use whatever you'd like or even
# a separate event type)
wx.PostEvent(self._notify_window, ResultEvent(None))
return
# Here's where the result would be returned (this is an
# example fixed result of the number 10, but it could be
# any Python object)
wx.PostEvent(self._notify_window, ResultEvent(10))
def abort(self):
"""abort worker thread."""
# Method for use by main thread to signal an abort
self._want_abort = 1
def resource_path(relative_path):
""" Get absolute path to resource, works for dev and for PyInstaller """
try:
# PyInstaller creates a temp folder and stores path in _MEIPASS
base_path = sys._MEIPASS
except Exception:
base_path = os.path.abspath(".")
return os.path.join(base_path, relative_path)
anonymizer = dicognito.anonymizer.Anonymizer()
# determine if application is a script file or frozen exe
@@ -194,6 +257,7 @@ def annonymise(
i += 1
# new_filepath = Path(output_dir).joinpath(f"IMG_{i:03}.dcm")
logger.debug(f"anon: {n}")
anonymize_file(file, new_filepath)
# progress_dialog.Destroy()
@@ -201,6 +265,7 @@ def annonymise(
return new_filepath
@logger.catch()
def anonymize_file(file: Path, new_filepath: Path, remove_original: bool = False):
logger.debug(f"Annonymise file, in={file}, out={new_filepath}")
# Ensure the output folder exists
@@ -517,6 +582,8 @@ class AnonGui(wx.App):
self.rqst = None
self.worker = None
wx.App.__init__(self, redirect, filename)
def my_listener(self, message, arg2=None):
@@ -571,7 +638,7 @@ class AnonGui(wx.App):
size=(300, 400),
)
self.frame.SetIcon(wx.Icon("icon/icon1.ico"))
self.frame.SetIcon(wx.Icon(resource_path("icon\icon1.ico")))
self.panel = wx.Panel(self.frame, wx.ID_ANY)
@@ -834,6 +901,16 @@ class AnonGui(wx.App):
if input_dir.is_dir():
logger.debug("is dir")
files = list(Path(input_dir).rglob("*.dcm"))
if not files:
# TODO load from DICOMDIR
to_exclude = ("DICOMDIR")
files = [i for i in Path(input_dir).rglob("*") if i.is_file() and i.name not in to_exclude]
else:
return
@@ -859,20 +936,25 @@ class AnonGui(wx.App):
with self.progress(len(files), "Annonymise files") as p:
# p.SetRange(len(files))
i: int = 0
for n, file in enumerate(files):
# progress_dialog.Update(n)
p.update(n)
new_filepath: Path
# Get next available filename
i: int = 0
while os.path.exists(
new_filepath := output_dir.joinpath(f"IMG_{i:03}.dcm")
):
i += 1
# new_filepath = Path(output_dir).joinpath(f"IMG_{i:03}.dcm")
dataset, filepath = anonymize_file(file, new_filepath, remove_original=remove_original)
self.add_datails_to_file_detail_map(dataset, filepath)
logger.debug(f"anon: {n}")
try:
dataset, filepath = anonymize_file(file, new_filepath, remove_original=remove_original)
except pydicom.errors.InvalidDicomError:
continue
self.add_datails_to_file_detail_map(dataset, filepath)
wx.GetApp().Yield()
# progress_dialog.Destroy()
self.LoadDir(self.dir)
@@ -942,7 +1024,7 @@ base site url: {self.base_site_url}
info.SetName(__APP_NAME__)
info.SetVersion(__VERSION__)
info.SetDescription(description)
icon_path = "icon/icon1.png"
icon_path = resource_path("icon\icon1.png")
desired_width = 200
desired_height = 200
@@ -1136,7 +1218,12 @@ base site url: {self.base_site_url}
files = [Path(self.dir, f) for f, file_hash in files]
for f in files:
os.remove(f)
try:
os.remove(f)
except OSError:
logger.debug(f"File to delete not found: {f}")
pass
if load_dir:
self.LoadDir(clear_file_detail_map=True)
@@ -1252,20 +1339,22 @@ base site url: {self.base_site_url}
hashes = []
for n, f in enumerate(self.files):
logger.debug(f"update {n}")
# progress_dialog.Update(n)
p.update(n)
#p.update(n)
# dataset = pydicom.read_file(f)
if f in self.file_detail_map:
d, hash, d2 = self.file_detail_map[f]
print(f"{n}: in map")
#print(f"{n}: in map")
else:
logger.debug("read: {f}")
try:
dataset = pydicom.dcmread(f)
except FileNotFoundError:
return
print("recalc")
#print("recalc")
d, hash, d2 = self.add_datails_to_file_detail_map(dataset, f)
hashes.append(hash)
@@ -1283,18 +1372,18 @@ base site url: {self.base_site_url}
except:
logger.debug(f"Unable to get Series Instance UID: {f.name}")
logger.debug(d)
DATA[n] = d
self.list_ctrl.Append(d)
self.list_ctrl.SetItemPyData(n, {"file": f, "hash": hash})
self.list_ctrl.SetItemData(n, n)
#logger.debug(d)
#DATA[n] = d
#self.list_ctrl.Append(d)
#self.list_ctrl.SetItemPyData(n, {"file": f, "hash": hash})
##self.list_ctrl.SetItemData(n, n)
if f in self.file_duplicate_check:
if self.file_duplicate_check[f]["id"]:
self.list_ctrl.SetItemBackgroundColour(n, wx.RED)
n = n + 1
self.list_ctrl.UpdateData(DATA)
#self.list_ctrl.UpdateData(DATA)
self.populate_series_grid()
self.frame.Refresh()
@@ -1347,9 +1436,9 @@ base site url: {self.base_site_url}
duplicate_files_not_uploaded = []
logger.debug("Upload files")
for f in self.files:
if f in self.file_duplicate_check:
# duplicate the api return format so ClearFiles works
duplicate_files_not_uploaded.append((f.name, "..."))
if f in self.file_duplicate_check and self.file_duplicate_check[f]["id"]:
# duplicate the api return format so ClearFiles works
duplicate_files_not_uploaded.append((f.name, "..."))
else:
files_to_upload.append(("files", open(str(f), "rb")))
@@ -1420,7 +1509,7 @@ base site url: {self.base_site_url}
if self.clear_files_on_upload:
all_files = upload_file_list + duplicate_file_list + duplicate_files_not_uploaded
print(all_files)
self.ClearFiles(event=None, load_dir=True, files=all_files)
wx.CallAfter(self.ClearFiles,event=None, load_dir=True, files=all_files)
def upload_complete_message(self, upload_file_list, duplicate_file_list, failed, duplicate_files_not_uploaded):
wx.MessageBox(
@@ -1501,3 +1590,4 @@ def launchGUI(
if __name__ == "__main__":
app()