Source code for ccpn.core.Data

"""
"""
#=========================================================================================
# Licence, Reference and Credits
#=========================================================================================
__copyright__ = "Copyright (C) CCPN project (http://www.ccpn.ac.uk) 2014 - 2021"
__credits__ = ("Ed Brooksbank, Joanna Fox, Victoria A Higman, Luca Mureddu, Eliza Płoskoń",
               "Timothy J Ragan, Brian O Smith, Gary S Thompson & Geerten W Vuister")
__licence__ = ("CCPN licence. See http://www.ccpn.ac.uk/v3-software/downloads/license")
__reference__ = ("Skinner, S.P., Fogh, R.H., Boucher, W., Ragan, T.J., Mureddu, L.G., & Vuister, G.W.",
                 "CcpNmr AnalysisAssign: a flexible platform for integrated NMR analysis",
                 "J.Biomol.Nmr (2016), 66, 111-124, http://doi.org/10.1007/s10858-016-0060-y")
#=========================================================================================
# Last code modification
#=========================================================================================
__modifiedBy__ = "$modifiedBy: Ed Brooksbank $"
__dateModified__ = "$dateModified: 2021-12-23 17:37:46 +0000 (Thu, December 23, 2021) $"
__version__ = "$Revision: 3.0.4 $"
#=========================================================================================
# Created
#=========================================================================================
__author__ = "$Author: CCPN $"
__date__ = "$Date: 2017-04-07 10:28:41 +0000 (Fri, April 07, 2017) $"
#=========================================================================================
# Start of code
#=========================================================================================

from typing import Optional

from ccpnmodel.ccpncore.lib import Util as coreUtil
from ccpn.core.lib import Pid
from ccpnmodel.ccpncore.api.ccp.nmr.NmrConstraint import Data as ApiData
from ccpnmodel.ccpncore.api.ccp.nmr.NmrConstraint import Parameter as ApiParameter
from ccpn.core._implementation.AbstractWrapperObject import AbstractWrapperObject
from ccpn.core.Project import Project
from ccpn.core.StructureData import StructureData
from ccpn.util.decorators import logCommand
from ccpn.core.lib.ContextManagers import newObject, renameObject


[docs]class Data(AbstractWrapperObject): """Object storing links to the data structures (PeakLists, Spectra, StructureEnsembles etc.) connected to a given StructureData, and their associated calculation parameters.""" #: Short class name, for PID. shortClassName = 'DA' # Attribute it necessary as subclasses must use superclass className className = 'Data' _parentClass = StructureData #: Name of plural link to instances of class _pluralLinkName = 'data' #: List of child classes. _childClasses = [] # Qualified name of matching API class _apiClassQualifiedName = ApiData._metaclass.qualifiedName() # CCPN properties @property def _apiData(self) -> ApiData: """ CCPN Data object matching Data""" return self._wrappedData
[docs] def print(self): pass
@property def _key(self) -> str: """id string - name""" # return self._wrappedData.name return self._wrappedData.name.translate(Pid.remapSeparators) @property def name(self) -> str: """name of Data object, used in Pid and to identify the Data object. """ return self._wrappedData.name @name.setter def name(self, value: str): """set name of Data object.""" self.rename(value) @property def _parent(self) -> StructureData: """StructureData containing Data.""" return self._project._data2Obj[self._wrappedData.nmrConstraintStore] calculationStep = _parent @property def attachedObjectPid(self) -> Optional[str]: """Pid for attached object - used to calculate the attachedObject Remains unchanged also if the object pointed to is renamed or deleted, to preserve, as far as possible, the original data.""" return self._wrappedData.attachedObjectPid @attachedObjectPid.setter def attachedObjectPid(self, value: str): self._wrappedData.attachedObjectPid = value @property def attachedObject(self) -> Optional[AbstractWrapperObject]: """attached object - derived from self.attachedObjectPid. If no attached object matching attachedObjectPid can be found (object has been renamed, deleted, or the attachedObjectPid is incorrect) this attribute has the value None.""" ss = self._wrappedData.attachedObjectPid if ss: return self.getByPid(ss) else: return None @attachedObject.setter def attachedObject(self, value: str): if value: self._wrappedData.attachedObjectPid = value.pid else: self._wrappedData.attachedObjectPid = None @property def dataParameters(self) -> dict: """Keyword-value dictionary of parameters. NB the value is a copy - modifying it will not modify the actual data. Use the setDataParameter, deleteDataParameter, clearDataParameters, and updateDataParameters methods to modify the parameters. Dictionary values can be anything that can be exported to JSON, including OrderedDict, numpy.ndarray, ccpn.util.Tensor, or pandas DataFrame, Series, or Panel""" return dict((x.name, x.value) for x in self._wrappedData.parameters)
[docs] def setDataParameter(self, name: str, value): """Add name:value to parameters, overwriting existing entries""" apiData = self._wrappedData parameter = apiData.findFirstParameter(name=name) if parameter is None: apiData.newParameter(name=name, value=value) else: parameter.value = value
[docs] def deleteDataParameter(self, name: str): """Delete parameter named 'name'""" apiData = self._wrappedData parameter = apiData.findFirstParameter(name=name) if parameter is None: raise KeyError("No parameter named %s" % name) else: parameter.delete()
[docs] def clearDataParameters(self): """Delete all parameters""" for parameter in self._wrappedData.parameters: parameter.delete()
[docs] def updateDataParameters(self, value: dict): """Convenience routine, similar to dict.update(). Calls self.setDataParameter(key, value) for each key,value pair in the input.""" for key, val in value.items(): self.setDataParameter(key, val)
#========================================================================================= # Implementation functions #========================================================================================= @classmethod def _getAllWrappedData(cls, parent: StructureData) -> list: """get wrappedData - all Data children of parent NmrConstraintStore""" return parent._wrappedData.sortedData()
[docs] @renameObject() @logCommand(get='self') def rename(self, value: str): """Rename Data, changing its name and Pid. """ name = self._uniqueName(project=self.project, name=value) # rename functions from here oldName = self.name self._oldPid = self.pid # GWV: unsure why this is different from rename() implementations of many other classes? coreUtil._resetParentLink(self._wrappedData, 'data', {'name': name}) return (oldName,)
#========================================================================================= # CCPN functions #========================================================================================= #=========================================================================================== # new'Object' and other methods # Call appropriate routines in their respective locations #=========================================================================================== #========================================================================================= # Connections to parents: #========================================================================================= @newObject(Data) def _newData(self: StructureData, name: str, attachedObjectPid: str = None, attachedObject: AbstractWrapperObject = None) -> Data: """Create new Data within StructureData. See the Data class for details. :param name: :param attachedObjectPid: :param attachedObject: :return: a new Data instance. """ project = self.project if attachedObject is not None: if attachedObjectPid is None: attachedObjectPid = attachedObject.pid else: raise ValueError( "Either attachedObject or attachedObjectPid must be None - values were %s and %s" % (attachedObject, attachedObjectPid)) apiData = self._wrappedData.newData(name=name, attachedObjectPid=attachedObjectPid) result = project._data2Obj.get(apiData) if result is None: raise RuntimeError('Unable to generate new Data item') return result # Notifiers: # Data change whenever a parameter is created, deleted, or changed Project._apiNotifiers.extend( ( ('_notifyRelatedApiObject', {'pathToObject': 'data', 'action': 'change'}, ApiParameter._metaclass.qualifiedName(), ''), ('_notifyRelatedApiObject', {'pathToObject': 'data', 'action': 'change'}, ApiParameter._metaclass.qualifiedName(), '__init__'), ('_notifyRelatedApiObject', {'pathToObject': 'data', 'action': 'change'}, ApiParameter._metaclass.qualifiedName(), 'delete'), ) )