149 lines
4 KiB
Python
149 lines
4 KiB
Python
# -*- coding: utf-8 -*-
|
|
#
|
|
# Copyright 2011 Google Inc. All Rights Reserved.
|
|
#
|
|
"""Tools for recording and reporting timeline of abstract events.
|
|
|
|
You can store any events provided that they can be stringified.
|
|
"""
|
|
|
|
__author__ = 'kbaclawski@google.com (Krystian Baclawski)'
|
|
|
|
import collections
|
|
import datetime
|
|
import time
|
|
|
|
|
|
class _EventRecord(object):
|
|
"""Internal class. Attaches extra information to an event."""
|
|
|
|
def __init__(self, event, time_started=None, time_elapsed=None):
|
|
self._event = event
|
|
self._time_started = time_started or time.time()
|
|
self._time_elapsed = None
|
|
|
|
if time_elapsed:
|
|
self.time_elapsed = time_elapsed
|
|
|
|
@property
|
|
def event(self):
|
|
return self._event
|
|
|
|
@property
|
|
def time_started(self):
|
|
return self._time_started
|
|
|
|
def _TimeElapsedGet(self):
|
|
if self.has_finished:
|
|
time_elapsed = self._time_elapsed
|
|
else:
|
|
time_elapsed = time.time() - self._time_started
|
|
|
|
return datetime.timedelta(seconds=time_elapsed)
|
|
|
|
def _TimeElapsedSet(self, time_elapsed):
|
|
if isinstance(time_elapsed, datetime.timedelta):
|
|
self._time_elapsed = time_elapsed.seconds
|
|
else:
|
|
self._time_elapsed = time_elapsed
|
|
|
|
time_elapsed = property(_TimeElapsedGet, _TimeElapsedSet)
|
|
|
|
@property
|
|
def has_finished(self):
|
|
return self._time_elapsed is not None
|
|
|
|
def GetTimeStartedFormatted(self):
|
|
return time.strftime('%m/%d/%Y %H:%M:%S', time.gmtime(self._time_started))
|
|
|
|
def GetTimeElapsedRounded(self):
|
|
return datetime.timedelta(seconds=int(self.time_elapsed.seconds))
|
|
|
|
def Finish(self):
|
|
if not self.has_finished:
|
|
self._time_elapsed = time.time() - self._time_started
|
|
|
|
|
|
class _Transition(collections.namedtuple('_Transition', ('from_', 'to_'))):
|
|
"""Internal class. Represents transition point between events / states."""
|
|
|
|
def __str__(self):
|
|
return '%s => %s' % (self.from_, self.to_)
|
|
|
|
|
|
class EventHistory(collections.Sequence):
|
|
"""Records events and provides human readable events timeline."""
|
|
|
|
def __init__(self, records=None):
|
|
self._records = records or []
|
|
|
|
def __len__(self):
|
|
return len(self._records)
|
|
|
|
def __iter__(self):
|
|
return iter(self._records)
|
|
|
|
def __getitem__(self, index):
|
|
return self._records[index]
|
|
|
|
@property
|
|
def last(self):
|
|
if self._records:
|
|
return self._records[-1]
|
|
|
|
def AddEvent(self, event):
|
|
if self.last:
|
|
self.last.Finish()
|
|
|
|
evrec = _EventRecord(event)
|
|
self._records.append(evrec)
|
|
return evrec
|
|
|
|
def GetTotalTime(self):
|
|
if self._records:
|
|
total_time_elapsed = sum(evrec.time_elapsed.seconds
|
|
for evrec in self._records)
|
|
|
|
return datetime.timedelta(seconds=int(total_time_elapsed))
|
|
|
|
def GetTransitionEventHistory(self):
|
|
records = []
|
|
|
|
if self._records:
|
|
for num, next_evrec in enumerate(self._records[1:], start=1):
|
|
evrec = self._records[num - 1]
|
|
|
|
records.append(_EventRecord(
|
|
_Transition(evrec.event, next_evrec.event), evrec.time_started,
|
|
evrec.time_elapsed))
|
|
|
|
if not self.last.has_finished:
|
|
records.append(_EventRecord(
|
|
_Transition(self.last.event,
|
|
'NOW'), self.last.time_started, self.last.time_elapsed))
|
|
|
|
return EventHistory(records)
|
|
|
|
@staticmethod
|
|
def _GetReport(history, report_name):
|
|
report = [report_name]
|
|
|
|
for num, evrec in enumerate(history, start=1):
|
|
time_elapsed = str(evrec.GetTimeElapsedRounded())
|
|
|
|
if not evrec.has_finished:
|
|
time_elapsed.append(' (not finished)')
|
|
|
|
report.append('%d) %s: %s: %s' % (num, evrec.GetTimeStartedFormatted(),
|
|
evrec.event, time_elapsed))
|
|
|
|
report.append('Total Time: %s' % history.GetTotalTime())
|
|
|
|
return '\n'.join(report)
|
|
|
|
def GetEventReport(self):
|
|
return EventHistory._GetReport(self, 'Timeline of events:')
|
|
|
|
def GetTransitionEventReport(self):
|
|
return EventHistory._GetReport(self.GetTransitionEventHistory(),
|
|
'Timeline of transition events:')
|