00001
00002 from ccsv import ccsv_parse
00003 import os
00004
00005 class Tab(list):
00006 """
00007 :class:`DybDbiPre.Tab` instances are created by the parsing of :file:`.spec` files (:dybgaudi:`Database/DybDbi/spec`).
00008 Instances contain a list of dicts corresponding to each payload row in the DBI table together
00009 with a metadata dictionary for class level information.
00010
00011 To test the parsing of a :file:`.spec` file, use for example::
00012
00013 cat $DYBDBIROOT/spec/GSimPmtSpec.spec | python $DYBDBIPREROOT/python/DybDbiPre/__init__.py
00014
00015 The instances are available in the django context used to fill templates
00016 :dybgaudi:`Database/DybDbi/templates` used in the generation of:
00017
00018 #. DbiTableRow subclasses allowing DBI to interact with the table
00019 #. Documentation presenting the DBI tables in :file:`.tex` and wiki formats
00020 #. SQL scripts for table creation :file:`.sql`
00021
00022 The meanings of the quantities in the :file:`.spec` are ultimately determined by their usage
00023 in the templates, however some guideline definitions are listed below:
00024
00025 .. rubric:: row level quantities
00026
00027 name
00028 column name as used in C++ getter and setter methods
00029 dbtype
00030 MySQL column type name used in table description, such as `double` or `int(10) unsigned`
00031 codetype
00032 type used in generated C++ code, eg `DayaBay::FeeChannelId`
00033 legacy
00034 name of the column in database table
00035 description
00036 short definition of the meaning of the column
00037 code2db
00038 C++ converter function used to translate a value in code into a value stored in the DB, eg `.fullPackedData()`
00039 memb
00040 name of the column data member in the C++ table row class, **WARNING, CURRENTLY NOT IN USE**
00041
00042
00043 .. rubric:: class/table level properties
00044
00045 meta
00046 a token that identifies the key, value pairs on the line as metadata rather than a table row
00047 table
00048 name of the payload Database table, eg `CalibFeeSpec`
00049 class
00050 name of the generated DbiTableRow class, follow convention of naming with a **G** prefix eg `GCalibFeeSpec`
00051 CanL2Cache
00052 set to `kFALSE`, L2 caching is for debugging only
00053 legacy
00054 name of prior table when migrations are performed, **WARNING, CURRENTLY NOT IN USE**, set to table name
00055 rctx
00056 default read context represented by a comma delimited string, see :dybgaudi:`Database/DybDbi/src/DbiCtx.cxx`
00057 wctx
00058 default write context range represented by a comma delimited string, see :dybgaudi:`Database/DybDbi/src/DbiCtx.cxx`
00059
00060
00061 .. rubric:: usage in templates
00062
00063 The class level and row level quantities are used in django templates with expressions of the form::
00064
00065 {{ t.meta.table }}
00066
00067 {% for r in t %}`{{ r.name }}` {{ r.dbtype }} default NULL COMMENT '{{ r.description }}',
00068
00069
00070 """
00071 def __init__(self):
00072 self.meta = {}
00073
00074 def __repr__(self):
00075 return "\n".join([repr(self.meta),list.__repr__(self)])
00076
00077 def _extras(self):
00078 """
00079 Extras property dict is updated into the context providing handy shortcuts
00080 """
00081 verbose = int(os.environ.get('VERBOSE', 0 ))
00082 debug = verbose > 0
00083 return dict(cls=self.meta.get('class','ErrorNoClass'),kls=self.meta.get('legacy','ErrorNoLegacy'),f=self.meta.get('prefix','m_'),debug=debug)
00084 extras = property( _extras , doc=_extras.__doc__ )
00085
00086 def _docstring(self):
00087 return self.docs.split("\n")
00088 docstring = property( _docstring )
00089
00090 def __call__(self, d ):
00091 """
00092 If fields in the :file:`.spec` file include a "meta" key then the
00093 fieldname(ie key),value pairs are included into the meta dictionary
00094 """
00095 if d.has_key('meta'):
00096 self.meta.update(d)
00097 else:
00098 self.append(d)
00099
00100
00101 class Enum(list):
00102 def __init__(self, *args ):
00103 list.__init__( self, *args )
00104 self.extras = dict( cls="Ctx", template_object_name="l" )
00105
00106 """
00107 Parsers provides interface required by FillTmpl
00108 ... a callable class that returns list of dicts like object
00109 """
00110 class Parser:
00111 def __call__(self, src ):
00112 t = Tab()
00113 p = ccsv_parse( src.read() )
00114 for d in p:
00115 t(d)
00116 t.docs = p.docs if hasattr(p,'docs') else ""
00117
00118
00119 return t
00120
00121 class EnumParser:
00122 def __call__(self, src ):
00123 return Enum( map(lambda x:x.strip(), src.readlines() ) )
00124
00125
00126 if __name__=='__main__':
00127 import sys
00128 arg = len(sys.argv) > 1 and sys.argv[1] or None
00129
00130 if arg == "enum":
00131 print EnumParser()(sys.stdin)
00132 else:
00133 print Parser()(sys.stdin)