From dad7aa35c5dfbf4c9a06e974fe1aea3e607c5932 Mon Sep 17 00:00:00 2001 From: Abdul Hakim Norazman Date: Thu, 10 Sep 2026 22:16:44 +0100 Subject: [PATCH 1/2] Fix pull request CI workflows --- .github/workflows/build-and-deploy-docs.yml | 20 ++++++++++++++------ .github/workflows/ci-lint-typecheck.yml | 6 ++++-- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build-and-deploy-docs.yml b/.github/workflows/build-and-deploy-docs.yml index ccef9c2..968ffd3 100644 --- a/.github/workflows/build-and-deploy-docs.yml +++ b/.github/workflows/build-and-deploy-docs.yml @@ -19,15 +19,10 @@ concurrency: cancel-in-progress: true permissions: contents: read - pages: write - id-token: write jobs: docs: name: Build docs runs-on: ubuntu-latest - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} steps: - uses: actions/checkout@v4 - name: Setup @@ -41,10 +36,23 @@ jobs: uses: actions/upload-pages-artifact@v3 with: path: docs/_build/html + + deploy: + name: Deploy docs + if: startsWith(github.ref, 'refs/tags/v') && github.event_name == 'push' + needs: docs + runs-on: ubuntu-latest + permissions: + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: - name: Deploy to GitHub Pages - if: startsWith(github.ref, 'refs/tags/v') && github.event_name == 'push' id: deployment uses: actions/deploy-pages@v4 + doctest: name: Run doctests runs-on: ubuntu-latest diff --git a/.github/workflows/ci-lint-typecheck.yml b/.github/workflows/ci-lint-typecheck.yml index 46a3e55..6f57531 100644 --- a/.github/workflows/ci-lint-typecheck.yml +++ b/.github/workflows/ci-lint-typecheck.yml @@ -35,13 +35,15 @@ jobs: - uses: actions/checkout@v6 - name: Ruff check - uses: astral-sh/ruff-action@v3 + uses: astral-sh/ruff-action@v4.1.0 with: + version-file: uv.lock args: "check" - name: Ruff format (check) - uses: astral-sh/ruff-action@v3 + uses: astral-sh/ruff-action@v4.1.0 with: + version-file: uv.lock args: "format --check" typecheck: From f5c397b16898efe4b83f42c5cc8dc52b51287fb8 Mon Sep 17 00:00:00 2001 From: Abdul Hakim Norazman Date: Thu, 10 Sep 2026 22:07:56 +0100 Subject: [PATCH 2/2] Promote mixed timeseries arithmetic to float --- src/backtest_lib/market/polars_impl/_timeseries.py | 14 +++++++++++--- .../market/polars_impl/test_polars_timeseries.py | 9 +++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/backtest_lib/market/polars_impl/_timeseries.py b/src/backtest_lib/market/polars_impl/_timeseries.py index 8ac9f87..005a03f 100644 --- a/src/backtest_lib/market/polars_impl/_timeseries.py +++ b/src/backtest_lib/market/polars_impl/_timeseries.py @@ -164,12 +164,20 @@ def to_series( # the scalar types are properly kept track of. def _rhs( self, other: VectorOps[Scalar] | ScalarU - ) -> tuple[pl.Series | T, type[ScalarU]]: + ) -> tuple[pl.Series | ScalarU, type[ScalarU]]: if isinstance(other, (int, float)): - return self._scalar_type(other), self._scalar_type + scalar_type = ( + float if self._scalar_type is float or isinstance(other, float) else int + ) + return other, scalar_type if isinstance(other, PolarsTimeseries): if other._axis is self._axis or other._axis.labels == self._axis.labels: - return other._vec, other._scalar_type + scalar_type = ( + float + if self._scalar_type is float or other._scalar_type is float + else int + ) + return other._vec, scalar_type raise ValueError("Axis mismatch: operations require identical PeriodAxis.") raise TypeError("Only scalars or same-axis PolarsTimeseries are supported.") diff --git a/tests/unit/market/polars_impl/test_polars_timeseries.py b/tests/unit/market/polars_impl/test_polars_timeseries.py index eb22983..3f8405c 100644 --- a/tests/unit/market/polars_impl/test_polars_timeseries.py +++ b/tests/unit/market/polars_impl/test_polars_timeseries.py @@ -113,6 +113,15 @@ def test_arithmetic_with_timeseries(small_timeseries, timeseries_type) -> None: assert combined.to_series().to_list() == [11.0, 22.0, 33.0] +def test_arithmetic_promotes_mixed_numeric_types(timeseries_type) -> None: + periods = [np.datetime64("2024-01-01"), np.datetime64("2024-01-02")] + ints = timeseries_type.from_vectors([1, 2], periods) + floats = timeseries_type.from_vectors([0.5, 1.5], periods) + + assert (ints + 0.5).to_series().to_list() == [1.5, 2.5] + assert (floats + ints).to_series().to_list() == [1.5, 3.5] + + def test_axis_mismatch_raises(timeseries_type) -> None: left = timeseries_type.from_vectors( values=[1.0, 2.0],