00001 import pprint, types
00002
00003 def RPT__del__(self):
00004 self.Delete()
00005
00006 def RPT__getitem__( self, i ):
00007 l = self.__len__()
00008 if isinstance( i , types.SliceType ):
00009 start, stop, step = i.start or 0, i.stop or l , i.step or 1
00010 if start < 0 and start >= -l:
00011 start += l
00012 if stop < 0 and stop >= -l:
00013 stop += l
00014 return [self.__getitem__(ii) for ii in range(start, stop, step )]
00015 elif isinstance( i , int ):
00016 if not(-l <= i < l):
00017 raise IndexError("out of range for index %d" % i )
00018 if i < 0:
00019 i += l
00020 return self.GetRow(i)
00021 else:
00022 raise TypeError("indexing expects a slice or integer ")
00023
00024 def RPT(cls):
00025 """
00026 Application of function RPT to DbiRpt<T> classes
00027 provides instances of that class with a list-like
00028 interface supporting access by index and slice,
00029 indices can be negative to provide access to the end.::
00030
00031
00032 r[0] first
00033 r[-1] last
00034
00035 r[0:9] first 10
00036 r[-3:] last 3
00037
00038
00039 r[0:2000:500]
00040 r[-10:-1:2] 2-step thru the last 10
00041
00042 for x in r[2540:]:
00043 print x
00044
00045 for x in r[-10:]:
00046 print x
00047
00048 THOUGHTS :
00049 * no need for generator implementation for large result set as already all in memory anyhow
00050
00051 """
00052 cls.__len__ = cls.GetNumRows
00053 cls.__getitem__ = RPT__getitem__
00054 cls.__del__ = RPT__del__
00055 cls.__skip__ = "Row RowByIndex".split()
00056 cls.vrec = property( cls.GetValidityRec )
00057
00058
00059
00060
00061 def _create(cls, *args, **kwargs):
00062 """
00063 Provide pythonic instance creation classmethod::
00064
00065 i = GCalibPmtSpec.Create( DarkRate=100. , ... )
00066
00067 doc from func
00068 """
00069 instance = cls(*args)
00070 for k,v in kwargs.items():
00071 Set = getattr(cls,'Set%s'%k, None)
00072 if Set:
00073 Set( instance, v )
00074 else:
00075 raise Exception("no such attribute %s", v )
00076 return instance
00077
00078
00079 class Wrap(object):
00080 """
00081 Control center for application of generic class manipulations based on the names of
00082 methods in contained kls. The manipulations do not require the classes to be imported into this scope.
00083
00084 Wrapping is applied to:
00085
00086 * all `genDbi` generated `DbiTableRow` subclasses and corresponding templated `DbiRpt` and `DbiWrt` (readers and writers)
00087 * a selection of other Dbi classes that are useful interactively
00088
00089
00090 """
00091 def wrap(cls, kls, attfn={}):
00092 w = Wrap(kls,attfn)
00093 return w()
00094 wrap = classmethod(wrap)
00095
00096 def __init__(self, kls, attfn={} ):
00097 self.kls = kls
00098 self.attfn = attfn
00099
00100 getters = property( lambda self:[g[3:] for g in dir(self.kls) if g.startswith('Get') and len(g)>3 ] )
00101 setters = property( lambda self:[s[3:] for s in dir(self.kls) if s.startswith('Set') and len(s)>3 ] )
00102 getset = property( lambda self:list(set(self.getters).intersection(set(self.setters))))
00103 onlyget = property( lambda self:list(set(self.getters).difference(set(self.setters))))
00104 skips = property( lambda self:getattr( self.kls, '__skip__',() ))
00105 isrpt = property( lambda self:self.kls.__name__.startswith("DbiRpt") )
00106 isdtr = property( lambda self:self.kls.__name__.startswith("G") )
00107
00108 def get_attfn( self, m ):
00109 """Returns function than when applied to an object returns (m,obj.Get<m>() ) where m is the attribute name """
00110 return self.attfn.get(m, lambda obj:(m,getattr(obj,'Get%s'%m)()) )
00111 attrs = property( lambda self:[g for g in self.getters if g not in self.skips])
00112 attfs = property(lambda self:map(lambda m:self.get_attfn(m),self.attrs))
00113
00114
00115 def __call__(self):
00116 self.define_properties()
00117 self.define__repr__()
00118 self.define_listlike()
00119 if self.isdtr:
00120 self.define_create()
00121 self.define_asdict()
00122 self.define_update()
00123 self.define_keys()
00124 self.define_csv()
00125 return self
00126
00127 def define_listlike( self):
00128 if self.isrpt:
00129 RPT(self.kls)
00130 define_listlike.__doc__ = RPT.__doc__
00131
00132 def define_properties( self ):
00133 """
00134 Define properties corresponding to Get* and Set* methods
00135 in the contained kls, providing attribute style access and setting ::
00136
00137 g = i.x
00138 i.x = s
00139
00140 NB "getters" which take arguments GetWithArg(Int_t naughty) have to be skipped via::
00141
00142 cls.__skip__ = ("WithArg",)
00143
00144 """
00145 for m in filter(lambda m:m not in self.skips,self.getset):
00146 setattr( self.kls, m.lower() , property( getattr(self.kls, 'Get%s' % m ), getattr( self.kls, 'Set%s' % m ) ) )
00147 for m in filter(lambda m:m not in self.skips,self.onlyget):
00148 setattr( self.kls, m.lower() , property( getattr(self.kls, 'Get%s' % m ) ) )
00149
00150 def make__repr__(self):
00151 """
00152 Provide a default `__repr__` function that presents the attribute names and values as a dict
00153 """
00154 def __repr__(iself):
00155 return "\n".join([ iself.__class__.__name__, "%s" % pprint.pformat( dict( [attf(iself) for attf in self.attfs ]) , indent=4) ])
00156 return __repr__
00157
00158 def define__repr__( self ):
00159 """
00160 Assign default repr ... override later if desired
00161 """
00162 if hasattr(self.kls,'AsString'):
00163 self.kls.__repr__ = getattr(self.kls, 'AsString')
00164 else:
00165 self.kls.__repr__ = self.make__repr__()
00166
00167 def define_create( self):
00168 self.kls.Create = classmethod(_create)
00169 define_create.__doc__ = _create.__doc__
00170
00171 def define_update( self):
00172 """
00173 Provide dict like updating for DbiTableRow subclasses, eg::
00174
00175 from DybDbi import GCalibPmtSpec
00176 r = GCalibPmtSpec.Rpt()
00177 z = r[0]
00178 print z.asdict
00179 print z.keys
00180 z.update( Status=10 )
00181
00182 """
00183 def _update(iself, **kwargs):
00184 for k,v in kwargs.items():
00185 Set = getattr(self.kls,'Set%s'%k, None)
00186 if Set:
00187 Set( iself, v )
00188 else:
00189 raise AttributeError("no such attribute %s" % k )
00190 self.kls.update = _update
00191
00192 def define_keys( self):
00193 def _keys(iself):
00194 return filter(lambda m:m not in self.skips,self.getset)
00195 setattr( self.kls, 'keys' , property( _keys ) )
00196
00197 def define_asdict( self):
00198 def _asdict(iself):
00199 d = {}
00200 for m in filter(lambda m:m not in self.skips,self.getset):
00201 d[m] = getattr( self.kls, 'Get%s' % m )(iself)
00202 return d
00203 setattr( self.kls, 'asdict' , property( _asdict ) )
00204
00205
00206 def define_csv(self):
00207 """
00208 Provide csv manipulations as classmethods on the Row classes
00209 """
00210 import csv_tools
00211 self.kls.csv_check = classmethod( csv_tools.csv_check )
00212 self.kls.csv_import = classmethod( csv_tools.csv_import )
00213 self.kls.csv_export = classmethod( csv_tools.csv_export )
00214 self.kls.csv_compare = classmethod( csv_tools.csv_compare )
00215
00216
00217
00218 if __name__=='__main__':
00219 from dummy import Dummy
00220 wd = Wrap(Dummy)()
00221
00222 d = Dummy()
00223 print d.state()
00224 print d
00225 d.a = "hello a set via property "
00226 d.b = "hello b set via property "
00227 print d
00228
00229
00230