Source code for admit.bdp.BDP

"""
   .. _BDP-base-api:

   **BDP** --- Basic data product base.
   ------------------------------------

   This module defines the Basic Data Product (BDP) base class.
"""

import os
import xml.etree.cElementTree as et
import types
import admit.util.utils as utils
import admit.util.bdp_types as bt
from admit.util.Image import Image
from admit.util.MultiImage import MultiImage
from admit.util.Line import Line
from admit.util.Table import Table
from admit.xmlio.DtdReader import DtdReader
##import zipfile
#import admit.util.util as util
import admit.xmlio.XmlWriter as XmlWriter

_debug = False
#_debug = True

[docs]class BDP(object): """Basic Data Product base. Basic Data Products (BDPs) are data containers used to transport information within ADMIT, as well as deliver it to users in a persistent, well-defined format. Parameters ---------- xmlFile : str, optional XML file associated with BDP (for persistence); defaults to ``None``. keyval : dict Dictionary of keyword value pairs. Attributes ---------- gous : TBD TBD mous : TBD TBD sous : TBD TBD (the official name is sous) project : TBD TBD xmlFile : str XML file associated with BDP (for persistence). _baseDir : str ADMIT project directory (None if unknown). _date : TBD Date of last edit. _taskid : int Originating ADMIT task ID number. _type : admit.util.bdp_types Concrete BDP type. _updated : bool Whether BDP has been modified since latest XML output. """ _uid = 0 """Class static BDP ID number.""" def __init__(self, xmlFile=None, **keyval): # just some default values self.project = "" self.sous = "" self.mous = "" self.gous = "" self._date = "" # date of last edit self._type = self.__class__.__name__ self.xmlFile = xmlFile # xml file associated with BDP self._baseDir = "" self._updated = False # has been updated self._taskid = -1 self._version = "0.0.0" self._uid = BDP._uid BDP._uid = BDP._uid + 1 if self.xmlFile is None: self.xmlFile = self._type + "_" + str(self._uid) self.setkey(keyval) def __str__(self): print bt.format.BOLD + bt.color.GREEN + "\nBDP :" + bt.format.END + \ bt.format.BOLD + self._type + bt.format.END for i, j in self.__dict__.iteritems(): if isinstance(j, (Line, Image, MultiImage, Table)): print bt.format.BOLD + i + ": " print j continue print bt.format.BOLD + i + ": " + bt.format.END + str(j) return "\n"
[docs] def getfiles(self): """ Return the filename(s) associated with the basic data in a BDP. Parameters ---------- None Returns ------- List of files Notes ----- .. todo:: Really should look for attribute .filename, but normally derived classes should implement these; see e.g. File_AT. """ files = [] for i in self.__dict__: if isinstance(getattr(self, i), Image): #print getattr(self, i).images for key in getattr(self, i).images: files.append(getattr(self, i).images[key]) #files.append(getattr(self, i).fileName) return files
[docs] def show(self): """ Show the xmlFile name. Parameters ---------- None Returns ------- the xml file name Notes ----- .. todo:: Extend functionality to show more. """ return self.xmlFile
[docs] def baseDir(self, path=None): """ Get/set project base directory. Parameters ---------- path : str, optional New project base directory (ignored if None). Returns ------- Updated project base directory. Notes ----- Unless empty, the base directory is guaranteed to end in os.sep. """ if path is not None: if path and path[-1] != os.sep: path += os.sep self._baseDir = path return self._baseDir
[docs] def update(self, new_state): """ Updates BDP state. Parameters ---------- new_state : varies New BDP state. Returns ------- None """ if _debug: print "UPDATE: %s" % self.xmlFile self._updated = new_state
[docs] def report(self): """ Report BDP properties in human readable format. Parameters ---------- None Returns ------- None """ print "===report===" print "BDP::%s" % self.xmlFile
[docs] def setkey(self, name="", key={}): """ Sets keyword value(s). Two styles are possible: 1. name = {key:val} e.g. **setkey({"a":1})** 2. name = "key", key = val e.g. **setkey("a", 1)** Parameters ---------- name : dict or str, optional Keyword/values pairs, or single keyword name; defaults to empty string. key : str, optional Keyword value; defaults to empty dictionary. init : bool, optional Whether keyword is being set for the first time. """ if isinstance(name, dict): #1 # check that the keys are valid first for i in name: if not self.haskey(i): raise Exception("%s is not a valid key for %s." % (i, self._type)) if type(getattr(self, i, None)) != type(name[i]): if isinstance(name[i], Image) and isinstance(getattr(self, i, None), MultiImage): continue raise Exception("You cannot change the data type of an BDP keyword. Type for %s is %s but needs to be %s" % (i, str(type(name[i])), str(type(getattr(self, i, None))))) for i in name: if isinstance(name[i], Image) and isinstance(getattr(self, i, None), MultiImage): t = getattr(self, i, None) t.addimage(name[i]) self.setkey(i, t) return setattr(self, i, name[i]) elif not name == "": #2 # check that the key is valid if not self.haskey(name): raise Exception("%s is not a valid key for %s." % (name, self._type)) if type(getattr(self, name, None)) != type(key): if isinstance(key, Image) and isinstance(getattr(self, name, None), MultiImage): t = getattr(self, name, None) t.addimage(key) self.setkey(name, t) return else: raise Exception("You cannot change the data type of an BDP keyword. Type for %s is %s but needs to be %s" % (name, str(type(key)), str(type(getattr(self, name, None))))) setattr(self, name, key) else: # @todo need to give more feedback to user raise Exception("Invalid keys given to setkey")
[docs] def haskey(self, key): """ Query if a key exists for an BDP. Parameters ---------- key : str Keyword name. Returns ------- True if keyword is present, else False. """ if getattr(self, key, None) is None: return False return True
[docs] def get(self, key): """ Access an attribute. Parameters ---------- key : str Keyword name. Returns ------- varies Attribute value if keyword is present, else ``None``. """ if _debug: print "BDP::get %s" % (key) return getattr(self, key, None)
[docs] def write(self, xmlFile=None): """ Writes the BDP to an XML file. Parameters ---------- xmlFile : str, optional Output XML file name; defaults to eponymous internal attribute. Notes ----- Do not edit unless you know what you are doing as all BDP's rely on this method to work properly. Normally the xmlFile here should be the full path. """ dtdRead = DtdReader(self._type + ".dtd") order = dtdRead.getOrder() dtd = dtdRead.getDtd() typs = dtdRead.getTypes() if xmlFile is None: raise Exception("No output files was specified") root = et.Element("BDP") root.set("type", self._type) XmlWriter.XmlWriter(self, order, typs, root) #Return a pretty-printed XML string for the Element. rough_string = et.tostring(root, 'utf-8') temp = rough_string.replace(">", ">\n") temp = temp.replace("</", "\n</") outFile = open(xmlFile + ".bdp", 'w') outFile.write("<?xml version=\"1.0\" ?>\n") # write out the dtd info at the top outFile.write("<!DOCTYPE BDP [\n\n") for line in dtd: outFile.write(line) outFile.write("]>\n\n") outFile.write(temp) outFile.close()
#zFile = zipfile.ZipFile(self.xmlFile + ".zip", 'w', compression=zipfile.ZIP_DEFLATED) #zFile.write(self.xmlFile) #zFile.close()
[docs] def delete(self, delfiles=True): """ Method to delete the BDP. This method will search through all class variables and delete any images since they contain external files, and then deletes the BDP's XML file. Parameters ---------- basedir : str, optional XML file directory; defaults to current directory. delfiles : bool, optional Whether or not to delete the actual files on disk; defaults to True. Notes ----- It is recommended that any BDP that stores images inside of lists, dictionaries, tuples, etc. override this method with a customized version. """ for i in self.__dict__: if isinstance(getattr(self, i), MultiImage): getattr(self, i).delete(self._baseDir, delfiles) del i if delfiles: utils.remove(self._baseDir + os.sep + self.xmlFile + ".bdp")
[docs] def getdir(self): """ Method to get the subdirectory(s) of the current BDP relative to the ADMIT working directory. Parameters ---------- None Returns ------- String containing the current BDPs subdirectory """ # @todo fails if the BDP is in the main admit directory and returns [:-1] loc = self.xmlFile.rfind("/") return self.xmlFile[:loc]
[docs] def isequal(self, bdp): """ Tests for equality with another BDP. Parameters ---------- bdp : BDP The other BDP. Returns ------- True if the BDP types and contents match, else False. """ try: if bdp.get("_type") != self._type: print "BDP types are not the same: " + bdp.get("_type") + " vs " +self._type return False for i in self.__dict__: if isinstance(i, (types.TypeType, types.ClassType)): if not(isinstance(i, Image) or isinstance(i, Line) or isinstance(i.Table)): continue if not getattr(self, i).isequal(getattr(bdp, i)): print "Attribute %s does not match" % (i) return False elif cmp(getattr(self, i), getattr(bdp, i)) != 0: print "Attribute %s does not match" % (i) return False except: return False return True