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

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

Trace put in for missing dict

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