# **************************************************************************
# *
# * Authors: J.M. De la Rosa Trevin (jmdelarosa@cnb.csic.es)
# *
# * Unidad de Bioinformatica of Centro Nacional de Biotecnologia , CSIC
# *
# * 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, write to the Free Software
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
# * 02111-1307 USA
# *
# * 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 pyworkflow.object as obj
[docs]class Mapper:
"""This class will serves as a Data Mapper pattern.
It will store/retrieve objects from some storage environment.
(like SQL, XML or others)
The mapper should have access to class dictionary
in order to build any give class by name"""
# Just to avoid print several times the same warning
__warnings = set()
ORIGINAL_CLASS_NAME_ATTRIBUTE = "oldClassName"
[docs] @staticmethod
def annotateClassName(instance, oldClassName):
""" Annotate an object with the original class name"""
setattr(instance, Mapper.ORIGINAL_CLASS_NAME_ATTRIBUTE, oldClassName)
[docs] @staticmethod
def getObjectPersistingClassName(instance):
if hasattr(instance, Mapper.ORIGINAL_CLASS_NAME_ATTRIBUTE):
return getattr(instance, Mapper.ORIGINAL_CLASS_NAME_ATTRIBUTE)
else:
return instance.getClassName()
def __init__(self, dictClasses=None):
if dictClasses:
self.dictClasses = dictClasses
else:
self.dictClasses = dir(obj)
[docs] def warning(self, msg):
if msg not in self.__warnings:
print("WARNING: %s" % msg)
self.__warnings.add(msg)
def _buildObjectFromClass(self, className):
""" Build an instance of an object
given the class name, it should be in
the classes' dictionary.
If class is missing, then the default class is used ("LegacyProtocol") and warns about it
"""
if className not in self.dictClasses:
self.warning("Class '%s' not found in mapper dict. Ignored. "
% className)
return None
objClass = self.dictClasses[className]
if not issubclass(objClass, obj.Object):
logger.warning("WARNING: Class '%s' is not a subclass of Object. Ignored. " % className)
return None
try:
instance = self.dictClasses[className]()
except Exception as e:
clazz = self.dictClasses._default
logger.error('Class %s could not be created. Replacing it with %s ' % (className, clazz.__name__), exc_info=e)
instance = clazz()
# If it's the default class in the dictionary
if objClass.__name__ != className:
# ... annotate original class name
self.annotateClassName(instance, className)
return instance
def _getStrValue(self, value):
""" Return empty string if value is None or empty. """
if not value:
return ''
return value
[docs] def commit(self):
"""Commit changes made to the storage"""
pass
[docs] def insert(self, obj):
"""Insert a new object into the system, the id will be set"""
pass
[docs] def update(self, obj, direction='to'):
"""Update an existing object, the id should not be None
direction can be "to" or "from" which indicates the
priority of the update.
If "to" is used, object data is put in storage.
If "from", object data is retrieved from storage"""
if direction == 'to': # Update db with object changes
self.updateTo(obj)
elif direction == 'from': # Update object with db info
self.updateFrom(obj)
else:
raise Exception('Invalid option %s for Sqlite.updateObject' % direction)
[docs] def updateFrom(self, obj):
"""Update object data with storage info"""
pass
[docs] def updateTo(self, obj):
"""Update storage with object info"""
pass
[docs] def store(self, obj):
"""Stores an object, it can be inserted or updated"""
if obj._objId is None:
self.insert(obj)
else:
self.updateTo(obj)
[docs] def selectById(self, objId):
"""Return the object which id is objId"""
pass
[docs] def exists(self, objId):
"""Return True if the id is in the database"""
pass
[docs] def selectAll(self, iterate=False):
"""Return all object from storage"""
pass
[docs] def selectFirst(self):
"""Return only the first element"""
for obj in self.selectAll(iterate=True):
return obj
return None
[docs] def selectBy(self, **args):
"""Select object meetings some criteria"""
pass
[docs] def selectByClass(self, className, includeSubclasses=True):
"""Select all object of a give class.
By default object of subclasses will be retrieved also.
This behaviour can be changed by passing includeSubclass=False"""
return self.selectBy(classname=className)
[docs] def getParent(self, obj):
""" Retrieve the parent object of another. """
pass
[docs] def getFullName(self, obj):
""" Return the full object name such as:
grandparent.parent.objName
"""
nameParts = []
parent = obj
while parent:
nameParts.insert(0, parent.getLastName())
parent = self.getParent(parent)
return '.'.join(nameParts)
[docs] def insertRelation(self, relName, creatorObj, parentObj, childObj):
""" This function will add a new relation between two objects.
Params:
relName: the name of the relation to be added.
creatorObj: this object will be the one who register the relation.
parentObj: this is "parent" in the relation
childObj: this is "child" in the relation
"""
pass
[docs] def getRelationChilds(self, relName, parentObj):
""" Return all "child" objects for a given relation.
Params:
relName: the name of the relation.
parentObj: this is "parent" in the relation
Returns:
a list of "child" objects.
"""
pass
[docs] def getRelationParents(self, relName, childObj):
""" Return all "parent" objects for a given relation.
Params:
relName: the name of the relation.
childObj: this is "child" in the relation
Returns:
a list of "parent" objects.
"""
pass
[docs] def getRelationsByCreator(self, creatorObj):
""" Return all relations created by creatorObj. """
pass
[docs] def deleteRelations(self, creatorObj):
""" Delete all relations created by object creatorObj """
pass