Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion codetiming/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""A flexible, customizable timer for your Python code
"""A flexible, customizable timer for your Python code.

You can use `codetiming.Timer` in several different ways:

Expand Down
14 changes: 7 additions & 7 deletions codetiming/_timer.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Definition of Timer
"""Definition of Timer.

See help(codetiming) for quick instructions, and
https://pypi.org/project/codetiming/ for more details.
Expand All @@ -16,12 +16,12 @@


class TimerError(Exception):
"""A custom exception used to report errors in use of Timer class"""
"""A custom exception used to report errors in use of Timer class."""


@dataclass
class Timer(ContextDecorator):
"""Time your code using a class, context manager, or decorator"""
"""Time your code using a class, context manager, or decorator."""

timers: ClassVar[Timers] = Timers()
_start_time: Optional[float] = field(default=None, init=False, repr=False)
Expand All @@ -31,14 +31,14 @@ class Timer(ContextDecorator):
last: float = field(default=math.nan, init=False, repr=False)

def start(self) -> None:
"""Start a new timer"""
"""Start a new timer."""
if self._start_time is not None:
raise TimerError("Timer is running. Use .stop() to stop it")

self._start_time = time.perf_counter()

def stop(self) -> float:
"""Stop the timer, and report the elapsed time"""
"""Stop the timer, and report the elapsed time."""
if self._start_time is None:
raise TimerError("Timer is not running. Use .start() to start it")

Expand All @@ -65,10 +65,10 @@ def stop(self) -> float:
return self.last

def __enter__(self) -> "Timer":
"""Start a new timer as a context manager"""
"""Start a new timer as a context manager."""
self.start()
return self

def __exit__(self, *exc_info: Any) -> None:
"""Stop the context manager timer"""
"""Stop the context manager timer."""
self.stop()
26 changes: 13 additions & 13 deletions codetiming/_timers.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Dictionary-like structure with information about timers"""
"""Dictionary-like structure with information about timers."""

# Standard library imports
import collections
Expand All @@ -14,63 +14,63 @@


class Timers(UserDict):
"""Custom dictionary that stores information about timers"""
"""Custom dictionary that stores information about timers."""

def __init__(self, *args: Any, **kwargs: Any) -> None:
"""Add a private dictionary keeping track of all timings"""
super().__init__(*args, **kwargs)
self._timings: Dict[str, List[float]] = collections.defaultdict(list)

def add(self, name: str, value: float) -> None:
"""Add a timing value to the given timer"""
"""Add a timing value to the given timer."""
self._timings[name].append(value)
self.data.setdefault(name, 0)
self.data[name] += value

def clear(self) -> None:
"""Clear timers"""
"""Clear timers."""
self.data.clear()
self._timings.clear()

def __setitem__(self, name: str, value: float) -> None:
"""Disallow setting of timer values"""
"""Disallow setting of timer values."""
raise TypeError(
f"{self.__class__.__name__!r} does not support item assignment. "
"Use '.add()' to update values."
)

def apply(self, func: Callable[[List[float]], float], name: str) -> float:
"""Apply a function to the results of one named timer"""
"""Apply a function to the results of one named timer."""
if name in self._timings:
return func(self._timings[name])
raise KeyError(name)

def count(self, name: str) -> float:
"""Number of timings"""
"""Number of timings."""
return self.apply(len, name=name)

def total(self, name: str) -> float:
"""Total time for timers"""
"""Total time for timers."""
return self.apply(sum, name=name)

def min(self, name: str) -> float:
"""Minimal value of timings"""
"""Minimal value of timings."""
return self.apply(lambda values: min(values or [0]), name=name)

def max(self, name: str) -> float:
"""Maximal value of timings"""
"""Maximal value of timings."""
return self.apply(lambda values: max(values or [0]), name=name)

def mean(self, name: str) -> float:
"""Mean value of timings"""
"""Mean value of timings."""
return self.apply(lambda values: statistics.mean(values or [0]), name=name)

def median(self, name: str) -> float:
"""Median value of timings"""
"""Median value of timings."""
return self.apply(lambda values: statistics.median(values or [0]), name=name)

def stdev(self, name: str) -> float:
"""Standard deviation of timings"""
"""Standard deviation of timings."""
if name in self._timings:
value = self._timings[name]
return statistics.stdev(value) if len(value) >= 2 else math.nan
Expand Down