Source code for default_profile.util.timer

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
===================================
Timer --- Create a timer decorator.
===================================

Largely this module was simply practice on writing decorators.

Might need to review logging best practices. I don't want the logger from
this module to emit anything, but it seems tedious to place that burden
on any module that imports from here.

.. seealso::

    :mod:`cProfile`
    :mod:`pstats`
    :mod:`timeit`
    :magic:`timeit`

"""
import datetime
import functools
import logging
from os import scandir
from runpy import run_path
import time
from timeit import Timer

from IPython.core.getipython import get_ipython

# noinspection PyProtectedMember
from IPython.core.magics.execution import _format_time as format_delta

logging.basicConfig(level=logging.INFO)


[docs]def timer(func): """Print the runtime of the decorated function. Utilizes `time.perf_counter`. .. todo:: Begin using the :mod:`timeit` module. There are more specialized ways of profiling things in other modules; however, this works for a rough estimate. Parameters ---------- func : function Function to profile Returns ------- value : float Output of function :func:`time.perf_counter()`. """ @functools.wraps(func) def wrapper_timer(*args, **kwargs): start_time = time.perf_counter() value = func(*args, **kwargs) end_time = time.perf_counter() run_time = end_time - start_time logging.info(f"Finished {func.__name__!r} in {run_time:.4f} secs") return value return wrapper_timer
# class ModuleTimer() # I mean while we're practicing decorators throw this in the mix
[docs]def debug(func): """Print the function signature and return value""" @functools.wraps(func) def wrapper_debug(*args, **kwargs): args_repr = [repr(a) for a in args] # 1 kwargs_repr = [f"{k}={v!r}" for k, v in kwargs.items()] # 2 signature = ", ".join(args_repr + kwargs_repr) # 3 print(f"Calling {func.__name__}({signature})") value = func(*args, **kwargs) print(f"{func.__name__!r} returned {value!r}") # 4 return value return wrapper_debug
[docs]def exc_timer(statement, setup=None): """A non-decorator implementation that uses `timeit`.""" t = Timer(stmt=statement, setup=setup) # outside the try/except try: return t.timeit() except Exception: # noqa E722 t.print_exc()
[docs]class ArgReparser: """Class decorator that echoes out the arguments a function was called with."""
[docs] def __init__(self, func): """Initialize the reparser with the function it wraps.""" self.func = func
def __call__(self, *args, **kwargs): print("entering function " + self.func.__name__) i = 0 for arg in args: print("arg {0}: {1}".format(i, arg)) i = i + 1 return self.func(*args, **kwargs)
[docs]def time_dir(directory=None): """How long does it take to exec(compile(file)) every file in the startup dir?""" if directory is None: directory = get_ipython().startup_dir result = [] for i in scandir("."): if i.name.endswith(".py"): file = i.name print(file) print(time.time()) start_time = time.time() exec(compile(open(file).read(), "timer", "exec")) end = time.time() diff = end - start_time print(f"{diff}") result.append((file, diff)) return result
[docs]class LineWatcher: """Class that implements a basic timer. Registers the `start` and `stop` methods with the IPython events API. """
[docs] def __init__(self): """Define the classes start_time parameter.""" self.start_time = self.start()
[docs] def start(self): """Return `time.time`.""" return time.time()
def __repr__(self): return f"{self.__class__.__name__} {self.start_time}"
[docs] def stop(self): """Determine the difference between start time and end time.""" stop_time = time.time() diff = abs(stop_time - self.start_time) print("time: {}".format(format_delta(diff))) return diff
[docs]def load_ipython_extension(ip=None, line_watcher=None): """Initialize a `LineWatcher` and register start and stop with IPython.""" if ip is None: ip = get_ipython() if ip is None: return if line_watcher is None: line_watcher = LineWatcher() ip.events.register("pre_run_cell", line_watcher.start) ip.events.register("post_run_cell", line_watcher.stop)
[docs]def unload_ipython_extension(ip=None, line_watcher=None): if ip is None: ip = get_ipython() if ip is None: return if line_watcher is None: line_watcher = LineWatcher() ip.events.unregister("pre_run_cell", line_watcher.start) ip.events.unregister("post_run_cell", line_watcher.stop)