Source code for pyworkflow.project.config

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# **************************************************************************
# *
# * Authors:     J.M. De la Rosa Trevin (delarosatrevin@scilifelab.se) [1]
# *
# * [1] SciLifeLab, Stockholm University
# *
# * This program is free software: you can redistribute it and/or modify
# * it under the terms of the GNU General Public License as published by
# * the Free Software Foundation, either version 3 of the License, or
# * (at your option) any later version.
# *
# * This program is distributed in the hope that it will be useful,
# * but WITHOUT ANY WARRANTY; without even the implied warranty of
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# * GNU General Public License for more details.
# *
# * You should have received a copy of the GNU General Public License
# * along with this program.  If not, see <https://www.gnu.org/licenses/>.
# *
# *  All comments concerning this program package may be sent to the
# *  e-mail address 'scipion@cnb.csic.es'
# *
# **************************************************************************

import logging
logger = logging.getLogger(__name__)
import json
import datetime as dt

import pyworkflow.object as pwobj
from pyworkflow.mapper import SqliteMapper


[docs]class ProjectSettings(pwobj.Object): """ Store settings related to a project. """ COLOR_MODE_STATUS = 0 COLOR_MODE_LABELS = 1 COLOR_MODE_AGE = 2 COLOR_MODE_SIZE = 3 COLOR_MODES = (COLOR_MODE_STATUS, COLOR_MODE_LABELS, COLOR_MODE_AGE) # This has poor performance many cases, COLOR_MODE_SIZE) def __init__(self, confs={}, **kwargs): super().__init__(**kwargs) # Store the current view selected by the user self.currentProtocolsView = pwobj.String() # Store the color mode: 0= Status, 1=Labels, ... self.colorMode = pwobj.Integer(ProjectSettings.COLOR_MODE_STATUS) # Store graph nodes positions and other info self.nodeList = NodeConfigList() self.labelsList = LabelsList() # Label list self.mapper = None # This should be set when load, or write self.runsView = pwobj.Integer(1) # by default the graph view self.readOnly = pwobj.Boolean(False) self.runSelection = pwobj.CsvList(int) # Store selected runs self.dataSelection = pwobj.CsvList(int) # Store selected runs # Some extra settings stored, now mainly used # from the webtools # Time when the project was created self.creationTime = pwobj.String(dt.datetime.now()) # Number of days that this project is active # if None, the project will not expire # This is used in webtools where a limited time # is allowed for each project self.lifeTime = pwobj.Integer() # Set a disk quota for the project (in Gb) # if None, quota is unlimited self.diskQuota = pwobj.Integer()
[docs] def commit(self): """ Commit changes made. """ self.mapper.commit()
[docs] def getRunsView(self): return self.runsView.get()
[docs] def setRunsView(self, value): self.runsView.set(value)
[docs] def getReadOnly(self): return self.readOnly.get()
[docs] def setReadOnly(self, value): self.readOnly.set(value)
[docs] def getCreationTime(self): return self.creationTime.datetime()
[docs] def setCreationTime(self, value): self.creationTime.set(value)
[docs] def getLifeTime(self): return self.lifeTime.get()
[docs] def setLifeTime(self, value): self.lifeTime.set(value)
[docs] def getProtocolView(self): return self.currentProtocolsView.get()
[docs] def setProtocolView(self, protocolView): """ Set the new protocol Menu given its index. The new ProtocolMenu will be returned. """ self.currentProtocolsView.set(protocolView)
[docs] def getColorMode(self): return self.colorMode.get()
[docs] def setColorMode(self, colorMode): """ Set the color mode to use when drawing the graph. """ # Skip LABELS color mode to avoid double iteration if colorMode == self.COLOR_MODE_LABELS: colorMode+=1 self.colorMode.set(colorMode)
[docs] def statusColorMode(self): return self.getColorMode() == self.COLOR_MODE_STATUS
[docs] def labelsColorMode(self): return self.getColorMode() == self.COLOR_MODE_LABELS
[docs] def ageColorMode(self): return self.getColorMode() == self.COLOR_MODE_AGE
[docs] def sizeColorMode(self): return self.getColorMode() == self.COLOR_MODE_SIZE
[docs] def write(self, dbPath=None): self.setName('ProjectSettings') if dbPath is not None: self.mapper = SqliteMapper(dbPath, globals()) else: if self.mapper is None: raise Exception("Can't write ProjectSettings without " "mapper or dbPath") self.mapper.deleteAll() self.mapper.insert(self) self.mapper.commit()
[docs] def getNodes(self): return self.nodeList
[docs] def cleanUpNodes(self, runsIds, toRemove=True): """ This will clean up all the nodes that do not have a matching run. This is because until now, the nodes here weren't removes when protocols were removed. :param runsIds: iterable with protocol's objId to be removed. :param toRemove: Passed is are to be removed. Otherwise, are the ones to keep """ try: logger.info("Cleaning up unused graphical nodes.") nodesToDelete = [] for node in self.getNodes(): nodeId = str(node.getId()) # if it is not the root node if nodeId != '0': if (nodeId in runsIds) == toRemove: nodesToDelete.append(node.getId()) logger.info("Following graphical nodes %s unmatched. Deleting them" % nodesToDelete) for key in nodesToDelete: self.getNodes().removeNode(key) except Exception as e: logger.error("Couldn't clean up graphical nodes.", exc_info=e)
[docs] def getNodeById(self, nodeId): return self.nodeList.getNode(nodeId)
[docs] def addNode(self, nodeId, **kwargs): return self.nodeList.addNode(nodeId, **kwargs)
[docs] def removeNode(self, nodeId): """ Removes a graphical node based on its id""" self.nodeList.removeNode(nodeId)
[docs] def getLabels(self): return self.labelsList
[docs] @classmethod def load(cls, dbPath): """ Load a ProjectSettings from dbPath. """ classDict = dict(globals()) classDict.update(pwobj.__dict__) mapper = SqliteMapper(dbPath, classDict) settingList = mapper.selectByClass('ProjectSettings') n = len(settingList) if n == 0: raise Exception("Can't load ProjectSettings from %s" % dbPath) elif n > 1: raise Exception("Only one ProjectSettings is expected in db, " "found %d in %s" % (n, dbPath)) settings = settingList[0] settings.mapper = mapper return settings
[docs]class NodeConfig(pwobj.Scalar): """ Store Graph node information such as x, y. """ def __init__(self, nodeId=0, x=None, y=None, selected=False, expanded=True, visible=True): pwobj.Scalar.__init__(self) # Special node id 0 for project node self._values = {'id': nodeId, 'x': pwobj.Integer(x).get(0), 'y': pwobj.Integer(y).get(0), 'selected': selected, 'expanded': expanded, 'visible': pwobj.Boolean(visible).get(0), 'labels': []} def _convertValue(self, value): """Value should be a str with comma separated values or a list. """ self._values = json.loads(value)
[docs] def getObjValue(self): self._objValue = json.dumps(self._values) return self._objValue
[docs] def get(self): return self.getObjValue()
[docs] def getId(self): return self._values['id']
[docs] def setX(self, x): self._values['x'] = x
[docs] def getX(self): return self._values['x']
[docs] def setY(self, y): self._values['y'] = y
[docs] def getY(self): return self._values['y']
[docs] def setPosition(self, x, y): self.setX(x) self.setY(y)
[docs] def getPosition(self): return self.getX(), self.getY()
[docs] def setSelected(self, selected): self._values['selected'] = selected
[docs] def isSelected(self): return self._values['selected']
[docs] def setExpanded(self, expanded): self._values['expanded'] = expanded
[docs] def isExpanded(self): return self._values['expanded']
[docs] def setVisible(self, visible): self._values['visible'] = visible
[docs] def isVisible(self): if self._values.get('visible') is None: self._values['visible'] = True return self._values['visible']
[docs] def setLabels(self, labels): self._values['labels'] = labels
[docs] def getLabels(self): return self._values.get('labels', None)
def __str__(self): return 'NodeConfig: %s' % self._values
[docs]class NodeConfigList(pwobj.List): """ Store all nodes information items and also store a dictionary for quick access to nodes query. """ def __init__(self): self._nodesDict = {} pwobj.List.__init__(self)
[docs] def getNode(self, nodeId): return self._nodesDict.get(nodeId, None)
[docs] def addNode(self, nodeId, **kwargs): node = NodeConfig(nodeId, **kwargs) self._nodesDict[node.getId()] = node self.append(node) return node
[docs] def removeNode(self, nodeId): """ Removes a node with the id = nodeId""" nodeToRemove = self._nodesDict[nodeId] self._nodesDict.pop(nodeId) self.remove(nodeToRemove)
[docs] def updateDict(self): self._nodesDict.clear() for node in self: self._nodesDict[node.getId()] = node
[docs] def clear(self): pwobj.List.clear(self) self._nodesDict.clear()
[docs]class Label(pwobj.Scalar): """ Store Label information """ EMPTY_OLD_NAME = None def __init__(self, name='', color=None): pwobj.Scalar.__init__(self) # Special node id 0 for project node self._values = {'name': name, 'color': color} self._oldName = self.EMPTY_OLD_NAME def _convertValue(self, value): """Value should be a str with comma separated values or a list. """ self._values = json.loads(value) # Clean unused "id" field if "id" in self._values: self._values.pop("id")
[docs] def getObjValue(self): self._objValue = json.dumps(self._values) return self._objValue
[docs] def get(self): return self.getObjValue()
[docs] def getName(self)->str: return self._values['name']
[docs] def setName(self, newName): # For recurrent edit, # we keep the old name only the first time if not self.hasOldName(): self._oldName = self._values['name'] self._values['name'] = newName
[docs] def hasOldName(self)->bool: return self._oldName != self.EMPTY_OLD_NAME
[docs] def clearOldName(self): self._oldName = self.EMPTY_OLD_NAME
[docs] def getOldName(self)->str: return self._oldName
[docs] def setColor(self, color): self._values['color'] = color
[docs] def getColor(self)->str: return self._values.get('color', None)
def __str__(self): return 'Label: %s' % self._values def __eq__(self, other): return self.getName() == other.getName()
[docs]class LabelsList(pwobj.List): """ Store all labels information""" def __init__(self): self._labelsDict = {} pwobj.List.__init__(self)
[docs] def getLabel(self, name): return self._labelsDict.get(name, None)
[docs] def addLabel(self, label): self._labelsDict[label.getName()] = label self.append(label) return label
[docs] def updateDict(self): self._labelsDict.clear() for label in self: self._labelsDict[label.getName()] = label
[docs] def deleteLabel(self, label): self._labelsDict.pop(label.getName()) self.remove(label)
[docs] def clear(self): pwobj.List.clear(self) self._labelDict.clear()