Skip to content

Commit

Permalink
Add functions to facilitate the copying of step settings from outside…
Browse files Browse the repository at this point in the history
… of MAP Client.
  • Loading branch information
hsorby committed Nov 5, 2023
1 parent 48cfd44 commit 9a60dbe
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 61 deletions.
77 changes: 45 additions & 32 deletions src/mapclient/core/managers/workflowmanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@


def _get_workflow_configuration(location):
return QtCore.QSettings(_get_workflow_configuration_absolute_filename(location), QtCore.QSettings.IniFormat)
return QtCore.QSettings(_get_workflow_configuration_absolute_filename(location), QtCore.QSettings.Format.IniFormat)


def _get_workflow_requirements(location):
Expand Down Expand Up @@ -115,7 +115,7 @@ def getFilteredStepModel(self):

def updateAvailableSteps(self):
self._steps.reload()
self._filtered_steps.sort(1, QtCore.Qt.AscendingOrder)
self._filtered_steps.sort(1, QtCore.Qt.SortOrder.AscendingOrder)

def undoStackIndexChanged(self, index):
self._currentStateIndex = index
Expand Down Expand Up @@ -156,47 +156,66 @@ def changeIdentifier(self, old_identifier, new_identifier):
def _checkRequirements(self):
requirements_file = _get_workflow_requirements_absolute_filename(self._location)

def new(self, location):
"""
Create a new workflow at the given location. The location is a directory, it must exist
it will not be created. A file is created in the directory at 'location' which holds
information describing the workflow.
"""
@staticmethod
def _check_workflow_location(location):
if location is None:
raise WorkflowError('No location given to create new Workflow.')

if not os.path.exists(location):
raise WorkflowError('Location %s does not exist.' % location)
raise WorkflowError(f'Location {location} does not exist.')

self.set_location(location)
if not os.path.isdir(location):
raise WorkflowError(f'Location {location} is not a directory.')

wf = _get_workflow_configuration(location)
if wf.contains('version'):
workflow_version = wf.value('version')
if version.parse(workflow_version) > version.parse('0.20.0'):
if wf.value('id') != info.DEFAULT_WORKFLOW_PROJECT_IDENTIFIER:
raise WorkflowError(f'Location {location} does not have a valid workflow configuration file.')
else:
raise WorkflowError(f'Location {location} does not have a valid workflow configuration file.')

def load_workflow_virtually(self, location):
self._check_workflow_location(location)

return _get_workflow_configuration(location)

@staticmethod
def create_empty_workflow(location):
wf = _get_workflow_configuration(location)
wf.setValue('version', info.VERSION_STRING)
wf.setValue('id', info.DEFAULT_WORKFLOW_PROJECT_IDENTIFIER)
return wf

def new(self, location):
"""
Create a new workflow at the given location. The location is a directory, it must exist
it will not be created. A file is created in the directory at 'location' which holds
information describing the workflow.
"""
self._check_workflow_location(location)
self.set_location(location)
self.create_empty_workflow(location)
self._scene.clear()

def exists(self, location):
"""
Determines whether a workflow exists in the given location.
Returns True if a valid workflow exists, False otherwise.
"""
if location is None:
return False

if not os.path.exists(location):
try:
self._check_workflow_location(location)
except WorkflowError:
return False

wf = _get_workflow_configuration(location)
if wf.contains('version'):
return True

return False
return True

@staticmethod
def is_restricted(location):
if location is None or not os.path.exists(location) or not os.path.isdir(location):
return False

wf = _get_workflow_configuration(location)
if not wf.contains('version'):
try:
WorkflowManager._check_workflow_location(location)
except WorkflowError:
return False

return is_workflow_in_use(location)
Expand All @@ -207,18 +226,12 @@ def load(self, location, scene_rect=QtCore.QPointF(0, 0)):
:param location:
:param scene_rect: Rectangle of the scene rect to load the workflow into.
"""
if location is None:
raise WorkflowError('No location given to open Workflow.')

if not os.path.exists(location):
raise WorkflowError('Given location %s does not exist' % location)

if os.path.isfile(location):
location = os.path.dirname(location)

self._check_workflow_location(location)

wf = _get_workflow_configuration(location)
if not wf.contains('version'):
raise WorkflowError('The given Workflow configuration file is not valid.')

workflow_version = version.parse(wf.value('version'))
application_version = version.parse(info.VERSION_STRING)
Expand Down
22 changes: 22 additions & 0 deletions src/mapclient/core/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"""
import os
import re
import shutil
import sys
from pathlib import Path

Expand Down Expand Up @@ -150,6 +151,27 @@ def load_configuration(location, identifier):
return configuration


def copy_step_additional_config_files(step, source_configuration_dir, target_configuration_dir):
for additional_cfg_file in step.getAdditionalConfigFiles():
source_cfg_dir = os.path.dirname(additional_cfg_file)
if os.path.isabs(additional_cfg_file):
relative_dir = os.path.relpath(source_configuration_dir, source_cfg_dir)
source_cfg_file = additional_cfg_file
else:
relative_dir = source_cfg_dir
source_cfg_file = os.path.join(source_configuration_dir, additional_cfg_file)

source_basename = os.path.basename(additional_cfg_file)
source_workflow_relative_cfg = os.path.join(relative_dir, source_basename)

target_cfg_file = os.path.realpath(os.path.join(target_configuration_dir, source_workflow_relative_cfg))
if os.path.isfile(source_cfg_file):
required_path = os.path.join(target_configuration_dir, relative_dir)
if not os.path.exists(required_path):
os.makedirs(required_path)
shutil.copyfile(source_cfg_file, target_cfg_file)


class FileTypeObject(object):
def __init__(self):
self.messages = list()
Expand Down
2 changes: 1 addition & 1 deletion src/mapclient/core/workflow/workflowitems.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class MetaStep(Item):
def __init__(self, step):
Item.__init__(self)
self._step = step
self._pos = QtCore.QPointF(0, 0)
self._pos = QtCore.QPointF(10, 10)
self._uid = str(uuid.uuid1())
self._id = step.getIdentifier()

Expand Down
56 changes: 56 additions & 0 deletions src/mapclient/core/workflow/workflowscene.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from PySide6 import QtCore

from mapclient.core.workflow.workflowdependencygraph import WorkflowDependencyGraph
from mapclient.core.workflow.workflowerror import WorkflowError
from mapclient.core.workflow.workflowitems import MetaStep, Connection
from mapclient.mountpoints.workflowstep import workflowStepFactory
from mapclient.core.utils import load_configuration
Expand Down Expand Up @@ -154,6 +155,61 @@ def _read_step_names(ws):

return step_names

def create_from(self, ws, name_identifiers, location):
"""
Create a workflow from the given names at the given location.
Returns a list of
:param ws: Workflow settings object.
:param name_identifiers: List of tuples consisting of step names and associated identifiers.
:param location: Location of the workflow on the local disk.
:return: List of steps.
"""
steps = []
try:
ws.beginGroup('nodes')
ws.beginWriteArray('nodelist')
for i, name_identifier in enumerate(name_identifiers):
ws.setArrayIndex(i)
step = workflowStepFactory(name_identifier[0], location)
step.setIdentifier(name_identifier[1])
meta_step = MetaStep(step)
ws.setValue('name', step.getName())
ws.setValue('position', meta_step.getPos())
ws.setValue('selected', meta_step.getSelected())
ws.setValue('identifier', meta_step.getIdentifier())
ws.setValue('unique_identifier', meta_step.getUniqueIdentifier())
steps.append(step)

ws.endArray()
ws.endGroup()

except ValueError:
names = [name_identifier[0] for name_identifier in name_identifiers]
raise WorkflowError(f'Could not create workflow from names: {names}')

return steps

@staticmethod
def get_step_name_from_identifier(ws, target_identifier):
ws.beginGroup('nodes')
step_name = ''
node_count = ws.beginReadArray('nodelist')
i = 0
while i < node_count and not step_name:
ws.setArrayIndex(i)
name = ws.value('name')
identifier = ws.value('identifier')
if identifier == target_identifier:
step_name = name

i += 1

ws.endArray()
ws.endGroup()

return step_name

def doStepReport(self, ws):
report = {}
ws.beginGroup('nodes')
Expand Down
1 change: 1 addition & 0 deletions src/mapclient/settings/info.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
DEFAULT_WORKFLOW_PROJECT_FILENAME = f'{_BASE_WORKFLOW_FILENAME}.proj'
DEFAULT_WORKFLOW_ANNOTATION_FILENAME = f'.{_BASE_WORKFLOW_FILENAME}.rdf'
DEFAULT_WORKFLOW_REQUIREMENTS_FILENAME = f'.{_BASE_WORKFLOW_FILENAME}.req'
DEFAULT_WORKFLOW_PROJECT_IDENTIFIER = _BASE_WORKFLOW_FILENAME


def set_applications_settings(app):
Expand Down
30 changes: 2 additions & 28 deletions src/mapclient/view/workflow/importconfigdialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from packaging import version

from mapclient.settings.info import DEFAULT_WORKFLOW_PROJECT_FILENAME, VERSION_STRING
from mapclient.core.utils import load_configuration
from mapclient.core.utils import load_configuration, copy_step_additional_config_files
from mapclient.core.workflow.workflowitems import MetaStep
from mapclient.view.workflow.workflowgraphicsitems import Node
from mapclient.view.workflow.ui.ui_importconfigdialog import Ui_ImportConfigDialog
Expand Down Expand Up @@ -153,33 +153,7 @@ def _do_import(self, configuration_dir, node_dict):
current_step_location = step.getLocation()
step.setLocation(configuration_dir)
step.deserialize(configuration)

# print(f'{current_text} ==> {identifier}')
# print('current location:', current_step_location)
# print('source step location:', step.getLocation())
for additional_cfg_file in step.getAdditionalConfigFiles():
target_cfg_dir = os.path.dirname(additional_cfg_file)
if os.path.isabs(additional_cfg_file):
relative_dir = os.path.relpath(configuration_dir, target_cfg_dir)
source_cfg_file = additional_cfg_file
else:
relative_dir = target_cfg_dir
source_cfg_file = os.path.join(configuration_dir, additional_cfg_file)

source_basename = os.path.basename(additional_cfg_file)
source_workflow_relative_cfg = os.path.join(relative_dir, source_basename)

target_cfg_file = os.path.realpath(os.path.join(current_step_location, source_workflow_relative_cfg))
# print('reported cfg file.', additional_cfg_file)
# print('source cfg file.', source_cfg_file)
# print('target cfg file.', target_cfg_file)
# print('is file:', os.path.isfile(source_cfg_file))
if os.path.isfile(source_cfg_file):
required_path = os.path.join(current_step_location, relative_dir)
if not os.path.exists(required_path):
os.makedirs(required_path)
shutil.copyfile(source_cfg_file, target_cfg_file)

copy_step_additional_config_files(step, configuration_dir, current_step_location)
step.setLocation(current_step_location)
self._workflow_scene.changeIdentifier(meta_step)

Expand Down

0 comments on commit 9a60dbe

Please sign in to comment.