From 7ce38d06bbddfc438ca2340bc772a6c0a649d56f Mon Sep 17 00:00:00 2001 From: Spill-Tea Date: Mon, 13 Apr 2026 23:18:20 -0700 Subject: [PATCH] typing(benchmark): Implement strict static typing rules. --- pyproject.toml | 1 + src/EpiLog/benchmark.py | 23 ++++++++++++++++++----- tests/test_bench.py | 8 +++++++- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 004a060..2191c95 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -62,6 +62,7 @@ exclude_also = ["def __repr__", 'if __name__ == "__main__"'] [tool.mypy] mypy_path = "EpiLog" +strict = true warn_unused_ignores = true allow_redefinition = false force_uppercase_builtins = true diff --git a/src/EpiLog/benchmark.py b/src/EpiLog/benchmark.py index 010976c..c7e5c2f 100644 --- a/src/EpiLog/benchmark.py +++ b/src/EpiLog/benchmark.py @@ -26,7 +26,8 @@ import logging from dataclasses import dataclass from time import perf_counter_ns -from typing import Dict, Iterator, Tuple, Union +from types import TracebackType +from typing import Dict, Iterator, Optional, Tuple, Union # Python < 3.11 support @@ -58,17 +59,24 @@ class Units: Args: units (Unit): unit definitions + Raises: + ValueError: if modifier value of units is not defined. + """ units: Tuple[Unit, ...] - def __init__(self, *units: Unit): + def __init__(self, *units: Unit) -> None: self.units = units self._update() - def _update(self): + def _update(self) -> None: for n, current in enumerate(self.units[1:]): previous = self.units[n] + if previous.modifier is None: + raise ValueError( + f"Modifier value of unit '{previous.unit}' cannot be None." + ) current.base = previous.base * previous.modifier def __iter__(self) -> Iterator[Unit]: @@ -158,10 +166,15 @@ def __enter__(self) -> Self: return self - def __exit__(self, exc_type, exc_val, exc_tb) -> None: + def __exit__( + self, + exc_type: Optional[type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: end: int = perf_counter_ns() - if exc_type is not None: + if exc_type is not None and exc_val is not None: self.log.error("Traceback:", exc_info=(exc_type, exc_val, exc_tb)) return diff --git a/tests/test_bench.py b/tests/test_bench.py index cf8c3e3..ae6568f 100644 --- a/tests/test_bench.py +++ b/tests/test_bench.py @@ -9,7 +9,7 @@ import pytest from EpiLog import EpiLog -from EpiLog.benchmark import NS_UNITS, BenchMark, Units +from EpiLog.benchmark import NS_UNITS, BenchMark, Unit, Units from .conftest import _assert_msg_in_output @@ -83,6 +83,12 @@ def test_empty_convert_units() -> None: assert u == "", "Expected empty unit string." +def test_units_raises() -> None: + """Confirm instantiating units without modifier value raises ValueError.""" + with pytest.raises(ValueError): + obj = Units(Unit("a"), Unit("b")) + + @pytest.mark.parametrize( ["value", "expected"], [