Source code for admit.ProjectManager
"""**Manager** --- Multiflow project manager.
------------------------------------------
This module defines the ProjectManager class.
"""
import os
import admit
from admit.Admit import Admit as Project
# ==============================================================================
[docs]class ProjectManager():
"""
Manages parent projects feeding a multiflow project.
Parameters
----------
baseDirs: list of str
Starting parent project directories.
Attributes
----------
_projects: dict of ADMITs
Parent project dictionary, keyed by project ID (a positive integer).
_baseDirs: dict of project base directories
Project directory dictionary, keyed by project ID (a positive integer).
Notes
-----
Managed projects are numbered sequentially beginning with one.
A project ID of zero is reserved for the parent project containing this
instance. Individual projects can be accessed by indexing the manager
object using the corresponding project ID number.
"""
def __init__(self, baseDirs=[]):
"""
Constructor.
"""
self._projects = {}
self._baseDirs = {}
for d in baseDirs: self.addProject(d)
def __len__(self):
"""
Number of projects under control of ProjectManager.
Returns
-------
int
Number of contained projects.
"""
return len(self._projects)
def __contains__(self, pid):
"""
Project membership operator.
Parameters
----------
pid : int
Project ID number.
Returns
-------
bool
Membership result.
"""
return self._projects.__contains__(pid)
def __iter__(self):
"""
Project iterator.
Returns
-------
iterator
Project iterator.
"""
return iter(self._projects)
def __getitem__(self, pid):
"""
Obtains project reference.
Parameters
----------
pid : int
Project ID number.
Returns
-------
ADMIT object
ADMIT project reference.
"""
return self._projects[pid]
def __setitem__(self, pid, project):
"""
Sets new project.
Parameters
----------
pid : int
Project ID number.
project : ADMIT project
Project reference.
Returns
-------
None
"""
# Check if pid exists...
for at in project.fm: at.setProject(pid)
self._projects[pid] = project
[docs] def addProject(self, baseDir):
"""
Adds a project.
The project must be completely up to date to be accepted.
Parameters
----------
baseDir : str
ADMIT project base directory.
Returns
-------
int
Project ID number, else -1 if the project was rejected
(not up-to-date).
Notes
-----
The up-to-date requirement is a safety feature. Managed projects are
assumed to be quasi-static since tasks linked from it must provide
valid BDP output at the root of the associated multiflow.
"""
# Ignore attempts to re-add same project.
# This will commonly occur when re-running a multiflow script.
for pid in self._baseDirs:
if baseDir == self._baseDirs[pid]: return pid
#project = admit.Project(baseDir)
project = Project(baseDir)
stale = project.fm.find(lambda at: at.isstale() == True)
if not stale:
pid = 1+len(self._projects)
project.project_id = pid
self._projects[pid] = project
self._baseDirs[pid] = baseDir
# Embed project ID in tasks to indicate project ownership.
for tid in project.fm: project.fm[tid].setProject(pid)
else:
print "PM.addProject(): Project", baseDir, \
"out of date; not added."
pid = -1
return pid
[docs] def removeProject(self, pid):
"""
Removes a project.
The project should not have any tasks still linked in the multiflow.
Verifying this is the responsibility of the caller (multiflow project).
Parameters
----------
pid : int
Project ID number.
Returns
-------
bool
True if the project was removed successfully, else False.
Notes
-----
This is a low-level interface not normally called by users.
"""
if pid in self:
self[pid].write() # Commit any unsaved changes.
self._projects.pop(pid)
return True
else:
print "PM.removeProject: Unknown project ID", pid
return False
[docs] def write(self):
"""
Writes project XML files.
Project IDs are temporarily reset to zero to avoid polluting
the parent project XML files.
Parameters
----------
None
Returns
-------
None
Notes
-----
Parent projects should be rewritten when a multiflow is run in case
linked tasks were updated.
"""
for pid in self:
project = self[pid]
project.project_id = 0
for tid in project.fm: project.fm[tid].setProject(0)
project.write()
project.project_id = pid
for tid in project.fm: project.fm[tid].setProject(pid)
[docs] def getProjectId(self, baseDir):
"""
Retrieves project ID number given the base directory.
Parameters
----------
baseDir: str
Project base directory.
Returns
-------
int
Project ID number, else -1 if project not found.
"""
for pid in self:
if self._baseDirs[pid] == baseDir: return pid
return -1
[docs] def getProjectDir(self, pid):
"""
Retrieves project base directory given its ID number.
Parameters
----------
pid: int
Project ID number.
Returns
-------
str
Project base directory, else None if project not found.
"""
if pid in self:
return self._baseDirs[pid]
else:
return None
[docs] def findTask(self, pid, isMatch):
"""
Finds AT(s) by arbitrary matching criterion.
Parameters
----------
pid: int
ADMIT project ID number.
isMatch: bool functor(AT)
Match function (returns True/False given an AT argument).
Returns
-------
list of ATs
ADMIT task reference(s) matching the criterion; may be empty.
"""
return self[pid].fm.find(isMatch)
[docs] def findTaskAlias(self, pid, alias):
"""
Finds AT(s) by alias.
Parameters
----------
pid: int
ADMIT project ID number.
alias: str
Matching task alias.
Returns
-------
list of ATs
ADMIT task reference(s) matching the alias; may be empty.
"""
return self.findTask(pid, lambda at: at._alias == alias)
[docs] def script(self, py, baseDir, proj = 'p'):
"""
Generates a Python script recreating the current project manager.
Parameters
----------
py : file
Open, writable Python file object.
baseDir : str
Master project base directory (ending in '/').
proj : str, optional
Project variable name; defaults to 'p'.
Returns
-------
None
Notes
-----
This is a low-level method normally called only by Admit.script().
"""
if len(self) == 0: return
baseDir = os.path.dirname(baseDir[:-1])
py.write("\n# Managed projects.\n"
"pm = %s.getManager()\n" % proj)
pids = self._baseDirs.keys()
pids.sort()
for pid in pids:
pdir = self[pid].dir()[:-1]
ht = os.path.split(pdir)
if ht[0] == baseDir: pdir = ht[1]
py.write("pm.addProject('%s')\n" % pdir)