flowy/record.py
2010-11-05 18:57:01 +01:00

165 lines
5.7 KiB
Python

"""
This module provides methods for dynamically creating flow and
group record classes.
"""
def get_record_class(attributes, types=None, default_vals=None):
'''
Creates a record class for given attribute names.
Arguments:
attributes - a sequence of attribute names
types - optional sequence of attribute types, which
correspond to the attribute names in attributes.
Types may be of any type, and are not used by the
Record class, but are useful for external storage,
where data type has to be predetermined.
default_val - a sequence of default values which
correspond to the attribute names in attributes
Lists are used instead of dictionaries because the order
may be important.
Return:
Record class which has attributes with the names given
by attributes list. The class uses __slots__ to lower
memory usage as potentially millions of instance will
be present during runtime. The class has a constructor,
which takes as argument values for the attributes ordered
the same way as in the attributes list. If default values
are specified there is a default(no argument) constructor
as well.
NOTE that this method returns a class not an instance.
Raises:
ValueError if number of types or default values doesn't
match number of attributes.
'''
if default_vals and len(attributes) != len(default_vals):
raise ValueError(
"Number of attributes(%d) and number of default values(%d)"%
(len(attributes),len(default_vals))+" don't match")
if types and len(attributes) != len(types):
raise ValueError(
"Number of attributes(%d) and number of default types(%d)"%
(len(attributes),len(default_vals))+" don't match")
elif types:
types_dict = dict(zip(attributes, types))
else:
types_dict = {}
class Record(object):
'''
Record class contains flow or group record information.
It uses __slots__ to save memory because potentially millions of
FlowRecords will be used during run time.
Attributes:
attribute names are specified in cls.__slots__
defaults - contains the default values for attributes used
with default constructor.
attr_types - contains a dictionary of the types of
the attributes.
Methods:
__init__ - when defaults is specified __init__()
creates an object with default values. If no
defaults are specified during class creation
__init__() raises TypeError.
__init__(*args) takes exactly the same number
of arguments as the classes' number of attributes,
and creates new instance with the given values.
Argument order corresponds to the order of
attributes in cls.__slots__
'''
# set slots to conserve memory
# copy ([:]) don't reference to protect from unexpected changes
__slots__ = attributes[:]
attr_types = types_dict
num_of_fields = len(__slots__)
defaults = default_vals[:] if default_vals else None
def __init__(self, *args):
num_args = len(args)
if num_args == self.num_of_fields:
for name, value in zip(self.__slots__,args):
setattr(self, name, value)
elif num_args == 0 and self.defaults != None:
for name, value in zip(self.__slots__,self.defaults):
setattr(self, name, value)
elif self.defaults == None:
raise TypeError(
"__init__() takes %d arguments (%d given)"%
( self.num_of_fields + 1, num_args+1))
else:
raise TypeError(
"__init__() takes either 1 or %d arguments (%d given)"%
( self.num_of_fields + 1, num_args+1))
def tuple(self):
return tuple(getattr(self, field) for field in self.slots)
def __repr__(self):
res = "Recod("
for field in self.__slots__:
val = getattr(self, field)
if type(val) is str:
val = "'" + str(val) + "'"
else:
val = str(val)
res += val + ", "
res =res[:-2] + ")"
return res
def __str__(self):
res = "Recod: "
for field in self.__slots__:
val = getattr(self, field)
res += field + "->" + str(val) + ", "
res =res[:-2]
return res
return Record
class RecordReader(object):
def __init__(self, reader_object):
self.reader = reader_object
#print self.reader.fields
self.Record = get_record_class(self.reader.fields)
def __iter__(self):
for tuple in self.reader:
yield self.Record(*tuple)
def read_rows_list(self, rows_list):
for tuple in self.reader.read_rows_list(rows_list):
yield self.Record(*tuple)
def read_row(self, row_n):
tup = self.reader.read_row(row_n)
return self.Record(*tup)
#from flowy import pytables
#ptread = pytables.FlowRecordsTable("../testFT.h5" )
#rr = RecordReader(ptread)
#for i in rr:
# print i.dOctets
#
#
#FlowRecord = get_record_class(["a","b"],["str","uint"],[1,6])
#
#def printSth(self):
# print "sth"
#
#FlowRecord.p = printSth
#
#x = FlowRecord(1,6)
#
#
#print x.a, x.b
#print x.__slots__
#
#t = FlowRecord()
#print t.a
#t.p()