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

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

removed fragile use of dict in namedtuple

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,idict=None,xmlMiniDom=None,id='defaultId',etree=False):
52         dictMode = idict != 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( idict )
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, idict ):
173         __doc__ = """Initialise from a dictionary."""
174         for a in self._a.keys():
175           if a in idict:
176             val = idict[a]
177           else:
178             val = self._d.defaults.get( a, self._d.glob )
179           setattr( self, a, val )
180         self._contentInitialised = True
181
182       def mdInit( self, el, etree=False ):
183         __doc__ = """Initialisation from a mindom XML element. The list of attributes must be set by the class factory before the class is initialised"""
184         deferredHandling=False
185         nw1 = 0
186         tvtl = []
187         if etree:
188           ks = set( el.keys() )
189           for a in self._a.keys():
190             if a in ks:
191               aa = '%s%s' % (self.ns,a)
192               tvtl.append( (a,True, str( el.get( a ) ) ) )
193             else:
194               tvtl.append( (a,False,None) )
195         else:
196           for a in self._a.keys():
197             if el.hasAttribute( a ):
198               tvtl.append( (a,True, str( el.getAttribute( a ) ) ) )
199             else:
200               tvtl.append( (a,False,None) )
201       
202         for a,tv,v in tvtl:
203           if tv:
204             if self._a[a].type == u'xs:float':
205               try:
206                 v = float(v)
207               except:
208                 print ( 'Failed to convert real number: %s' % v )
209                 raise
210             elif self._a[a].type == u'xs:integer':
211               if self._rc.isIntStr( v ):
212                 v = int(v)
213               else:
214                 v = string.strip(v)
215                 thissect = '%s [%s]' % (self._h.title,self._h.tag)
216                 if v in [ '',u'',' ', u' ']:
217                   if nw1 < 20:
218                     print ( 'WARN.050.0001: input integer non-compliant: %s: %s: "%s" -- set to zero' % (thissect,a,v) )
219                     nw1 += 1
220                   v = 0
221                 else:
222                   try:
223                     v = int(float(v))
224                     print ( 'WARN: input integer non-compliant: %s: %s: %s' % (thissect,a,v) )
225                   except:
226                     msg = 'ERROR: failed to convert integer: %s: %s: %s' % (thissect,a,v)
227                     deferredHandling=True
228             elif self._a[a].type == u'xs:boolean':
229               v = v in ['true','1']
230             self.__dict__[a] = v
231           else:
232             if a in ['uid',]:
233               thissect = '%s [%s]' % (self._h.title,self._h.tag)
234               print ( 'ERROR.020.0001: missing uid: %s' % thissect )
235               if etree:
236                 print ( ks )
237                 import sys
238                 sys.exit(0)
239             self.__dict__[a] = self._d.defaults.get( a, self._d.glob )
240
241           ##if type( self.__dict__.get( 'rowIndex', 0 ) ) != type(0):
242             ##print 'Bad row index ', el.hasAttribute( 'rowIndex' )
243             ##raise
244           if deferredHandling:
245             print ( msg )
246
247         self._contentInitialised = True
248
249   
250class config(object):
251  """Read in a vocabulary collection configuration document and a vocabulary document"""
252
253  def __init__(self, configdoc='out/dreqDefn.xml', thisdoc='../workbook/trial_20150724.xml', useShelve=False):
254    self.rc = rechecks()
255    self.silent = True
256    self.vdef = configdoc
257    self.vsamp = thisdoc
258
259    self.nts = collections.namedtuple( 'sectdef', ['tag','label','title','id','itemLabelMode','level','maxOccurs','labUnique'] )
260    self.nti = collections.namedtuple( 'itemdef', ['tag','label','title','type','useClass','techNote'] )
261    self.ntt = collections.namedtuple( 'sectinit', ['header','attributes','defaults'] )
262    self.nt__default = collections.namedtuple( 'deflt', ['defaults','glob'] )
263    self.ntf = collections.namedtuple( 'sect', ['header','attDefn','items'] )
264    self.bscc = loadBS(blockSchemaFile)
265
266    self.coll = {}
267    doc = xml.dom.minidom.parse( self.vdef  )
268##
269## elementTree parsing implemented for main document
270##
271    self.etree = False
272    self.etree = True
273    if self.etree:
274      import xml.etree.cElementTree as cel
275
276      self.contentDoc = cel.parse( self.vsamp )
277      root = self.contentDoc.getroot()
278      ##bs = string.split( root.tag, '}' )
279      bs = root.tag.split( '}' )
280      if len( bs ) > 1:
281        self.ns = bs[0] + '}'
282      else:
283        self.ns = None
284    else:
285      self.contentDoc = xml.dom.minidom.parse( self.vsamp )
286      self.ns = None
287
288    vl = doc.getElementsByTagName( 'table' )
289    self.tables = {}
290    tables = {}
291    self.tableClasses = {}
292    self.tableItems = collections.defaultdict( list )
293##
294## this loads in some metadata, but not yet in a useful way.
295##
296    self._t0 = self.parsevcfg(None)
297    self._tableClass0 = self.itemClassFact( self._t0, ns=self.ns )
298
299##
300## define a class for the section heading records.
301##
302    self._t1 = self.parsevcfg('__sect__')
303    self._t2 = self.parsevcfg('__main__')
304    self._sectClass0 = self.itemClassFact( self._t1, ns=self.ns )
305
306    self.tt0 = {}
307    for k in self.bscc:
308      self.tt0[k] = self._tableClass0(idict=self.bscc[k])
309      if k in self._t0.attributes:
310        setattr( self._tableClass0, '%s' % k, self.tt0[k] )
311      if k in self._t1.attributes:
312        setattr( self._sectClass0, '%s' % k, self.tt0[k] )
313
314##
315## save header information, as for recordAttributeDefn below
316##
317    self._recAtDef = {'__core__':self._t0, '__sect__':self._t1}
318##
319## experimental addition of __core__ to coll dictionary ..
320##
321    self.coll['__core__'] = self.ntf( self._t0.header, self._t0.attributes, [self.tt0[k] for k in self.tt0] )
322      ##self.coll[k] = self.ntf( self.recordAttributeDefn[k].header, self.recordAttributeDefn[k].attributes, self.tableItems[k] )
323
324    self.tt1 = {}
325    self.ttl2 = []
326    for v in vl:
327      t = self.parsevcfg(v)
328      tables[t[0].label] = t
329      self.tableClasses[t[0].label] = self.itemClassFact( t, ns=self.ns )
330      thisc = self.tableClasses[t[0].label]
331      self.tt1[t[0].label] = self._sectClass0( idict=t.header._asdict() )
332      self.tt1[t[0].label].maxOccurs = t.header.maxOccurs
333      self.tt1[t[0].label].labUnique = t.header.labUnique
334      self.tt1[t[0].label].level = t.header.level
335      self.tt1[t[0].label].itemLabelMode = t.header.itemLabelMode
336      self.ttl2 += [thisc.__dict__[a] for a in t.attributes]
337    self.coll['__main__'] = self.ntf( self._t2.header, self._t2.attributes, self.ttl2 )
338
339    self.coll['__sect__'] = self.ntf( self._t1.header, self._t1.attributes, [self.tt1[k] for k in self.tt1] )
340
341    self.recordAttributeDefn = tables
342    for k in tables.keys():
343      if self.etree:
344        vl = root.findall( './/%s%s' % (self.ns,k) )
345        if len(vl) == 1:
346          v = vl[0]
347          t = v.get( 'title' )
348          i = v.get( 'id' )
349          uid = v.get( 'uid' )
350          useclass = v.get( 'useClass' )
351
352          self.tt1[k].label = k
353          self.tt1[k].title = t
354          self.tt1[k].id = i
355          self.tt1[k].uid = uid
356          self.tt1[k].useClass = useclass
357          self.tableClasses[k]._h = self.tt1[k]
358          il = v.findall( '%sitem' % self.ns )
359          self.info( '%s, %s, %s, %s' % ( k, t, i, len(il) ) )
360 
361          self.tables[k] = (i,t,len(il))
362       
363          for i in il:
364            ii = self.tableClasses[k](xmlMiniDom=i, etree=True)
365            self.tableItems[k].append( ii )
366        elif len(vl) > 1:
367          assert False, 'not able to handle repeat sections with etree yet'
368      else:
369        vl = self.contentDoc.getElementsByTagName( k )
370        if len(vl) == 1:
371          v = vl[0]
372          t = v.getAttribute( 'title' )
373          i = v.getAttribute( 'id' )
374          il = v.getElementsByTagName( 'item' )
375          self.info( '%s, %s, %s, %s' % ( k, t, i, len(il) ) )
376 
377          self.tables[k] = (i,t,len(il))
378       
379          for i in il:
380            ii = self.tableClasses[k](xmlMiniDom=i)
381            self.tableItems[k].append( ii )
382        elif len(vl) > 1:
383          l1 = []
384          l2 = []
385          for v in vl:
386            t = v.getAttribute( 'title' )
387            i = v.getAttribute( 'id' )
388            il = v.getElementsByTagName( 'item' )
389            self.info( '%s, %s, %s, %s' % ( k, t, i, len(il) ) )
390            l1.append( (i,t,len(il)) )
391         
392            l2i = []
393            for i in il:
394              ii = self.tableClasses[k](xmlMiniDom=i)
395              l2i.append( ii )
396            l2.append( l2i )
397          self.tables[k] = l1
398          self.tableItems[k] = l2
399      self.coll[k] = self.ntf( self.recordAttributeDefn[k].header, self.recordAttributeDefn[k].attributes, self.tableItems[k] )
400 
401  def info(self,ss):
402    if not self.silent:
403      print ( ss )
404
405  def get(self):
406    return self.coll
407
408  def itemClassFact(self, sectionInfo,ns=None):
409     class dreqItem(dreqItemBase):
410       """Inherits all methods from dreqItemBase.
411
412USAGE
413-----
414The instanstiated object contains a single data record. The "_h" attribute links to information about the record and the section it belongs to.
415
416object._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.
417
418object._h: a python named tuple describing the section. E.g. object._h.title is the section title (E.g. "CMOR Variables")
419"""
420       _base=dreqItemBase
421       
422     dreqItem.__name__ = 'dreqItem_%s' % str( sectionInfo.header.label )
423     dreqItem._h = sectionInfo.header
424     dreqItem._a = sectionInfo.attributes
425     dreqItem._d = sectionInfo.defaults
426     if sectionInfo.attributes != None:
427        self.addAttributes(dreqItem, sectionInfo.attributes )
428     ##dreqItem.itemLabelMode = itemLabelMode
429     ##dreqItem.attributes = attributes
430     dreqItem._rc = self.rc
431     dreqItem.ns = ns
432     return dreqItem
433
434  def addAttributes( self, thisClass, attrDict ):
435    for k in attrDict:
436      setattr( thisClass, '%s' % k , attrDict[k] )
437         
438  def parsevcfg(self,v):
439      """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."""
440      if v in [ None,'__main__']:
441        idict = {'description':'An extended description of the object', 'title':'Record Description', \
442         'techNote':'', 'useClass':'__core__', 'superclass':'rdf:property',\
443         'type':'xs:string', 'uid':'__core__:description', 'label':'label' }
444        if v == None:
445          vtt = self.nts( '__core__', 'CoreAttributes', 'Core Attributes', '00000000', 'def', '0', '0', 'false' )
446        else:
447          vtt = self.nts( '__main__', 'Attributes defined for the Data Request', 'Data Request Attributes', '00000001', 'def', '0', '0', 'false' )
448      elif v == '__sect__':
449        idict = {'title':'Record Description', \
450         'uid':'__core__:description', 'label':'label', 'useClass':'text', 'id':'id', 'maxOccurs':'', 'itemLabelMode':'', 'level':'', 'labUnique':'' }
451        vtt = self.nts( '__core__', 'sectionAttributes', 'Section Attributes', '00000000', 'def', '0', '0', 'false' )
452##<var label="var" uid="SECTION:var" useClass="vocab" title="MIP Variable" id="cmip.drv.001">
453      else:
454        l = v.getAttribute( 'label' )
455        t = v.getAttribute( 'title' )
456        i = v.getAttribute( 'id' )
457        ilm = v.getAttribute( 'itemLabelMode' )
458        lev = v.getAttribute( 'level' )
459        maxo = v.getAttribute( 'maxOccurs' )
460        labu = v.getAttribute( 'labUnique' )
461        il = v.getElementsByTagName( 'rowAttribute' )
462        vtt = self.nts( v.nodeName, l,t,i,ilm,lev, maxo, labu )
463        idict = {}
464        for i in il:
465          tt = self.parseicfg(i)
466          idict[tt.label] = tt
467      deflt = self.nt__default( {}, '__unset__' )
468      return self.ntt( vtt, idict, deflt )
469
470  def parseicfg(self,i):
471      """Parse a record attribute specification"""
472      defs = {'type':"xs:string"}
473      ll = []
474      ee = {}
475      for k in ['label','title','type','useClass','techNote','description','uid']:
476        if i.hasAttribute( k ):
477          ll.append( i.getAttribute( k ) )
478        else:
479          ll.append( defs.get( k, None ) )
480        ee[k] = ll[-1]
481      l, t, ty, cls, tn, desc, uid = ll
482      self.lastTitle = t
483
484      returnClass = True
485      if returnClass:
486        return self._tableClass0( idict=ee )
487      else:
488        return self.nti( i.nodeName, l,t,ty,cls,tn )
489
490class container(object):
491  """Simple container class, to hold a set of dictionaries of lists."""
492  def __init__(self, atl ):
493    self.uid = {}
494    for a in atl:
495      self.__dict__[a] =  collections.defaultdict( list )
496
497class c1(object):
498  def __init__(self):
499    self.a = collections.defaultdict( list )
500
501class index(object):
502  """Create an index of the document. Cross-references are generated from attributes with class 'internalLink'.
503This version assumes that each record is identified by an "uid" attribute and that there is a "var" section.
504Invalid internal links are recorded in tme "missingIds" dictionary.
505For any record, with identifier u, iref_by_uid[u] gives a list of the section and identifier of records linking to that record.
506"""
507
508  def __init__(self, dreq):
509    self.silent = True
510    self.uid = {}
511    self.uid2 = collections.defaultdict( list )
512    nativeAtts = ['uid','iref_by_uid','iref_by_sect','missingIds']
513    naok = map( lambda x: not x in dreq, nativeAtts )
514    assert all(naok), 'This version cannot index collections containing sections with names: %s' % str( nativeAtts )
515    self.var_uid = {}
516    self.var_by_name = collections.defaultdict( list )
517    self.var_by_sn = collections.defaultdict( list )
518    self.iref_by_uid = collections.defaultdict( list )
519    irefdict = collections.defaultdict( list )
520    for k in dreq.keys():
521      if 'sn' in dreq[k].attDefn:
522         self.__dict__[k] =  container( ['label','sn'] )
523      else:
524         self.__dict__[k] =  container( ['label'] )
525    ##
526    ## collected names of attributes which carry internal links
527    ##
528      for ka in dreq[k].attDefn.keys():
529        if hasattr( dreq[k].attDefn[ka], 'useClass') and dreq[k].attDefn[ka].useClass == 'internalLink':
530           irefdict[k].append( ka )
531
532    for k in dreq.keys():
533        for i in dreq[k].items:
534          assert 'uid' in i.__dict__, 'uid not found::\n%s\n%s' % (str(i._h),str(i.__dict__) )
535          if 'uid' in self.uid:
536            print ( 'ERROR.100.0001: Duplicate uid: %s [%s]' % (i.uid,i._h.title) )
537            self.uid2[i.uid].append( (k,i) )
538          else:
539### create index bx uid.
540            self.uid[i.uid] = i
541
542    self.missingIds = collections.defaultdict( list )
543    self.iref_by_sect = collections.defaultdict( c1 )
544    for k in dreq.keys():
545        for k2 in irefdict.get( k, [] ):
546          n1 = 0
547          n2 = 0
548          for i in dreq[k].items:
549            id2 = i.__dict__.get( k2 )
550            if id2 != '__unset__':
551              sect = i._h.label
552## append attribute name and target  -- item i.uid, attribute k2 reference item id2
553              self.iref_by_uid[ id2 ].append( (k2,i.uid) )
554              self.iref_by_sect[ id2 ].a[sect].append( i.uid )
555              if id2 in self.uid:
556                n1 += 1
557              else:
558                n2 += 1
559                self.missingIds[id2].append( (k,k2,i.uid) )
560          self.info(  'INFO:: %s, %s%s (%s)' % (k,k2,n1,n2) )
561
562    for k in dreq.keys():
563      for i in dreq[k].items:
564        self.__dict__[k].uid[i.uid] = i
565        self.__dict__[k].label[i.label].append( i.uid )
566        if 'sn' in dreq[k].attDefn:
567          self.__dict__[k].sn[i.sn].append( i.uid )
568
569  def info(self,ss):
570    if not self.silent:
571      print ( ss )
572
573class ds(object):
574  def __init__(self,k):
575    self.k = k
576  def cmp(self,x,y):
577    return cmp( x.__dict__[self.k], y.__dict__[self.k] )
578
579src1 = '../workbook/trial_20150831.xml'
580
581#DEFAULT LOCATION -- changed automatically when building distribution
582defaultDreq = 'dreq.xml'
583#DEFAULT CONFIG
584defaultConfig = 'dreq2Defn.xml'
585
586defaultDreqPath = '%s/%s' % (DOC_DIR, defaultDreq )
587defaultConfigPath = '%s/%s' % (DOC_DIR, defaultConfig )
588
589class loadDreq(object):
590  """Load in a vocabulary document.
591  dreqXML: full path to the XML document
592  configdoc: full path to associated configuration document
593  useShelve: flag to specify whether to retrieve data from cache (not implemented)
594  htmlStyles: dictionary of styling directives which influence structure of html page generates by the "makeHtml" method
595"""
596
597  def __init__(self,dreqXML=defaultDreqPath, configdoc=defaultConfigPath, useShelve=False, htmlStyles=None ):
598    self.c = config( thisdoc=dreqXML, configdoc=configdoc, useShelve=useShelve)
599    self.coll = self.c.get()
600    self.inx = index(self.coll)
601    self.defaultItemLineStyle = lambda i, frm='': '<li>%s: %s</li>' % ( i.label, i.__href__(odir='../u/') )
602    self.itemStyles = {}
603##
604## add index to Item base class .. so that it can be accessed by item instances
605##
606    dreqItemBase._inx = self.inx
607    dreqItemBase._indexInitialised = True
608##
609## load in additional styling directives
610##
611    if htmlStyles != None:
612      for k in htmlStyles:
613        dreqItemBase._htmlStyle[k] = htmlStyles[k]
614
615##    dreqItemBase._htmlStyle['__general__'] = {'addRemarks':True}
616
617    self.pageTmpl = """<html><head><title>%s</title>
618<link rel="stylesheet" type="text/css" href="%scss/dreq.css">
619</head><body>
620<div id="top">CMIP6 Data Request</div>
621%s</body></html>"""
622
623  def getHtmlItemStyle(self, sect):
624    if sect in self.itemStyles:
625      return self.itemStyles[sect]
626    return self.defaultItemLineStyle
627
628  def makeHtml(self,odir='./html', ttl0 = 'Data Request Index'):
629    """Generate a html view of the vocabularies, using the "__html__" method of the vocabulary item class to generate a
630page for each item and also generating index pages.
631    odir: directory for html files;
632    ttl0: Title for main index (in odir/index.html)"""
633
634    for k in self.inx.uid.keys():
635      i = self.inx.uid[k]
636      ttl = 'Data Request Record: [%s]%s' % (i._h.label,i.label)
637      bdy = string.join( i.__html__( ghis=self.getHtmlItemStyle ), '\n' )
638      oo = open( '%s/u/%s.html' % (odir,i.uid), 'w' )
639      oo.write( self.pageTmpl % (ttl, '../', bdy ) )
640      oo.close()
641
642    msg0 = ['<h1>%s</h1>' % ttl0, '<ul>',]
643    ks = sorted( self.coll.keys() )
644    for k in ks:
645##
646## sort on item label
647##
648      self.coll[k].items.sort( ds('label').cmp )
649      ttl = 'Data Request Section: %s' % k
650      msg0.append( '<li><a href="index/%s.html">%s [%s]</a></li>\n' % (k,self.coll[k].header.title,k) )
651      msg = ['<h1>%s</h1>\n' % ttl, '<ul>',]
652      msg.append( '<a href="../index.html">Home</a><br/>\n' )
653      lst = self.getHtmlItemStyle(k)
654      for i in self.coll[k].items:
655        ##m = '<li>%s: %s</li>' % ( i.label, i.__href__(odir='../u/') )
656        m = lst( i )
657        msg.append( m )
658      msg.append( '</ul>' )
659      bdy = string.join( msg, '\n' )
660      oo = open( '%s/index/%s.html' % (odir,k), 'w' )
661      oo.write( self.pageTmpl % (ttl, '../', bdy ) )
662      oo.close()
663    msg0.append( '</ul>' )
664    bdy = string.join( msg0, '\n' )
665    oo = open( '%s/index.html' % odir, 'w' )
666    oo.write( self.pageTmpl % (ttl0, '', bdy ) )
667    oo.close()
668   
669if __name__ == '__main__':
670  dreq = loadDreq( )
671
Note: See TracBrowser for help on using the repository browser.