A better resolution to a possible circular dependency.
[htsworkflow.git] / htsworkflow / pipelines / firecrest.py
1 """
2 Extract information about the Firecrest run
3
4 Firecrest
5   class holding the properties we found
6 firecrest
7   Firecrest factory function initalized from a directory name
8 fromxml
9   Firecrest factory function initalized from an xml dump from
10   the Firecrest object.
11 """
12
13 from datetime import date
14 from glob import glob
15 import logging
16 import os
17 import re
18 import time
19
20 from htsworkflow.pipelines import \
21    ElementTree, \
22    VERSION_RE, \
23    EUROPEAN_STRPTIME
24
25 LOGGER = logging.getLogger(__name__)
26
27 __docformat__ = "restructuredtext en"
28
29 class Firecrest(object):
30     XML_VERSION=1
31
32     # xml tag names
33     FIRECREST = 'Firecrest'
34     SOFTWARE_VERSION = 'version'
35     START = 'FirstCycle'
36     STOP = 'LastCycle'
37     DATE = 'run_time'
38     USER = 'user'
39     MATRIX = 'matrix'
40
41     def __init__(self, xml=None):
42         self.start = None
43         self.stop = None
44         self.version = None
45         self.date = date.today()
46         self.user = None
47         self.matrix = None
48
49         if xml is not None:
50             self.set_elements(xml)
51
52     def _get_software(self):
53         return "Firecrest"
54     software = property(_get_software)
55
56     def _get_time(self):
57         return time.mktime(self.date.timetuple())
58     time = property(_get_time, doc='return run time as seconds since epoch')
59
60     def dump(self):
61         print "Starting cycle:", self.start
62         print "Ending cycle:", self.stop
63         print "Firecrest version:", self.version
64         print "Run date:", self.date
65         print "user:", self.user
66
67     def get_elements(self):
68         attribs = {'version': str(Firecrest.XML_VERSION) }
69         root = ElementTree.Element(Firecrest.FIRECREST, attrib=attribs)
70         version = ElementTree.SubElement(root, Firecrest.SOFTWARE_VERSION)
71         version.text = self.version
72         start_cycle = ElementTree.SubElement(root, Firecrest.START)
73         start_cycle.text = str(self.start)
74         stop_cycle = ElementTree.SubElement(root, Firecrest.STOP)
75         stop_cycle.text = str(self.stop)
76         run_date = ElementTree.SubElement(root, Firecrest.DATE)
77         run_date.text = str(self.time)
78         user = ElementTree.SubElement(root, Firecrest.USER)
79         user.text = self.user
80         if self.matrix is not None:
81             matrix = ElementTree.SubElement(root, Firecrest.MATRIX)
82             matrix.text = self.matrix
83         return root
84
85     def set_elements(self, tree):
86         if tree.tag != Firecrest.FIRECREST:
87             raise ValueError('Expected "Firecrest" SubElements')
88         xml_version = int(tree.attrib.get('version', 0))
89         if xml_version > Firecrest.XML_VERSION:
90             LOGGER.warn('Firecrest XML tree is a higher version than this class')
91         for element in list(tree):
92             if element.tag == Firecrest.SOFTWARE_VERSION:
93                 self.version = element.text
94             elif element.tag == Firecrest.START:
95                 self.start = int(element.text)
96             elif element.tag == Firecrest.STOP:
97                 self.stop = int(element.text)
98             elif element.tag == Firecrest.DATE:
99                 self.date = date.fromtimestamp(float(element.text))
100             elif element.tag == Firecrest.USER:
101                 self.user = element.text
102             elif element.tag == Firecrest.MATRIX:
103                 self.matrix = element.text
104             else:
105                 raise ValueError("Unrecognized tag: %s" % (element.tag,))
106
107 def firecrest(pathname):
108     """
109     Examine the directory at pathname and initalize a Firecrest object
110     """
111     f = Firecrest()
112     f.pathname = pathname
113
114     # parse firecrest directory name
115     path, name = os.path.split(pathname)
116     groups = name.split('_')
117     # grab the start/stop cycle information
118     cycle = re.match("C([0-9]+)-([0-9]+)", groups[0])
119     f.start = int(cycle.group(1))
120     f.stop = int(cycle.group(2))
121     # firecrest version
122     version = re.search(VERSION_RE, groups[1])
123     f.version = (version.group(1))
124     # datetime
125     t = time.strptime(groups[2], EUROPEAN_STRPTIME)
126     f.date = date(*t[0:3])
127     # username
128     f.user = groups[3]
129
130     bustard_pattern = os.path.join(pathname, 'Bustard*')
131     # should I parse this deeper than just stashing the
132     # contents of the matrix file?
133     matrix_pathname = os.path.join(pathname, 'Matrix', 's_matrix.txt')
134     if os.path.exists(matrix_pathname):
135         # this is for firecrest < 1.3.2
136         f.matrix = open(matrix_pathname, 'r').read()
137     elif glob(bustard_pattern) > 0:
138         f.matrix = None
139         # there are runs here. Bustard should save the matrix.
140     else:
141         return None
142
143     return f
144
145 def fromxml(tree):
146     """
147     Initialize a Firecrest object from an element tree node
148     """
149     f = Firecrest()
150     f.set_elements(tree)
151     return f