def __exit__(self, *args): if self._clear_called: os.remove(self.filepath) # Delete timer. else: with util.OpenAndLock(self.filepath, 'w') as f: f.write(util.json_dumps(self._timer_obj)) self._enter_called = False
def __enter__(self): # TODO(alive): Should likely hold the file lock throughout the entire `with` # statement. # TODO(alive): Explicitly create timer files. This can cause subtle bugs. self._enter_called = True if not os.path.isfile(self.filepath): self._timer_obj = { 'label': self._label, 'endtime': 0, # This field is 0 when the timer is not running. 'remaining': sys.maxint } with util.OpenAndLock(self.filepath, 'w') as f: f.write(util.json_dumps(self._timer_obj)) else: with util.OpenAndLock(self.filepath, 'r') as f: self._timer_obj = json.load(f) return self
def done_command(label): # TODO(alive): Rewrite with the paradigm used in timer_db.py. # Move this logic into Entry. if not os.path.isfile(_resource_path(label)): util.tlog("No diary entry with label `%s` exists" % label) return with util.OpenAndLock(_resource_path(label), 'r') as f: entry = json.load(f) now = time.time() span = now - entry['epoch'] effective = entry['effective'] # Handle orderings: # 1. __enter__, new, done, __exit__. # 2. new, done, __enter__, __exit__. # 3. __enter__, __exit__, new, done. # # If we are in any of the above orderings AND effective is 0.0, then we # simply set `effective` to `span`. In these cases, there is no interaction # between diary and timer. # # If, however, the first condition is True, but the second is false, then # we must be in case #1 above. The only way for `effective` to be non-zero # here is for the user to have called timer.inc(). This is only possible # if a timer is running, and therefore, cases #2 and #3 are ruled out. The # else block handles this case. if (util.isclose(entry['epoch'], entry['interval_start_time']) and util.isclose(effective, 0.0)): effective = span else: # Handle orderings: # 1. __enter__, new, done, __exit__ (with call to timer.inc()). # 5. new, __enter__, done, __exit__. # Capture the amount of time elapsed after __enter__. timer = timer_db.running_timer() if timer: with timer: if timer.label == label: effective += time.time() - entry['interval_start_time'] if util.isclose(span - effective, 0.0, abs_tol=_TIME_EPSILON): overhead = 0.0 else: overhead = (span - effective) / span click.echo(" Start time: %s" % _format_timestamp(entry['epoch'])) click.echo(" End time: %s" % _format_timestamp(now)) click.echo(" Span (m): %.2f" % (span / 60.0)) click.echo(" Effective (m): %.2f" % (effective / 60.0)) click.echo(" Overhead (%%): %.1f%%" % (overhead * 100.0)) os.remove(_resource_path(label))
def increment_effective(label, delta): if not os.path.isfile(_resource_path(label)): return False with util.OpenAndLock(_resource_path(label), 'r+') as f: entry = json.load(f) entry['effective'] += delta # Can validly result in negative numbers. f.truncate(0) f.seek(0) f.write(util.json_dumps(entry)) return True
def new_command(label): if os.path.isfile(_resource_path(label)): util.tlog("A diary entry with label `%s` already exists" % label) return now = time.time() entry = { 'label': label, 'epoch': now, 'interval_start_time': now, 'effective': 0.0, } with util.OpenAndLock(_resource_path(label), 'w') as f: f.write(util.json_dumps(entry)) util.tlog("diary entry with label `%s` created" % label)
def __exit__(self, *args): """Signals this module that the timer is running on the given label. If a diary entry for the given label exists, this function increments its 'effective' field by (time.time() - interval_start_time). """ if os.path.isfile(_resource_path(self._label)): # TODO(alive): there's a harmless and unlikely race condition here. with util.OpenAndLock(_resource_path(self._label), 'r+') as f: entry = json.load(f) entry['effective'] += time.time( ) - entry['interval_start_time'] f.seek(0) f.truncate(0) f.write(util.json_dumps(entry))
def __enter__(self): """Signals this module that the timer is running on the given label. If a diary entry for the given label exists, this function sets its interval_start_time to the current time. Possible interactions with timer: Trivial orderings (no interaction): In these cases, new and done track all elapsed time. 1. new, done, __enter__, __exit__ 2. __enter__, __exit__, new, done 3. __enter__, new, done, __exit__ In this case, __enter__ and __exit__ track all elapsed time. 4. new, __enter__, __exit__, done Tricky orderings: 5. new, __enter__, done, __exit__ In this case, done captures the amount of time elapsed after __enter__. 6. __enter__, new, __exit__, done In this case, __exit__ captures the amount of time elapsed after new. """ # TODO(alive): rewrite with the paradigm used in timer_db.py. if os.path.isfile(_resource_path(self._label)): # TODO(alive): there's a harmless and unlikely race condition here. with util.OpenAndLock(_resource_path(self._label), 'r+') as f: entry = json.load(f) entry['interval_start_time'] = time.time() f.seek(0) f.truncate(0) f.write(util.json_dumps(entry)) return self