Source code for ccpn.core.lib.ProjectSaveHistory

"""Project-History related  routines

# Licence, Reference and Credits
__copyright__ = "Copyright (C) CCPN project ( 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")
__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,")
# Last code modification
__modifiedBy__ = "$modifiedBy: Ed Brooksbank $"
__dateModified__ = "$dateModified: 2022-03-01 18:06:36 +0000 (Tue, March 01, 2022) $"
__version__ = "$Revision: 3.1.0 $"
# Created
__author__ = "$Author: Geerten Vuister $"
__date__ = "$Date: 2021-11-10 10:28:41 +0000 (Wed, November 10, 2021) $"
# Start of code

import json
import sys
import getpass
from collections import namedtuple

from ccpn.util.Path import aPath
from ccpn.framework.PathsAndUrls import CCPN_STATE_DIRECTORY, ccpnVersionHistory
from ccpn.framework.Version import VersionString, applicationVersion
from ccpn.util.Time import now
from ccpn.util.traits.CcpNmrJson import CcpNmrJson, TraitJsonHandlerBase
from ccpn.util.traits.CcpNmrTraits import List, Path

[docs]def getProjectSaveHistory(projectPath): """Return a ProjectSaveHistory instance from a project path, or None if it doesn't exist """ sv = ProjectSaveHistory(projectPath) if sv.exists(): return sv
[docs]def fetchProjectSaveHistory(projectPath): """Return a ProjectSaveHistory instance from a project path """ sv = ProjectSaveHistory(projectPath) if not sv.exists(): # pre 3.1.0 ccp project; create one with '3.0.4' as the last (and only) entry sv.addSaveRecord('3.0.4', comment='created retroactively') else: sv.restore() return sv
[docs]def newProjectSaveHistory(projectPath): """Create and return a new ProjectSaveHistory instance """ sv = ProjectSaveHistory(projectPath) sv.addSaveRecord(applicationVersion, 'created') return sv
[docs]class ProjectSaveHistory(CcpNmrJson): """A simple class to maintain a project save history as a list, to be saved to and restored from a json file stores (version, datetime, user, platform, comment) tuples """ classVersion = 1.0 # Json classVersion SaveRecord = namedtuple('SaveRecord', 'version datetime user platform comment'.split()) # The path of the file path = Path()
[docs] class RecordListHandler(TraitJsonHandlerBase): """Record-list handling by Json"""
[docs] def decode(self, obj, trait, value): """uses value to generate and set the new (or modified) obj""" newValue = [] for item in value: record = obj._newRecord(*item) newValue.append(record) setattr(obj, trait, newValue)
# the list of entries records = List(default_value=[]).tag(saveToJson=True, jsonHandler=RecordListHandler) def __init__(self, projectPath): """ :param projectPath: path of project """ super().__init__() _path = aPath(projectPath) if not _path.exists(): raise ValueError('Project path "%s" does not exist' % projectPath) self.path = _path.fetchDir(CCPN_STATE_DIRECTORY) / ccpnVersionHistory @property def lastSavedVersion(self) -> VersionString: """Return the program version of which the project was last saved as a VersionString instance """ return VersionString(self.records[-1].version) def _newRecord(self, version, datetime=None, user=None, platform=None, comment=None): """Return a new record, set default for all None values """ if not isinstance(version, (VersionString, str)): raise ValueError('Invalid version parameter "%s"' % version) version = VersionString(version) if datetime is None: datetime = str(now()) if user is None: user = getpass.getuser() if platform is None: platform = sys.platform record = self.SaveRecord( version, datetime, user, platform, comment ) return record
[docs] def addSaveRecord(self, version=None, comment=None): """Add a save record to the history; get version from application if None :return self """ if version is None: version = applicationVersion record = self._newRecord(version=version, comment=comment) self.records.append(record) return self
[docs] def exists(self) -> bool: """Return true if project save history file exists """ return self.path.exists()
[docs] def save(self): """Save to (json) file """ super().save(self.path)
[docs] def restore(self): """Restore self from a json file. Check for prior 'ed'-formatted file :return self """ if not self.exists(): raise RuntimeError('Path "%s" does not exist; unable to restore project save history' % self.path) try: super().restore(self.path) except (RuntimeError, ValueError) as es: # test for old 'ed' files with'r') as fp: records = json.load(fp) self.records = [] if isinstance(records, list) and len(records) > 0 and isinstance(records[0], str): for item in records: self.addSaveRecord(item, 'reconstructed') else: self.addSaveRecord('3.0.4', 'created retroactively') return self
def __getitem__(self, item): return self.records[item] def __len__(self): return len(self.records) def __str__(self): return '<%s: len=%s, lastSavedVersion=%r>' % \ (self.__class__.__name__, len(self), self.lastSavedVersion)
# Register this class ProjectSaveHistory.register()