ilog.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 # -*- Python -*-
00003 # -*- coding: utf-8 -*-
00004 
00005 '''rtshell
00006 
00007 Copyright (C) 2009-2014
00008     Geoffrey Biggs
00009     RT-Synthesis Research Group
00010     Intelligent Systems Research Institute,
00011     National Institute of Advanced Industrial Science and Technology (AIST),
00012     Japan
00013     All rights reserved.
00014 Licensed under the Eclipse Public License -v 1.0 (EPL)
00015 http://www.opensource.org/licenses/eclipse-1.0.txt
00016 
00017 Log interface.
00018 
00019 '''
00020 
00021 
00022 import sys
00023 
00024 
00025 ###############################################################################
00026 ## Log exceptions.
00027 
00028 class EndOfLogError(EOFError):
00029     '''The end of the log has been reached while reading.'''
00030     pass
00031 
00032 
00033 class InvalidIndexError(EOFError):
00034     '''An invalid index was requested.'''
00035     pass
00036 
00037 
00038 ###############################################################################
00039 ## Entry timestamps
00040 
00041 class EntryTS(object):
00042     def __init__(self, sec=0, nsec=0, time=None):
00043         super(EntryTS, self).__init__()
00044         if time is not None:
00045             self._sec, self._nsec = self._get_values(time)
00046         else:
00047             self._sec = sec
00048             self._nsec = nsec
00049 
00050     def __repr__(self):
00051         return 'EntryTS(_sec={0}, _nsec={1})'.format(self._sec, self._nsec)
00052 
00053     def __str__(self):
00054         return '{0}.{1:09}'.format(self._sec, self._nsec)
00055 
00056     def __lt__(self, other):
00057         sec, nsec = self._get_values(other)
00058         if self._sec < sec:
00059             return True
00060         elif self._sec == sec:
00061             if self._nsec < nsec:
00062                 return True
00063         return False
00064 
00065     def __le__(self, other):
00066         sec, nsec = self._get_values(other)
00067         if self._sec < sec:
00068             return True
00069         elif self._sec == sec:
00070             if self._nsec <= nsec:
00071                 return True
00072         return False
00073 
00074     def __eq__(self, other):
00075         sec, nsec = self._get_values(other)
00076         if self._sec == sec and self._nsec == nsec:
00077             return True
00078         return False
00079 
00080     def __ne__(self, other):
00081         sec, nsec = self._get_values(other)
00082         if self._sec != sec or self._nsec != nsec:
00083             return True
00084         return False
00085 
00086     def __gt__(self, other):
00087         sec, nsec = self._get_values(other)
00088         if self._sec > sec:
00089             return True
00090         elif self._sec == sec:
00091             if self._nsec > nsec:
00092                 return True
00093         return False
00094 
00095     def __ge__(self, other):
00096         sec, nsec = self._get_values(other)
00097         if self._sec > sec:
00098             return True
00099         elif self._sec == sec:
00100             if self._nsec >= nsec:
00101                 return True
00102         return False
00103 
00104     @property
00105     def float(self):
00106         '''Get the time value as a float.'''
00107         return float(self._sec) + float(self._nsec) / 1e9
00108 
00109     @property
00110     def sec(self):
00111         return self._sec
00112 
00113     @sec.setter
00114     def sec(self, sec):
00115         self._sec = sec
00116 
00117     @property
00118     def nsec(self):
00119         return self._nsec
00120 
00121     @nsec.setter
00122     def nsec(self, nsec):
00123         self._nsec = nsec
00124 
00125     def _get_values(self, other):
00126         if type(other) == EntryTS:
00127             return other.sec, other.nsec
00128         else:
00129             return int(other), int((other * 1000000000) % 1000000000)
00130 
00131 
00132 ###############################################################################
00133 ## Log interface. All loggers must conform to this.
00134 
00135 class Log(object):
00136     def __init__(self, mode='r', meta=None, verbose=False, *args, **kwargs):
00137         '''Base constructor.
00138 
00139         The log will be opened on construction. It should be closed manually,
00140         as Python does not guarantee that __del__() will be called.
00141 
00142         @param mode Permissions. Specificy 'r' for read, 'w' for write or 'rw'
00143                     for read/write. Not all logs support all permissions.
00144                     Read/write permissions are particularly uncommon.
00145         @param meta A block of data to write into the log. Implementations
00146                     are free to deal with this any way they wish, as long as it
00147                     can be retrieved in read mode. However, there is no
00148                     requirement that it can be changed after opening the log
00149                     for writing. Users should set it before opening the log.
00150         @param verbose Print verbose output to stderr.
00151 
00152         '''
00153         super(Log, self).__init__()
00154         self._mode = mode
00155         self._meta = meta
00156         self._vb = verbose
00157         self.open()
00158 
00159     def __del__(self):
00160         self.close()
00161 
00162     def __enter__(self):
00163         return self
00164 
00165     def __exit__(self, exc_type, exc_val, exc_tb):
00166         if exc_type == None:
00167             self.close(finalise=True)
00168         else:
00169             self.close(finalise=False)
00170         return False
00171 
00172     def __iter__(self):
00173         return self
00174 
00175     def next(self):
00176         d = self.read()
00177         if not d:
00178             raise StopIteration
00179         return d[0]
00180 
00181     def __str__(self):
00182         return 'Log interface object.'
00183 
00184     @property
00185     def end(self):
00186         '''The position of the final entry in the log.
00187 
00188         A tuple of (index, timestamp).
00189 
00190         '''
00191         return self._get_end()
00192 
00193     @property
00194     def eof(self):
00195         '''True if the log has reached the end.'''
00196         return self._eof()
00197 
00198     @property
00199     def metadata(self):
00200         '''Return the metadata from the log (if any).'''
00201         return self._meta
00202 
00203     @metadata.setter
00204     def metadata(self, metadata):
00205         self._meta = metadata
00206 
00207     @property
00208     def mode(self):
00209         '''The mode of the log.'''
00210         return self._mode
00211 
00212     @property
00213     def name(self):
00214         '''The name of the log.'''
00215         return self._name
00216 
00217     @property
00218     def pos(self):
00219         '''The current position in the log.
00220 
00221         A tuple of (index, timestamp).
00222 
00223         This points at the current position - i.e. the entry most recently
00224         read.
00225 
00226         '''
00227         return self._get_cur_pos()
00228 
00229     @property
00230     def start(self):
00231         '''The position of the first entry in the log.
00232 
00233         A tuple of (index, timestamp).
00234 
00235         '''
00236         return self._get_start()
00237 
00238     def open(self):
00239         '''Opens the log.'''
00240         self._open()
00241 
00242     def finalise(self):
00243         '''Prepare the log to be closed.
00244 
00245         Any cleaning up that needs to be done before closing the log should
00246         be done here.
00247 
00248         This function is called just before closing the log by @ref close.
00249         If using the context manager statement (the 'with' statement), it will
00250         be called automatically, unless an exception has occured.
00251 
00252         It is not required for objects implementing the Log interface to
00253         implement this function.
00254 
00255         '''
00256         self._finalise()
00257 
00258     def close(self, finalise=True):
00259         '''Closes the log.
00260 
00261         @param finalise Whether the log should be finalised before closing.
00262                         Defaults to True.
00263 
00264         '''
00265         if finalise:
00266             self.finalise()
00267         self._close()
00268 
00269     def write(self, timestamp, data):
00270         '''Writes an entry to the log.
00271 
00272         The timestamp is necessary to allow reading back data at the
00273         same rate as it was recorded. It must be an object that
00274         supports comparisons using <, <=, =, >= and >. ilog.EntryTS
00275         provides a suitable object.
00276 
00277         '''
00278         raise NotImplementedError
00279 
00280     def read(self, timestamp=None, number=None):
00281         '''Read entries from the log.
00282 
00283         If a time limit is given, all entries until that time limit is
00284         reached will be read.
00285 
00286         If a number is given, that number of entries will be returned.
00287         This option overrides the time limit option.
00288 
00289         If EOF is hit before the requested entries are read, what was
00290         read will be returned and @ref eof will return True.
00291 
00292         If neither option is given, the next value will be returned.
00293 
00294         Returns a list of tuples, [(index, timestamp, data), ...].
00295 
00296         '''
00297         raise NotImplementedError
00298 
00299     def rewind(self):
00300         '''Rewind the log to the first entry.'''
00301         raise NotImplementedError
00302 
00303     def seek(self, timestamp=None, index=None):
00304         '''Rewind or fast-forward the log.
00305 
00306         If the timestamp or index is earlier than the current position, the log
00307         will be rewound. If it is later, the log will be fast-forwarded.
00308 
00309         When the log is rewound, it will go back to the first entry before
00310         the given timestamp or index. If an entry exactly matches the given
00311         timestamp or index, the log position will be at that entry, meaning
00312         that the next value read will be that entry.
00313 
00314         When a log is fast-forwarded, it will go to the first entry after the
00315         given timestamp or index. If an entry exactly matches the given
00316         timestamp or index, the log position will be at that entry, meaning
00317         that the next value read will be that entry.
00318 
00319         '''
00320         raise NotImplementedError
00321 
00322     def _close(self):
00323         raise NotImplementedError
00324 
00325     def _eof(self):
00326         return True
00327 
00328     def _finalise(self):
00329         pass
00330 
00331     def _get_cur_pos(self):
00332         '''Get the current position in the log.
00333 
00334         Should be implemented by implementation objects. Called by the
00335         @ref position property.
00336 
00337         '''
00338         raise NotImplementedError
00339 
00340     def _get_start(self):
00341         '''Get the position of the first entry in the log.
00342 
00343         Should be implemented by implementation objects. Called by the
00344         @ref start property.
00345 
00346         '''
00347         raise NotImplementedError
00348 
00349     def _get_end(self):
00350         '''Get the position of the last entry in the log.
00351 
00352         Should be implemented by implementation objects. Called by the
00353         @ref end property.
00354 
00355         '''
00356         raise NotImplementedError
00357 
00358     def _open(self):
00359         raise NotImplementedError
00360 
00361     def _vb_print(self, string):
00362         '''Print verbose information when self._vb is True.'''
00363         if self._vb:
00364             print >>sys.stderr, string
00365 


rtshell
Author(s): Geoffrey Biggs
autogenerated on Fri Aug 28 2015 12:55:12