From 4355ac0d023950e1d8bb2bd9c20a5493a99277c9 Mon Sep 17 00:00:00 2001 From: John Riley Date: Fri, 28 Aug 2026 00:36:17 -0400 Subject: [PATCH] Update ruff requirement from ^0.11.10 to >=0.11.10,<0.17.0 Rebuilt on current main -- Dependabot could not rebase this itself after the DDD restructure, failing two rebases and a recreate. Widening the constraint alone would have broken CI. poetry.lock is gitignored here, so CI resolves ruff fresh on every run; with the new ceiling it picks up 0.16.x, which enables B905 and finds seven `zip()` calls with no explicit `strict=`: algosystem/validation/domain/statistics/walkforward.py:126 algosystem/validation/domain/strategy.py:99 algosystem/validation/infrastructure/matplotlib_charts.py:144,157,158 tests/validation/application/test_bruteforce.py:33 tests/validation/infrastructure/test_strategies.py:131 All seven zip equal-length sequences by construction -- parameter keys against a combination drawn from those same keys, means against stds built from one list of values, and one unzip of a list of pairs. So `strict=True` is both correct and the documented invariant: if the lengths ever diverge it is a bug, and now it raises instead of silently truncating. One line went over 100 chars as a result and was split. Verified against ruff 0.16.5 (the newest release under the new ceiling): `ruff check algosystem tests` passes, and black and isort are unchanged. Co-Authored-By: Claude Opus 5 --- algosystem/validation/domain/statistics/walkforward.py | 2 +- algosystem/validation/domain/strategy.py | 2 +- algosystem/validation/infrastructure/matplotlib_charts.py | 6 +++--- pyproject.toml | 2 +- tests/validation/application/test_bruteforce.py | 2 +- tests/validation/infrastructure/test_strategies.py | 3 ++- 6 files changed, 9 insertions(+), 8 deletions(-) diff --git a/algosystem/validation/domain/statistics/walkforward.py b/algosystem/validation/domain/statistics/walkforward.py index 35d76e3..f3ba26d 100644 --- a/algosystem/validation/domain/statistics/walkforward.py +++ b/algosystem/validation/domain/statistics/walkforward.py @@ -123,7 +123,7 @@ def walk_forward_analysis( n = len(returns) keys = sorted(param_grid.keys()) values = [param_grid[k] for k in keys] - param_list = [dict(zip(keys, combo)) for combo in itertools.product(*values)] + param_list = [dict(zip(keys, combo, strict=True)) for combo in itertools.product(*values)] # Compute fold boundaries # Each fold: [fold_start, fold_end) with IS = first is_ratio, OOS = rest diff --git a/algosystem/validation/domain/strategy.py b/algosystem/validation/domain/strategy.py index 35c66b6..ac163b4 100644 --- a/algosystem/validation/domain/strategy.py +++ b/algosystem/validation/domain/strategy.py @@ -96,7 +96,7 @@ def combinations(self) -> Iterator[ParameterSet]: keys = [name for name, _ in self._items] value_lists = [values for _, values in self._items] for combo in itertools.product(*value_lists): - yield ParameterSet(zip(keys, combo)) + yield ParameterSet(zip(keys, combo, strict=True)) def to_dict(self) -> dict[str, list[object]]: """Return a mutable dict copy preserving stable parameter order.""" diff --git a/algosystem/validation/infrastructure/matplotlib_charts.py b/algosystem/validation/infrastructure/matplotlib_charts.py index 09584cc..c85f95c 100644 --- a/algosystem/validation/infrastructure/matplotlib_charts.py +++ b/algosystem/validation/infrastructure/matplotlib_charts.py @@ -141,7 +141,7 @@ def draw(plt): if show_individual: for points in slices.values(): points.sort() - xs, ys = zip(*points) + xs, ys = zip(*points, strict=True) ax.plot(xs, ys, color="grey", alpha=0.15, linewidth=0.7, zorder=1) value_sharpes = {value: [] for value in values} @@ -154,8 +154,8 @@ def draw(plt): ax.fill_between( xs_mean, - [mean - std for mean, std in zip(means, stds)], - [mean + std for mean, std in zip(means, stds)], + [mean - std for mean, std in zip(means, stds, strict=True)], + [mean + std for mean, std in zip(means, stds, strict=True)], alpha=0.25, color="steelblue", zorder=2, diff --git a/pyproject.toml b/pyproject.toml index 3fe13c3..fe643df 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,7 +55,7 @@ isort = "^5.13.2" mypy = "^1.8.0" pytest-cov = "^5.0.0" backoff = "^1.2.1" -ruff = "^0.11.10" +ruff = ">=0.11.10,<0.17.0" import-linter = "^2.3.0" [tool.poetry.group.docs] diff --git a/tests/validation/application/test_bruteforce.py b/tests/validation/application/test_bruteforce.py index 01a1c26..ca3d087 100644 --- a/tests/validation/application/test_bruteforce.py +++ b/tests/validation/application/test_bruteforce.py @@ -30,7 +30,7 @@ def test_full_crossvalidation(self): # Brute-force: re-run all passes manually keys = sorted(param_grid.keys()) values = [param_grid[k] for k in keys] - plist = [dict(zip(keys, combo)) for combo in itertools.product(*values)] + plist = [dict(zip(keys, combo, strict=True)) for combo in itertools.product(*values)] n_params = len(plist) master_rng = np.random.default_rng(55) diff --git a/tests/validation/infrastructure/test_strategies.py b/tests/validation/infrastructure/test_strategies.py index 8aebdaf..3be326b 100644 --- a/tests/validation/infrastructure/test_strategies.py +++ b/tests/validation/infrastructure/test_strategies.py @@ -128,7 +128,8 @@ def test_trending_persists_oos(self): grid = {"lookback": [5, 10, 20, 40], "threshold": [0.0, 0.001]} keys = sorted(grid.keys()) - plist = [dict(zip(keys, c)) for c in itertools.product(*[grid[k] for k in keys])] + combos = itertools.product(*[grid[k] for k in keys]) + plist = [dict(zip(keys, c, strict=True)) for c in combos] is_sharpes = [momentum_backtest(p, is_data) for p in plist] best_idx = np.argmax(is_sharpes)