Python utility functions for I/O

Python utility functions in memops.general.Io that help you do various tasks like create a project and load, save and backup a project. (2008)

Contents:

Create New Project

def newProject(projectName, path = None, removeExisting = False, showYesNo = None):

Create a new project (MemopsRoot) with specified projectName and located in specified path (directory).  The default API project constructor uses the current working directory as the path, so this function is useful if you want to stick it somewhere else.

The path can be absolute or relative.  If path is not specified then it is the current working directory.

In terms of repositories, this changes the path of the (default) 'userData' repository to path, and it also changes the backup repository path to what it would have been if the API project constructor had been invoked with the path directory as the current working directory (so, path + '_backup').

The removeExisting and showYesNo arguments are there in case the proposed userData or backup repository paths already exist. If removeExisting is True then they are removed (silently).  If removeExisting is False and if showYesNo is not specified and either of these paths exist then an IOError is thrown.  If showYesNo is specified then the user is asked if the path(s) should be removed.

Save Project

def saveProject(project, newPath = None, newProjectName = None,  changeBackup = True, createFallback = False, removeExisting = False, showYesNo = None):

Save a project to a specified newPath (directory).  If you just want to save the project without changing the directory you can just do project.saveModified(), although the function here also lets you create a "fallback" copy of the modified files.

The newPath can be absolute or relative.  If newPath is not specified then the current path (called oldPath below) is used.

In terms of repositories, if oldPath != newPath then 'userData' repository path is set to newPath.  If changeBackup is True then the 'backup' repository path is also changed (to newPath + '_backup').

If newProjectName is specified then the project name is set to that (not using the API, since the name is frozen).  Otherwise newProjectName is set to project.name (called oldProjectName below).  (Below we also call newProjectFile the corresponding XML file for the Implementation package.)

The removeExisting and showYesNo arguments are there in case the proposed paths already exist.

If newPath == oldPath:

If newProjectName != oldProjectName and newProjectFile exists:

If removeExisting is True then newProjectFile is removed (silently).  (It would be overwritten later anyway.)  If removeExisting is False and if showYesNo is not specified then an IOError is thrown.  If showYesNo is specified then the user is asked if newProjectFile should be removed.

Else: # newPath != oldPath

If removeExisting is True then newPath is removed (silently).  If removeExisting is False and if showYesNo is not specified and newPath exists then an IOError is thrown.  If showYesNo is specified then the user is asked if newPath should be removed.

If createFallback is True then all topObjects (including Project) which have been modified have a copy of the existing data on disk (so before the modifications) made to the same location with a '.bak' appended.

At the end of all the checks and path changing and copying, a project.saveModified() is done.  So this saves all modified topObjects, not just those in the 'userData' repository.

Save Repository

def saveRepository(repository, newPath = None, createFallback = False, removeExisting = False, showYesNo = None):

Save a repository to a specified newPath (directory).  If you want to save the 'userData' repository then use saveProject() instead (and for that repository the function saveProject() is just called, with the default values for newProjectName and changeBackup).  The function here is just meant to save topObjects inside other repositories.

The newPath can be absolute or relative.  If newPath is not specified then the current path (called oldPath below) is used.

The removeExisting and showYesNo arguments are there in case the proposed newPath already exists.  So if newPath != oldPath then if removeExisting is True the newPath is removed (silently).  If removeExisting is False and if showYesNo is not specified then an IOError is thrown.  If showYesNo is specified then the user is asked if newPath should be removed.

If createFallback is True then all modified topObjects with this repository as the first activeRepository have a copy of the existing data on disk (so before the modifications) made to the same location with a '.bak' appended.

At the end of all the checks and path changing and copying, a topObject.save() is done for all topObjects with this repository as the first activeRepository.  In addition, the project paths have changed so also project.save() is done.

Load Project

def loadProject(path, projectName = None, showWarning = None, askFile = None, askDir = None):

Load a project from a specified path.  (This is the repository path, not the project XML path, which is two levels down.)

The path can be absolute or relative.

If projectName is specified then the corresponding project XML file is expected to exist, otherwise an IOError is thrown.

If projectName is not specified then the default project XML file is used if it exists.  Otherwise all possible project XML files are considered (so whatever is in the appropriate directory and ends in '.xml').  If there are no such files than an IOError is thrown.  Otherwise if there is one such file then that is used.  Otherwise if askFile is specified then the user is asked to specify which file to use.  Otherwise an IOError is thrown.

If none of the project.packageLocator.repositories has path as their path, then the first one's path is set to path.  In this case, if the path for the backup repository (called backupRepository below) starts with the same old path (the normal case) then it is changed to point to the corresponding changed path as well.

The variable projectRepository (referred to below) is set to the repository with this path.  Normally it should be the 'userData' repository.

The path for the 'refData' repository (called refDataRepository below) is changed to getDataDirectory() (joinPath(getTopDirectory(), 'data')) if that is different from what the project file had set.

For any repository that is not in (projectRepository, refDataRepository, backupRepository), if repository.stored is empty then the repository is deleted.  Otherwise, if the repository path does not exist and if askDir is set, then the user is asked where the repository data is.  If the user does not specify, or if askDir is not set, then a warning is given (so no IOError).

Backup Project

def backupProject(project, dataLocationStores = None, skipRefData = True, clearOutDir = False):

Backup a project.  This assumes that a 'backup' repository exists, otherwise it just prints a warning and returns (so no IOError).

If clearOutDir is True then it removes the existing backup path.

If skipRefData is True then the 'refData' repository is not backed up.

For all topObjects (except possibly the 'refData' ones in the case mentioned above), including the project, if the topObject is modified then topObject.backup() is called.  Otherwise if the original file exists on disk and either the corresponding backup file does not exist or it is older than the original file, then the original file is copied to the backup location.

The backup directory for a given repository is joinPath(backupRepository.url.path, repository.name).

For all dataStores in all dataLocationStores specified, a backup is made.  If the original file exists on disk and either the corresponding backup file does not exist or it is older than the original file, then the original file is copied to the backup location.

The backup directory for a given dataLocationStore is

joinPath(backupRepository.url.path, 'data', dataLocationStore.name)