From d0ed14d6dd101395eb95f03e5f3574b8f41e26e8 Mon Sep 17 00:00:00 2001 From: Ryan Min <73128364+kcrmin@users.noreply.github.com> Date: Mon, 26 Oct 2026 22:08:59 +0900 Subject: [PATCH 1/2] fix(backtest): annotate scalar_one results SQLAlchemy 2.1 types Result with variadic generics, so mypy 2.3.0 reports var-annotated on bare scalar_one() assignments. --- src/backtest_engine/backtest_request_intake.py | 2 +- tests/persistence/test_money_precision.py | 2 +- tests/persistence/test_runtime_no_ddl.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backtest_engine/backtest_request_intake.py b/src/backtest_engine/backtest_request_intake.py index 5cc9fa5..fc436df 100644 --- a/src/backtest_engine/backtest_request_intake.py +++ b/src/backtest_engine/backtest_request_intake.py @@ -408,7 +408,7 @@ def claim( ) return RequestClaim(RequestClaimDisposition.CLAIMED) - latest = connection.execute( + latest: int = connection.execute( text( """ SELECT COALESCE(MAX(o.aggregate_sequence), 0) diff --git a/tests/persistence/test_money_precision.py b/tests/persistence/test_money_precision.py index b869888..fce4eba 100644 --- a/tests/persistence/test_money_precision.py +++ b/tests/persistence/test_money_precision.py @@ -75,7 +75,7 @@ def test_numeric_24_8_round_trips_without_precision_loss(persistence: BacktestPe with persistence.unit_of_work() as uow: stored = uow.runs.get(row.id).initial_cash_amount # `==` on Decimal ignores trailing zeros, so read the stored digits as text too. - stored_text = uow.connection.execute( + stored_text: str = uow.connection.execute( text("SELECT initial_cash_amount::text FROM backtest.runs WHERE id = :id"), {"id": str(row.id)}, ).scalar_one() diff --git a/tests/persistence/test_runtime_no_ddl.py b/tests/persistence/test_runtime_no_ddl.py index c642e72..dd97895 100644 --- a/tests/persistence/test_runtime_no_ddl.py +++ b/tests/persistence/test_runtime_no_ddl.py @@ -167,6 +167,6 @@ def test_ddl_really_did_not_happen(persistence: BacktestPersistence, admin_engin uow.connection.execute(text("CREATE TABLE backtest.sneaky (id uuid PRIMARY KEY)")) with admin_engine.connect() as connection: - exists = connection.execute(text("SELECT to_regclass('backtest.sneaky') IS NOT NULL")).scalar_one() + exists: bool = connection.execute(text("SELECT to_regclass('backtest.sneaky') IS NOT NULL")).scalar_one() assert exists is False From c44a0034e2a5225e25de145f7d087c3e1b6c6031 Mon Sep 17 00:00:00 2001 From: Ryan Min <73128364+kcrmin@users.noreply.github.com> Date: Mon, 26 Oct 2026 22:11:13 +0900 Subject: [PATCH 2/2] build(deps): cap sqlalchemy below 2.2 SQLAlchemy 2.1 retyped Result and broke the type gate, so the next minor should be a deliberate bump. mypy stays pinned with data-pipeline. --- pyproject.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 84e8f09..5e632d3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,7 +17,9 @@ dependencies = [ "psutil==7.2.2", "psycopg[binary]>=3.2,<4.0", "pyarrow==25.0.0", - "sqlalchemy>=2.0,<3.0", + # Capped below the next minor, not the next major: SQLAlchemy 2.1 retyped `Result`, + # which failed the type gate, so moving past 2.1 is a deliberate bump. + "sqlalchemy>=2.0,<2.2", "tzdata==2026.3", "uvicorn==0.52.1", ] @@ -38,6 +40,7 @@ test = [ ] dev = [ "idea2strategy-backtest-engine[test]", + # The same release data-pipeline pins, so the two type gates agree. Bump both together. "mypy==2.3.0", "mutmut==3.3.1", "ruff==0.16.1",