source: CMIP6dreq/trunk/dreqPy/dreq.py @ 471

Subversion URL: http://proj.badc.rl.ac.uk/svn/exarch/CMIP6dreq/trunk/dreqPy/dreq.py@471
Revision 471, 26.3 KB checked in by mjuckes, 5 years ago (diff)

Updated setup for tag 01.beta.11

Line 
1"""This module provides a basic python API to the Data Request.
2After ingesting the XML documents (configuration and request) the module generates two python objects:
31. A collection of records
42. Index
5"""
6import xml, string, collections
7import xml.dom
8import xml.dom.minidom
9import re, shelve
10from __init__ import DOC_DIR
11
12
13blockSchemaFile = '%s/%s' % (DOC_DIR, 'BlockSchema.csv' )
14
15def loadBS(bsfile):
16  ii = open( bsfile, 'r' ).readlines()
17  ll = []
18  for l in ii:
19    ll.append( [x[1:-1] for x in string.strip(l).split('\t') ] )
20  cc = collections.defaultdict( dict )
21  for l in ll[3:]:
22    for i in range( len(ll[2]) ):
23      cc[l[0]][ll[2][i]] = l[i]
24  return cc
25
26class rechecks(object):
27  """Checks to be applied to strings"""
28  def __init__(self):
29    self.__isInt = re.compile( '-{0,1}[0-9]+' )
30
31  def isIntStr( self, tv ):
32    """Check whether a string is a valid representation of an integer."""
33    if type( tv ) not in {type(''),type(u'')}:
34      self.reason = 'NOT STRING'
35      return False
36    ok = self.__isInt.match( tv ) != None
37    if not ok:
38      self.reason = 'Failed to match regular expression for integers'
39    else:
40      self.reason = ''
41    return ok
42
43class dreqItemBase(object):
44       __doc__ = """A base class used in the definition of records. Designed to be used via a class factory which sets "itemLabelMode" and "attributes" before the class is instantiated: attempting to instantiate the class before setting these will trigger an exception."""
45       _indexInitialised = False
46       _inx = None
47       _urlBase = ''
48       _htmlStyle = {}
49       _linkAttrStyle = {}
50
51       def __init__(self,dict=None,xmlMiniDom=None,id='defaultId',etree=False):
52         dictMode = dict != None
53         mdMode = xmlMiniDom != None
54         assert not( dictMode and mdMode), 'Mode must be either dictionary of minidom: both assigned'
55         assert dictMode or mdMode, 'Mode must be either dictionary of minidom: neither assigned'
56         ##self._defaults = { }
57         ##self._globalDefault = '__unset__'
58         self._contentInitialised = False
59         self._greenIcon = '<img height="12pt" src="/images/154g.png" alt="[i]"/>'
60         if dictMode:
61           self.dictInit( dict )
62         elif mdMode:
63           self.mdInit( xmlMiniDom, etree=etree )
64
65       def __repr__(self):
66         """Provide a one line summary of identifying the object."""
67         if self._contentInitialised:
68           return 'Item <%s>: [%s] %s' % (self._h.title,self.label,self.title)
69         else:
70           return 'Item <%s>: uninitialised' % self._h.title
71
72       def __info__(self,full=False):
73         """Print a summary of the data held in the object as a list of key/value pairs"""
74         if self._contentInitialised:
75           print ( 'Item <%s>: [%s] %s' % (self._h.title,self.label,self.title) )
76           for a in self.__dict__.keys():
77             if a[0] != '_' or full:
78               if hasattr( self._a[a], 'useClass') and self._a[a].useClass == 'internalLink' and self._base._indexInitialised:
79                 if self.__dict__[a] in self._base._inx.uid:
80                   targ = self._base._inx.uid[ self.__dict__[a] ]
81                   print ( '   %s: [%s]%s [%s]' % ( a, targ._h.label, targ.label, self.__dict__[a] ) )
82                 else:
83                   print ( '   %s: [ERROR: key not found] [%s]' % ( a, self.__dict__[a] ) )
84               else:
85                 print ( '    %s: %s' % ( a, self.__dict__[a] ) )
86         else:
87           print ( 'Item <%s>: uninitialised' % self.sectionLabel )
88
89       def __href__(self,odir="",label=None):
90         igns =  {'','__unset__'}
91         if 'description' in self.__dict__ and self.description != None and string.strip( self.description ) not in igns:
92           ttl = self.description
93         elif 'title' in self.__dict__ and self.title != None and string.strip( self.title ) not in igns:
94           ttl = self.title
95         else:
96           ttl = self.label
97         if label == None:
98           label = self.uid
99         return '<span title="%s"><a href="%s%s.html">%s</a></span>' % (ttl,odir,self.uid,label)
100
101       def getHtmlLinkAttrStyle(self,a):
102         """Return a string containing a html fragment for a link to an attribute."""
103         if a in self.__class__._linkAttrStyle:
104           return self.__class__._linkAttrStyle[a]
105         else:
106           return lambda a,targ, frm='': '<li>%s: [%s] %s [%s]</li>' % ( a, targ._h.label, targ.label, targ.__href__() )
107
108       def __html__(self,ghis=None):
109         """Create html view"""
110         msg = []
111         if self._contentInitialised:
112           sect = self._h.label
113           msg.append( '<h1>%s: [%s] %s</h1>' % (self._h.title,self.label,self.title) )
114           msg.append( '<a href="../index.html">Home</a> &rarr; <a href="../index/%s.html">%s section index</a><br/>\n' % (sect, self._h.title) )
115           msg.append( '<ul>' )
116           for a in self.__dict__.keys():
117             if a[0] != '_':
118               app = '%s%s' % (a, self.__class__.__dict__[a].__href__(label=self._greenIcon) )
119               if hasattr( self._a[a], 'useClass') and self._a[a].useClass == 'internalLink' and self._base._indexInitialised:
120                 if self.__dict__[a] == '__unset__':
121                   m = '<li>%s: %s [missing link]</li>' % ( app, self.__dict__[a] )
122                 else:
123                   try:
124                     targ = self._base._inx.uid[ self.__dict__[a] ]
125                   except:
126                     print ( a, self.__dict__[a], sect )
127                     raise
128                   lst = self.getHtmlLinkAttrStyle(a)
129                   m = lst( app, targ, frm=sect )
130                   ##m = '<li>%s, %s: [%s] %s [%s]</li>' % ( a, self.__class__.__dict__[a].__href__(label=self._greenIcon), targ._h.label, targ.label, targ.__href__() )
131               else:
132                 m = '<li>%s: %s</li>' % ( app, self.__dict__[a] )
133               msg.append( m )
134           msg.append( '</ul>' )
135##
136## add list of inward references
137##
138           if self._base._indexInitialised:
139             f1 = self._htmlStyle.get( sect, {} ).get( 'getIrefs', None ) != None
140             if f1:
141               tl = []
142               if f1:
143                 tl = self._htmlStyle[sect]['getIrefs']
144               doall = '__all__' in tl
145               if doall:
146                 tl = self._inx.iref_by_sect[self.uid].a.keys()
147               am = []
148               for t in tl:
149                 if t in self._inx.iref_by_sect[self.uid].a:
150                   am.append( '<h3>%s</h3>' % t )
151                   am.append( '<ul>' )
152                   items = [self._inx.uid[u] for  u in self._inx.iref_by_sect[self.uid].a[t] ]
153                   items.sort( ds('label').cmp )
154                   for targ in items:
155                     if ghis == None:
156                       m = '<li>%s:%s [%s]</li>' % ( targ._h.label, targ.label, targ.__href__() )
157                     else:
158                       lst = ghis( targ._h.label )
159                       m = lst( targ, frm=sect )
160                     am.append( m )
161                   am.append( '</ul>' )
162               if len(am) > 0:
163                  msg.append( '<h2>Links from other sections</h2>' )
164                  for m in am:
165                    msg.append(m)
166               
167         else:
168           msg.append( '<b>Item %s: uninitialised</b>' % self.sectionLabel )
169         return msg
170
171
172       def dictInit( self, dict ):
173         __doc__ = """Initialise from a dictionary."""
174         for a in self._a.keys():
175           if a in dict:
176             self.__dict__[a] = dict[a]
177           else:
178             self.__dict__[a] = self._d.defaults.get( a, self._d.glob )
179         self._contentInitialised = True
180
181       def mdInit( self, el, etree=False ):
182         __doc__ = """Initialisation from a mindom XML element. The list of attributes must be set by the class factory before the class is initialised"""
183         deferredHandling=False
184         nw1 = 0
185         tvtl = []
186         if etree:
187           ks = set( el.keys() )
188           for a in self._a.keys():
189             if a in ks:
190               aa = '%s%s' % (self.ns,a)
191               tvtl.append( (a,True, str( el.get( a ) ) ) )
192             else:
193               tvtl.append( (a,False,None) )
194         else:
195           for a in self._a.keys():
196             if el.hasAttribute( a ):
197               tvtl.append( (a,True, str( el.getAttribute( a ) ) ) )
198             else:
199               tvtl.append( (a,False,None) )
200       
201         for a,tv,v in tvtl:
202           if tv:
203             if self._a[a].type == u'xs:float':
204               try:
205                 v = float(v)
206               except:
207                 print ( 'Failed to convert real number: %s' % v )
208                 raise
209             elif self._a[a].type == u'xs:integer':
210               if self._rc.isIntStr( v ):
211                 v = int(v)
212               else:
213                 v = string.strip(v)
214                 thissect = '%s [%s]' % (self._h.title,self._h.tag)
215                 if v in { '',u'',' ', u' '}:
216                   if nw1 < 20:
217                     print ( 'WARN.050.0001: input integer non-compliant: %s: %s: "%s" -- set to zero' % (thissect,a,v) )
218                     nw1 += 1
219                   v = 0
220                 else:
221                   try:
222                     v = int(float(v))
223                     print ( 'WARN: input integer non-compliant: %s: %s: %s' % (thissect,a,v) )
224                   except:
225                     msg = 'ERROR: failed to convert integer: %s: %s: %s' % (thissect,a,v)
226                     deferredHandling=True
227             elif self._a[a].type == u'xs:boolean':
228               v = v in {'true','1'}
229             self.__dict__[a] = v
230           else:
231             if a in {'uid'}:
232               thissect = '%s [%s]' % (self._h.title,self._h.tag)
233               print ( 'ERROR.020.0001: missing uid: %s' % thissect )
234               if etree:
235                 print ( ks )
236                 import sys
237                 sys.exit(0)
238             self.__dict__[a] = self._d.defaults.get( a, self._d.glob )
239
240           ##if type( self.__dict__.get( 'rowIndex', 0 ) ) != type(0):
241             ##print 'Bad row index ', el.hasAttribute( 'rowIndex' )
242             ##raise
243           if deferredHandling:
244             print ( msg )
245
246         self._contentInitialised = True
247
248   
249class config(object):
250  """Read in a vocabulary collection configuration document and a vocabulary document"""
251
252  def __init__(self, configdoc='out/dreqDefn.xml', thisdoc='../workbook/trial_20150724.xml', useShelve=False):
253    self.rc = rechecks()
254    self.silent = True
255    self.vdef = configdoc
256    self.vsamp = thisdoc
257
258    self.nts = collections.namedtuple( 'sectdef', ['tag','label','title','id','itemLabelMode','level','maxOccurs','labUnique'] )
259    self.nti = collections.namedtuple( 'itemdef', ['tag','label','title','type','useClass','techNote'] )
260    self.ntt = collections.namedtuple( 'sectinit', ['header','attributes','defaults'] )
261    self.nt__default = collections.namedtuple( 'deflt', ['defaults','glob'] )
262    self.ntf = collections.namedtuple( 'sect', ['header','attDefn','items'] )
263    self.bscc = loadBS(blockSchemaFile)
264
265    self.coll = {}
266    doc = xml.dom.minidom.parse( self.vdef  )
267##
268## elementTree parsing implemented for main document
269##
270    self.etree = False
271    self.etree = True
272    if self.etree:
273      import xml.etree.cElementTree as cel
274
275      self.contentDoc = cel.parse( self.vsamp )
276      root = self.contentDoc.getroot()
277      ##bs = string.split( root.tag, '}' )
278      bs = root.tag.split( '}' )
279      if len( bs ) > 1:
280        self.ns = bs[0] + '}'
281      else:
282        self.ns = None
283    else:
284      self.contentDoc = xml.dom.minidom.parse( self.vsamp )
285      self.ns = None
286
287    vl = doc.getElementsByTagName( 'table' )
288    self.tables = {}
289    tables = {}
290    self.tableClasses = {}
291    self.tableItems = collections.defaultdict( list )
292##
293## this loads in some metadata, but not yet in a useful way.
294##
295    self._t0 = self.parsevcfg(None)
296    self._tableClass0 = self.itemClassFact( self._t0, ns=self.ns )
297
298##
299## define a class for the section heading records.
300##
301    self._t1 = self.parsevcfg('__sect__')
302    self._t2 = self.parsevcfg('__main__')
303    self._sectClass0 = self.itemClassFact( self._t1, ns=self.ns )
304
305    self.tt0 = {}
306    for k in self.bscc:
307      self.tt0[k] = self._tableClass0(dict=self.bscc[k])
308      if k in self._t0.attributes:
309        setattr( self._tableClass0, '%s' % k, self.tt0[k] )
310      if k in self._t1.attributes:
311        setattr( self._sectClass0, '%s' % k, self.tt0[k] )
312
313##
314## save header information, as for recordAttributeDefn below
315##
316    self._recAtDef = {'__core__':self._t0, '__sect__':self._t1}
317##
318## experimental addition of __core__ to coll dictionary ..
319##
320    self.coll['__core__'] = self.ntf( self._t0.header, self._t0.attributes, [self.tt0[k] for k in self.tt0] )
321      ##self.coll[k] = self.ntf( self.recordAttributeDefn[k].header, self.recordAttributeDefn[k].attributes, self.tableItems[k] )
322
323    self.tt1 = {}
324    self.ttl2 = []
325    for v in vl:
326      t = self.parsevcfg(v)
327      tables[t[0].label] = t
328      self.tableClasses[t[0].label] = self.itemClassFact( t, ns=self.ns )
329      thisc = self.tableClasses[t[0].label]
330      self.tt1[t[0].label] = self._sectClass0( dict=t.header.__dict__ )
331      self.tt1[t[0].label].maxOccurs = t.header.maxOccurs
332      self.tt1[t[0].label].labUnique = t.header.labUnique
333      self.tt1[t[0].label].level = t.header.level
334      self.tt1[t[0].label].itemLabelMode = t.header.itemLabelMode
335      self.ttl2 += [thisc.__dict__[a] for a in t.attributes]
336    self.coll['__main__'] = self.ntf( self._t2.header, self._t2.attributes, self.ttl2 )
337
338    self.coll['__sect__'] = self.ntf( self._t1.header, self._t1.attributes, [self.tt1[k] for k in self.tt1] )
339
340    self.recordAttributeDefn = tables
341    for k in tables.keys():
342      if self.etree:
343        vl = root.findall( './/%s%s' % (self.ns,k) )
344        if len(vl) == 1:
345          v = vl[0]
346          t = v.get( 'title' )
347          i = v.get( 'id' )
348          uid = v.get( 'uid' )
349          useclass = v.get( 'useClass' )
350
351          self.tt1[k].label = k
352          self.tt1[k].title = t
353          self.tt1[k].id = i
354          self.tt1[k].uid = uid
355          self.tt1[k].useClass = useclass
356          self.tableClasses[k]._h = self.tt1[k]
357          il = v.findall( '%sitem' % self.ns )
358          self.info( '%s, %s, %s, %s' % ( k, t, i, len(il) ) )
359 
360          self.tables[k] = (i,t,len(il))
361       
362          for i in il:
363            ii = self.tableClasses[k](xmlMiniDom=i, etree=True)
364            self.tableItems[k].append( ii )
365        elif len(vl) > 1:
366          assert False, 'not able to handle repeat sections with etree yet'
367      else:
368        vl = self.contentDoc.getElementsByTagName( k )
369        if len(vl) == 1:
370          v = vl[0]
371          t = v.getAttribute( 'title' )
372          i = v.getAttribute( 'id' )
373          il = v.getElementsByTagName( 'item' )
374          self.info( '%s, %s, %s, %s' % ( k, t, i, len(il) ) )
375 
376          self.tables[k] = (i,t,len(il))
377       
378          for i in il:
379            ii = self.tableClasses[k](xmlMiniDom=i)
380            self.tableItems[k].append( ii )
381        elif len(vl) > 1:
382          l1 = []
383          l2 = []
384          for v in vl:
385            t = v.getAttribute( 'title' )
386            i = v.getAttribute( 'id' )
387            il = v.getElementsByTagName( 'item' )
388            self.info( '%s, %s, %s, %s' % ( k, t, i, len(il) ) )
389            l1.append( (i,t,len(il)) )
390         
391            l2i = []
392            for i in il:
393              ii = self.tableClasses[k](xmlMiniDom=i)
394              l2i.append( ii )
395            l2.append( l2i )
396          self.tables[k] = l1
397          self.tableItems[k] = l2
398      self.coll[k] = self.ntf( self.recordAttributeDefn[k].header, self.recordAttributeDefn[k].attributes, self.tableItems[k] )
399 
400  def info(self,ss):
401    if not self.silent:
402      print ( ss )
403
404  def get(self):
405    return self.coll
406
407  def itemClassFact(self, sectionInfo,ns=None):
408     class dreqItem(dreqItemBase):
409       """Inherits all methods from dreqItemBase.
410
411USAGE
412-----
413The instanstiated object contains a single data record. The "_h" attribute links to information about the record and the section it belongs to.
414
415object._a: a python dictionary defining the attributes in each record. The keys in the dictionary correspond to the attribute names and the values are python "named tuples" (from the "collections" module). E.g. object._a['priority'].type contains the type of the 'priority' attribute. Type is expressed using XSD schema language, so "xs:integer" implies integer.  The "useClass" attribute carries information about usage. If object._a['xxx'].useClass = u'internalLink' then the record attribute provides a link to another element and object.xxx is the unique identifier of that element.
416
417object._h: a python named tuple describing the section. E.g. object._h.title is the section title (E.g. "CMOR Variables")
418"""
419       _base=dreqItemBase
420       
421     dreqItem.__name__ = 'dreqItem_%s' % str( sectionInfo.header.label )
422     dreqItem._h = sectionInfo.header
423     dreqItem._a = sectionInfo.attributes
424     dreqItem._d = sectionInfo.defaults
425     if sectionInfo.attributes != None:
426        self.addAttributes(dreqItem, sectionInfo.attributes )
427     ##dreqItem.itemLabelMode = itemLabelMode
428     ##dreqItem.attributes = attributes
429     dreqItem._rc = self.rc
430     dreqItem.ns = ns
431     return dreqItem
432
433  def addAttributes( self, thisClass, attrDict ):
434    for k in attrDict:
435      setattr( thisClass, '%s' % k , attrDict[k] )
436         
437  def parsevcfg(self,v):
438      """Parse a section definition element, including all the record attributes. The results are returned as a namedtuple of attributes for the section and a dictionary of record attribute specifications."""
439      if v in [ None,'__main__']:
440        idict = {'description':'An extended description of the object', 'title':'Record Description', \
441         'techNote':'', 'useClass':'__core__', 'superclass':'rdf:property',\
442         'type':'xs:string', 'uid':'__core__:description', 'label':'label' }
443        if v == None:
444          vtt = self.nts( '__core__', 'CoreAttributes', 'Core Attributes', '00000000', 'def', '0', '0', 'false' )
445        else:
446          vtt = self.nts( '__main__', 'Attributes defined for the Data Request', 'Data Request Attributes', '00000001', 'def', '0', '0', 'false' )
447      elif v == '__sect__':
448        idict = {'title':'Record Description', \
449         'uid':'__core__:description', 'label':'label', 'useClass':'text', 'id':'id', 'maxOccurs':'', 'itemLabelMode':'', 'level':'', 'labUnique':'' }
450        vtt = self.nts( '__core__', 'sectionAttributes', 'Section Attributes', '00000000', 'def', '0', '0', 'false' )
451##<var label="var" uid="SECTION:var" useClass="vocab" title="MIP Variable" id="cmip.drv.001">
452      else:
453        l = v.getAttribute( 'label' )
454        t = v.getAttribute( 'title' )
455        i = v.getAttribute( 'id' )
456        ilm = v.getAttribute( 'itemLabelMode' )
457        lev = v.getAttribute( 'level' )
458        maxo = v.getAttribute( 'maxOccurs' )
459        labu = v.getAttribute( 'labUnique' )
460        il = v.getElementsByTagName( 'rowAttribute' )
461        vtt = self.nts( v.nodeName, l,t,i,ilm,lev, maxo, labu )
462        idict = {}
463        for i in il:
464          tt = self.parseicfg(i)
465          idict[tt.label] = tt
466      deflt = self.nt__default( {}, '__unset__' )
467      return self.ntt( vtt, idict, deflt )
468
469  def parseicfg(self,i):
470      """Parse a record attribute specification"""
471      defs = {'type':"xs:string"}
472      ll = []
473      ee = {}
474      for k in ['label','title','type','useClass','techNote','description','uid']:
475        if i.hasAttribute( k ):
476          ll.append( i.getAttribute( k ) )
477        else:
478          ll.append( defs.get( k, None ) )
479        ee[k] = ll[-1]
480      l, t, ty, cls, tn, desc, uid = ll
481      self.lastTitle = t
482
483      returnClass = True
484      if returnClass:
485        return self._tableClass0( dict=ee )
486      else:
487        return self.nti( i.nodeName, l,t,ty,cls,tn )
488
489class container(object):
490  """Simple container class, to hold a set of dictionaries of lists."""
491  def __init__(self, atl ):
492    self.uid = {}
493    for a in atl:
494      self.__dict__[a] =  collections.defaultdict( list )
495
496class c1(object):
497  def __init__(self):
498    self.a = collections.defaultdict( list )
499
500class index(object):
501  """Create an index of the document. Cross-references are generated from attributes with class 'internalLink'.
502This version assumes that each record is identified by an "uid" attribute and that there is a "var" section.
503Invalid internal links are recorded in tme "missingIds" dictionary.
504For any record, with identifier u, iref_by_uid[u] gives a list of the section and identifier of records linking to that record.
505"""
506
507  def __init__(self, dreq):
508    self.silent = True
509    self.uid = {}
510    self.uid2 = collections.defaultdict( list )
511    nativeAtts = ['uid','iref_by_uid','iref_by_sect','missingIds']
512    naok = map( lambda x: not x in dreq, nativeAtts )
513    assert all(naok), 'This version cannot index collections containing sections with names: %s' % str( nativeAtts )
514    self.var_uid = {}
515    self.var_by_name = collections.defaultdict( list )
516    self.var_by_sn = collections.defaultdict( list )
517    self.iref_by_uid = collections.defaultdict( list )
518    irefdict = collections.defaultdict( list )
519    for k in dreq.keys():
520      if 'sn' in dreq[k].attDefn:
521         self.__dict__[k] =  container( ['label','sn'] )
522      else:
523         self.__dict__[k] =  container( ['label'] )
524    ##
525    ## collected names of attributes which carry internal links
526    ##
527      for ka in dreq[k].attDefn.keys():
528        if hasattr( dreq[k].attDefn[ka], 'useClass') and dreq[k].attDefn[ka].useClass == 'internalLink':
529           irefdict[k].append( ka )
530
531    for k in dreq.keys():
532        for i in dreq[k].items:
533          assert 'uid' in i.__dict__, 'uid not found::\n%s\n%s' % (str(i._h),str(i.__dict__) )
534          if 'uid' in self.uid:
535            print ( 'ERROR.100.0001: Duplicate uid: %s [%s]' % (i.uid,i._h.title) )
536            self.uid2[i.uid].append( (k,i) )
537          else:
538### create index bx uid.
539            self.uid[i.uid] = i
540
541    self.missingIds = collections.defaultdict( list )
542    self.iref_by_sect = collections.defaultdict( c1 )
543    for k in dreq.keys():
544        for k2 in irefdict.get( k, [] ):
545          n1 = 0
546          n2 = 0
547          for i in dreq[k].items:
548            id2 = i.__dict__.get( k2 )
549            if id2 != '__unset__':
550              sect = i._h.label
551## append attribute name and target  -- item i.uid, attribute k2 reference item id2
552              self.iref_by_uid[ id2 ].append( (k2,i.uid) )
553              self.iref_by_sect[ id2 ].a[sect].append( i.uid )
554              if id2 in self.uid:
555                n1 += 1
556              else:
557                n2 += 1
558                self.missingIds[id2].append( (k,k2,i.uid) )
559          self.info(  'INFO:: %s, %s%s (%s)' % (k,k2,n1,n2) )
560
561    for k in dreq.keys():
562      for i in dreq[k].items:
563        self.__dict__[k].uid[i.uid] = i
564        self.__dict__[k].label[i.label].append( i.uid )
565        if 'sn' in dreq[k].attDefn:
566          self.__dict__[k].sn[i.sn].append( i.uid )
567
568  def info(self,ss):
569    if not self.silent:
570      print ( ss )
571
572class ds(object):
573  def __init__(self,k):
574    self.k = k
575  def cmp(self,x,y):
576    return cmp( x.__dict__[self.k], y.__dict__[self.k] )
577
578src1 = '../workbook/trial_20150831.xml'
579
580#DEFAULT LOCATION -- changed automatically when building distribution
581defaultDreq = 'dreq.xml'
582#DEFAULT CONFIG
583defaultConfig = 'dreq2Defn.xml'
584
585defaultDreqPath = '%s/%s' % (DOC_DIR, defaultDreq )
586defaultConfigPath = '%s/%s' % (DOC_DIR, defaultConfig )
587
588class loadDreq(object):
589  """Load in a vocabulary document.
590  dreqXML: full path to the XML document
591  configdoc: full path to associated configuration document
592  useShelve: flag to specify whether to retrieve data from cache (not implemented)
593  htmlStyles: dictionary of styling directives which influence structure of html page generates by the "makeHtml" method
594"""
595
596  def __init__(self,dreqXML=defaultDreqPath, configdoc=defaultConfigPath, useShelve=False, htmlStyles=None ):
597    self.c = config( thisdoc=dreqXML, configdoc=configdoc, useShelve=useShelve)
598    self.coll = self.c.get()
599    self.inx = index(self.coll)
600    self.defaultItemLineStyle = lambda i, frm='': '<li>%s: %s</li>' % ( i.label, i.__href__(odir='../u/') )
601    self.itemStyles = {}
602##
603## add index to Item base class .. so that it can be accessed by item instances
604##
605    dreqItemBase._inx = self.inx
606    dreqItemBase._indexInitialised = True
607##
608## load in additional styling directives
609##
610    if htmlStyles != None:
611      for k in htmlStyles:
612        dreqItemBase._htmlStyle[k] = htmlStyles[k]
613
614##    dreqItemBase._htmlStyle['__general__'] = {'addRemarks':True}
615
616    self.pageTmpl = """<html><head><title>%s</title>
617<link rel="stylesheet" type="text/css" href="%scss/dreq.css">
618</head><body>
619<div id="top">CMIP6 Data Request</div>
620%s</body></html>"""
621
622  def getHtmlItemStyle(self, sect):
623    if sect in self.itemStyles:
624      return self.itemStyles[sect]
625    return self.defaultItemLineStyle
626
627  def makeHtml(self,odir='./html', ttl0 = 'Data Request Index'):
628    """Generate a html view of the vocabularies, using the "__html__" method of the vocabulary item class to generate a
629page for each item and also generating index pages.
630    odir: directory for html files;
631    ttl0: Title for main index (in odir/index.html)"""
632
633    for k in self.inx.uid.keys():
634      i = self.inx.uid[k]
635      ttl = 'Data Request Record: [%s]%s' % (i._h.label,i.label)
636      bdy = string.join( i.__html__( ghis=self.getHtmlItemStyle ), '\n' )
637      oo = open( '%s/u/%s.html' % (odir,i.uid), 'w' )
638      oo.write( self.pageTmpl % (ttl, '../', bdy ) )
639      oo.close()
640
641    msg0 = ['<h1>%s</h1>' % ttl0, '<ul>',]
642    ks = sorted( self.coll.keys() )
643    for k in ks:
644##
645## sort on item label
646##
647      self.coll[k].items.sort( ds('label').cmp )
648      ttl = 'Data Request Section: %s' % k
649      msg0.append( '<li><a href="index/%s.html">%s [%s]</a></li>\n' % (k,self.coll[k].header.title,k) )
650      msg = ['<h1>%s</h1>\n' % ttl, '<ul>',]
651      msg.append( '<a href="../index.html">Home</a><br/>\n' )
652      lst = self.getHtmlItemStyle(k)
653      for i in self.coll[k].items:
654        ##m = '<li>%s: %s</li>' % ( i.label, i.__href__(odir='../u/') )
655        m = lst( i )
656        msg.append( m )
657      msg.append( '</ul>' )
658      bdy = string.join( msg, '\n' )
659      oo = open( '%s/index/%s.html' % (odir,k), 'w' )
660      oo.write( self.pageTmpl % (ttl, '../', bdy ) )
661      oo.close()
662    msg0.append( '</ul>' )
663    bdy = string.join( msg0, '\n' )
664    oo = open( '%s/index.html' % odir, 'w' )
665    oo.write( self.pageTmpl % (ttl0, '', bdy ) )
666    oo.close()
667   
668if __name__ == '__main__':
669  dreq = loadDreq( )
670
Note: See TracBrowser for help on using the repository browser.