#=========================================================================================
# Licence, Reference and Credits
#=========================================================================================
__copyright__ = "Copyright (C) CCPN project (https://www.ccpn.ac.uk) 2014 - 2022"
__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: Geerten Vuister $"
__dateModified__ = "$dateModified: 2022-03-01 18:02:13 +0000 (Tue, March 01, 2022) $"
__version__ = "$Revision: 3.1.0 $"
#=========================================================================================
# Created
#=========================================================================================
__author__ = "$Author: geertenv $"
__date__ = "$Date: 2018-05-14 10:28:41 +0000 (Fri, April 07, 2017) $"
#=========================================================================================
# Start of code
#=========================================================================================
import sys
import os
from traitlets import HasTraits, Undefined
[docs]class TraitBase(HasTraits):
"""Class to give HasTraits dict-like methods keys, values, update, items and iteration
"""
keysInOrder = True # If True, return key in order defined by _traitOrder attribute
# of the keys
[docs] def getTraitValue(self, trait):
"""convenience (to complement setTraitValue): return value of trait
"""
if not self.hasTrait(trait):
raise ValueError('Trait "%s" does not exist for object %s' % (trait, self))
return self._trait_values[trait]
[docs] def setTraitValue(self, trait, value, force=False):
"""Convenience: set value of trait, optionally overwriting immutable ones
"""
if not self.hasTrait(trait):
raise ValueError('Trait "%s" does not exist for object %s' % (trait, self))
if self.isMutableTrait(trait) or force:
self.set_trait(trait, value)
else:
raise ValueError('Trait "%s" is immutable' % trait)
[docs] def getTraitDefaultValue(self, trait):
"""convenience: return default value of trait
"""
if not self.hasTrait(trait):
raise ValueError('Trait "%s" does not exist for object %s' % (trait, self))
return self.getTraitObject(trait).default_value
[docs] def setTraitDefaultValue(self, trait):
"""convenience: set trait to default value
"""
if not self.hasTrait(trait):
raise ValueError('Trait "%s" does not exist for object %s' % (trait, self))
defaultValue = self.getTraitObject(trait).default_value
if defaultValue == Undefined:
raise RuntimeError('Trait "%s" of object %s does not have a default value defined' % (trait, self))
self.setTraitValue(trait, defaultValue, force=True)
[docs] def hasTrait(self, trait):
"""Convenience, Return True if self has trait
"""
return self.has_trait(trait)
[docs] def getTrait(self, trait):
"""Return the trait object corresponding to trait, or None if does not exists
"""
return self.class_traits().get(trait)
[docs] def getItemTrait(self, trait):
"""Return the trait object corresponding to trait for items of an iterable, i.e. used for validate_items
or None if does not exists
"""
theTrait = self.getTrait(trait)
if theTrait is None: return None
return theTrait._trait
[docs] def getAllTraitObjects(self, objectOnly=False, **metadata) -> dict :
"""Return a dict of (traitName, trait object) key,value pairs, optionally filtering
for metadata.
If objectOnly is True, only traits defined for this object are included;
if False, also include any inherited traits.
"""
if objectOnly:
return self.class_own_traits(**metadata)
else:
return self.class_traits(**metadata)
[docs] def getTraitObject(self, trait):
"""get the trait object or None if trait does not exist
"""
traits = self.traits()
return traits.get(trait)
[docs] def isMutableTrait(self, trait):
"Return True is trait is mutable"
if not self.hasTrait(trait):
raise ValueError('Trait "%s" does not exist for object %s' % (trait,self))
traitObj = self.getTraitObject(trait)
return not traitObj.read_only
[docs] def keys(self, **metadata):
"""get keys (object only), optionally filtering for metadata
"""
if self.keysInOrder:
items = [(val._traitOrder, key) for key,val in self.class_traits(**metadata).items()]
items.sort()
keys = [key for val,key in items]
else:
keys = [key for key in self.class_traits(**metadata).keys()]
keys.sort()
return keys
# the ones below are derived from keys() method
[docs] def values(self, **metadata):
"""get values, optionally filtering for metadata"""
return [getattr(self, key) for key in self.keys(**metadata)]
[docs] def update(self, other, **metadata):
"""update self with values from other (dict-like), optionally filtering for metadata"""
for key in self.keys(**metadata):
if key in other:
setattr(self, key, other[key])
[docs] def items(self, **metadata):
"""iterable over key, value pairs, optionally filtering for metadata"""
for key in self.keys(**metadata):
value = getattr(self, key)
yield (key, value)
def __iter__(self, **metadata):
"""iterable over key, optionally filtering for metadata"""
for key in self.keys(**metadata):
yield (key)
def __getitem__(self, key):
"""Implement dict-like item assignment"""
if key not in self.keys():
raise KeyError("""trait "%s" does not exist; cannot get value""" % key)
return getattr(self, key)
def __setitem__(self, key, value):
"""Implement dict-like item assignment"""
if key not in self.keys():
raise KeyError("""trait "%s" does not exist; cannot set value""" % key)
setattr(self, key, value)
[docs] def asDict(self, **metadata):
"""return trait, value pairs as dict, optionally filtering for metadata"""
return dict(self.items(**metadata))
def __str__(self):
return '<%s>' % (self.__class__.__name__,)
def __repr__(self):
return '<%s: at %x>' % (self.__class__.__name__, id(self))
[docs] def print(self, printInfo=False):
"""Print all traits"""
print('-------', self, '-------')
for trait, value in self.items():
info = self.getMetadata(trait, key='info', default='')
if len(info) > 0 and printInfo:
print('%-20s : %-40s (%s)' % (trait, value, info))
else:
print('%-20s : %s' % (trait, value))
# --------------------------------------------------------------------------------------------
[docs] def getInfo(self, noDoc=False, noTraits=False, noValues=False, maxLen=50, **traits):
"""Extract information from:
- Class docstring
- .metadata['info'] (if metadata is present)
- all traits tagged with 'info'
Modify what is included using the noDoc, noTraits or **traits. For the latter, setting
a trait True or False will switch its inclusion in the output.
Example: print(a.info(noDoc=True, noTraits=True, maxLen=50, mydict=True))
==> does not print the doc-string, does not print any traits (noTraits=True) except
trait 'mydict' (mydict=True). The output of the trait values is limited to 50
characters.
return string, optionally limited to maxLen if maxLen is not None
"""
s = 'str: %s\n' % self
# doc string
if self.__class__.__doc__ is not None and len(self.__class__.__doc__) > 0 and not noDoc:
doc = self.__class__.__doc__.rstrip()
s += 'doc: %s\n' % doc
# info if present in metadata attribute
if hasattr(self, 'metadata') and 'info' in self.metadata and self.metadata['info'] is not None:
s += 'info: %s\n' % self.metadata['info']
# find all traits that have info metadata
iTraits = self.traits(info=lambda i: i is not None and len(i) > 0)
if len(iTraits) > 0:
for traitName, trait in iTraits.items():
# the selector for displaying traits
doTrait = traits.setdefault(traitName, not noTraits)
if doTrait:
s += 'trait: %-20s %-20r' % (traitName +',',
trait.metadata['info']
)
if not noValues:
value = str(self._trait_values[traitName])
m2 = int(maxLen / 2)
# Not sure why this does not work:
# value = value[0,m2] + ' ... ' + value[-m2:] if len(value) > maxLen else value
value = value[slice(0, m2)] + ' ... ' + value[slice(-m2, len(value))] \
if len(value) > maxLen else value
s += ', value = %s' % value
s += '\n'
# strip last \n and return value
#s = s[:-1] if s[-1] == '\n' else s
return s.rstrip('\n ')
# --------------------------------------------------------------------------------------------
# end class