Skip to content

Commit

Permalink
Merge pull request ilastik#2882 from thodkatz/add-indicator-starting-…
Browse files Browse the repository at this point in the history
…tiktorch-server

Add wait cursor when tiktorch server is started
  • Loading branch information
k-dominik authored Aug 7, 2024
2 parents 7e9bb44 + 1b3a08c commit 0d9e807
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 135 deletions.
112 changes: 56 additions & 56 deletions ilastik/shell/gui/ilastikShell.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import platform
import threading
import warnings
from typing import List, Type, Optional

# SciPy
import numpy
Expand Down Expand Up @@ -74,7 +75,7 @@

# ilastik
import ilastik.ilastik_logging.default_config
from ilastik.workflow import getAvailableWorkflows, getWorkflowFromName
from ilastik.workflow import getAvailableWorkflows, getWorkflowFromName, Workflow
from ilastik.utility import bind, log_exception
from ilastik.utility.gui import ThunkEventHandler, ThreadRouter, threadRouted
from ilastik.exceptions import UserAbort
Expand Down Expand Up @@ -508,8 +509,7 @@ def workflow(self):
def loadWorkflow(self, workflow_class):
self.onNewProjectActionTriggered(workflow_class)

def getWorkflow(self, w=None):

def getWorkflow(self, w: Optional[str] = None) -> Type[Workflow]:
listOfItems = [workflowDisplayName for _, __, workflowDisplayName in getAvailableWorkflows()]
if w is not None and w in listOfItems:
cur = listOfItems.index(w)
Expand Down Expand Up @@ -579,7 +579,6 @@ def _createProjectMenu(self):
return (menu, shellActions)

def setupOpenFileButtons(self):

for b in self.openFileButtons:
b.close()
b.deleteLater()
Expand Down Expand Up @@ -1644,81 +1643,83 @@ def _loadProject(self, hdf5File, projectFilePath, workflow_class, readOnly, impo

try:
assert self.projectManager is None, "Expected projectManager to be None."
QApplication.setOverrideCursor(Qt.WaitCursor)
self.projectManager = ProjectManager(
self,
workflow_class,
workflow_cmdline_args=self._workflow_cmdline_args,
project_creation_args=project_creation_args,
)

except Exception as e:
msg = "Could not load project file.\n" + str(e)
log_exception(logger, msg)
QMessageBox.warning(self, "Failed to Load", msg)

# no project will be loaded, free the file resource
hdf5File.close()
else:
return
finally:
QApplication.restoreOverrideCursor()

try:
# Add all the applets from the workflow
for index, app in enumerate(self.projectManager.workflow.applets):
self.addApplet(index, app)

start = time.perf_counter()
# load the project data from file
if importFromPath is None:
# FIXME: load the project asynchronously
self.projectManager.loadProject(hdf5File, projectFilePath, readOnly)
else:
assert not readOnly, "Can't import into a read-only file."
self.projectManager.importProject(importFromPath, hdf5File, projectFilePath)
except Exception as ex:
self.closeCurrentProject()

# loadProject failed, so we cannot expect it to clean up
# the hdf5 file (but it might have cleaned it up, so we catch
# the error)
try:
# Add all the applets from the workflow
for index, app in enumerate(self.projectManager.workflow.applets):
self.addApplet(index, app)

start = time.perf_counter()
# load the project data from file
if importFromPath is None:
# FIXME: load the project asynchronously
self.projectManager.loadProject(hdf5File, projectFilePath, readOnly)
else:
assert not readOnly, "Can't import into a read-only file."
self.projectManager.importProject(importFromPath, hdf5File, projectFilePath)
except Exception as ex:
self.closeCurrentProject()

# loadProject failed, so we cannot expect it to clean up
# the hdf5 file (but it might have cleaned it up, so we catch
# the error)
try:
hdf5File.close()
except:
pass
hdf5File.close()
except:
pass

if not isinstance(ex, UserAbort):
log_exception(logger)
QMessageBox.warning(self, "Failed to Load", "Could not load project file.\n" + str(ex))
if not isinstance(ex, UserAbort):
log_exception(logger)
QMessageBox.warning(self, "Failed to Load", "Could not load project file.\n" + str(ex))
return

else:
stop = time.perf_counter()
logger.debug("Loading the project took {:.2f} sec.".format(stop - start))
stop = time.perf_counter()
logger.debug("Loading the project took {:.2f} sec.".format(stop - start))

workflowDisplayName = self.projectManager.workflow.workflowDisplayName
self._setRecentlyOpenedList(projectFilePath, workflowDisplayName)
workflowDisplayName = self.projectManager.workflow.workflowDisplayName
self._setRecentlyOpenedList(projectFilePath, workflowDisplayName)

workflowName = self.projectManager.workflow.workflowName
# be friendly to user: if this file has not specified a default workflow, do it now
if not "workflowName" in list(hdf5File.keys()) and not readOnly:
hdf5File.create_dataset("workflowName", data=workflowName.encode("utf-8"))
workflowName = self.projectManager.workflow.workflowName
# be friendly to user: if this file has not specified a default workflow, do it now
if not "workflowName" in list(hdf5File.keys()) and not readOnly:
hdf5File.create_dataset("workflowName", data=workflowName.encode("utf-8"))

# switch away from the startup screen to show the loaded project
self.mainStackedWidget.setCurrentIndex(1)
# By default, make the splitter control expose a reasonable width of the applet bar
self.mainSplitter.setSizes([300, 1])
# switch away from the startup screen to show the loaded project
self.mainStackedWidget.setCurrentIndex(1)
# By default, make the splitter control expose a reasonable width of the applet bar
self.mainSplitter.setSizes([300, 1])

self.progressDisplayManager.cleanUp()
self.progressDisplayManager.initializeForWorkflow(self.projectManager.workflow)
self.progressDisplayManager.cleanUp()
self.progressDisplayManager.initializeForWorkflow(self.projectManager.workflow)

self.setImageNameListSlot(self.projectManager.workflow.imageNameListSlot)
self.updateShellProjectDisplay()
self.setImageNameListSlot(self.projectManager.workflow.imageNameListSlot)
self.updateShellProjectDisplay()

# Enable all the applet controls
self.enableWorkflow = True
# Enable all the applet controls
self.enableWorkflow = True

if "currentApplet" in list(hdf5File.keys()):
appletName = hdf5File["currentApplet"][()]
self.setSelectedAppletDrawer(appletName)
else:
self.setSelectedAppletDrawer(self.projectManager.workflow.defaultAppletIndex)
if "currentApplet" in list(hdf5File.keys()):
appletName = hdf5File["currentApplet"][()]
self.setSelectedAppletDrawer(appletName)
else:
self.setSelectedAppletDrawer(self.projectManager.workflow.defaultAppletIndex)

def _setRecentlyOpenedList(self, projectFilePath, workflowDisplayName):
recentlyOpenedList = [(projectFilePath, workflowDisplayName)] + [
Expand All @@ -1735,7 +1736,6 @@ def closeCurrentProject(self):
"""
assert threading.current_thread().name == "MainThread"
if self.projectManager is not None:

self.removeAllAppletWidgets()
for f in self.cleanupFunctions:
f()
Expand Down
109 changes: 51 additions & 58 deletions ilastik/shell/projectManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import gc
import copy
import platform
from typing import Optional, List, Type, Dict

import h5py
import logging
import time
Expand All @@ -33,7 +35,7 @@
from ilastik import Project
from ilastik import isVersionCompatible
from ilastik.utility import log_exception
from ilastik.workflow import getWorkflowFromName
from ilastik.workflow import getWorkflowFromName, Workflow
from lazyflow.utility.timer import Timer, timeLogged

try:
Expand All @@ -57,10 +59,6 @@ class ProjectManager(object):
member for direct access to its applets and their top-level operators.
"""

#########################
## Error types
#########################

class ProjectVersionError(RuntimeError):
"""
Raised if an attempt is made to open a project file that was generated with an old version of ilastik.
Expand Down Expand Up @@ -88,13 +86,49 @@ class SaveError(RuntimeError):

pass

#########################
## Class methods
#########################
@property
def _applets(self):
if self.workflow is not None:
return self.workflow.applets
else:
return []

def __init__(
self,
shell,
workflowClass: Type[Workflow],
headless: bool = False,
workflow_cmdline_args: Optional[List[str]] = None,
project_creation_args: Optional[List[str]] = None,
):
"""
:param shell
:param workflowClass: The class of the workflow to be managed.
:param headless: Indicates whether the workflow should be opened in 'headless' mode (default is False).
:param workflow_cmdline_args: Optional list of strings from the command-line to configure the workflow.
:param project_creation_args: Optional list of strings for project creation arguments.
"""
# Init
self.closed = True
self._shell = shell
self.workflow = None
self.currentProjectFile = None
self.currentProjectPath = None
self.currentProjectIsReadOnly = False

# Instantiate the workflow.
self._workflowClass = workflowClass
self._workflow_cmdline_args = workflow_cmdline_args or []
self._project_creation_args = project_creation_args or []
self._headless = headless

@classmethod
# the workflow class has to be specified at this point
assert workflowClass is not None
self.workflow = workflowClass(shell, headless, self._workflow_cmdline_args, self._project_creation_args)

@staticmethod
def createBlankProjectFile(
cls, projectFilePath, workflow_class=None, workflow_cmdline_args=None, h5_file_kwargs={}
projectFilePath, workflow_class=None, workflow_cmdline_args=None, h5_file_kwargs: Optional[Dict] = None
):
"""Create a new ilp file at the given path and initialize it with a project version.
Expand All @@ -109,6 +143,7 @@ def createBlankProjectFile(
:rtype: h5py.File
"""
h5_file_kwargs = h5_file_kwargs or {}
# Create the blank project file
if "mode" in h5_file_kwargs:
raise ValueError("ProjectManager.createBlankProjectFile(): 'mode' is not allowed as a h5py.File kwarg")
Expand All @@ -123,12 +158,12 @@ def createBlankProjectFile(

return h5File

@classmethod
def getWorkflowName(self, projectFile):
@staticmethod
def getWorkflowName(projectFile):
return str(projectFile["workflowName"][()].decode("utf-8"))

@classmethod
def openProjectFile(cls, projectFilePath, forceReadOnly=False):
@staticmethod
def openProjectFile(projectFilePath, forceReadOnly=False):
"""
Class method.
Attempt to open the given path to an existing project file.
Expand Down Expand Up @@ -170,8 +205,8 @@ def openProjectFile(cls, projectFilePath, forceReadOnly=False):

return (hdf5File, workflow_class, readOnly)

@classmethod
def downloadProjectFromDvid(cls, hostname, node_uuid, keyvalue_name, project_key=None, local_filepath=None):
@staticmethod
def downloadProjectFromDvid(hostname, node_uuid, keyvalue_name, project_key=None, local_filepath=None):
"""
Download a file from a dvid keyvalue data instance and store it to the given local_filepath.
If no local_filepath is given, create a new temporary file.
Expand Down Expand Up @@ -208,37 +243,6 @@ def downloadProjectFromDvid(cls, hostname, node_uuid, keyvalue_name, project_key

return local_filepath

#########################
## Public methods
#########################

def __init__(self, shell, workflowClass, headless=False, workflow_cmdline_args=None, project_creation_args=None):
"""
Constructor.
:param workflowClass: A subclass of ilastik.workflow.Workflow (the class, not an instance).
:param headless: A bool that is passed to the workflow constructor,
indicating whether or not the workflow should be opened in 'headless' mode.
:param workflow_cmdline_args: A list of strings from the command-line to configure the workflow.
"""
# Init
self.closed = True
self._shell = shell
self.workflow = None
self.currentProjectFile = None
self.currentProjectPath = None
self.currentProjectIsReadOnly = False

# Instantiate the workflow.
self._workflowClass = workflowClass
self._workflow_cmdline_args = workflow_cmdline_args or []
self._project_creation_args = project_creation_args or []
self._headless = headless

# the workflow class has to be specified at this point
assert workflowClass is not None
self.workflow = workflowClass(shell, headless, self._workflow_cmdline_args, self._project_creation_args)

def cleanUp(self):
"""
Should be called when the Projectmanager is canceled. Closes the project file.
Expand Down Expand Up @@ -417,17 +421,6 @@ def saveProjectAs(self, newPath):
# Save the current project state
self.saveProject()

#########################
## Private methods
#########################

@property
def _applets(self):
if self.workflow is not None:
return self.workflow.applets
else:
return []

@timeLogged(logger, logging.DEBUG)
def loadProject(self, hdf5File, projectFilePath, readOnly):
"""
Expand Down
Loading

0 comments on commit 0d9e807

Please sign in to comment.