From 80db05f05d3840b9e405dc854b2d9d330f5c1e3a Mon Sep 17 00:00:00 2001 From: Matthew Wardrop Date: Sat, 20 Sep 2025 22:56:43 -0700 Subject: [PATCH 1/2] Add explicit support for 3.14. --- .github/workflows/tests.yml | 2 +- pyproject.toml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 72ed1b2..f4e3d0a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -13,7 +13,7 @@ jobs: max-parallel: 4 fail-fast: false matrix: - python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] + python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] env: OS: ${{ matrix.os }} PYTHON: ${{ matrix.python-version }} diff --git a/pyproject.toml b/pyproject.toml index 93aa45c..26b5e13 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,6 +23,7 @@ classifiers = [ "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", ] requires-python = ">=3.9" dependencies = [ From c53380935a798b1fe770804eed29a4050b5330b4 Mon Sep 17 00:00:00 2001 From: Matthew Wardrop Date: Wed, 7 Jan 2026 14:45:19 -0800 Subject: [PATCH 2/2] Fix typing lints. --- .github/workflows/tests.yml | 2 +- formulaic/materializers/base.py | 2 +- formulaic/materializers/narwhals.py | 4 ++-- formulaic/model_spec.py | 6 +++--- formulaic/transforms/poly.py | 4 +++- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f4e3d0a..d835ea4 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -32,7 +32,7 @@ jobs: - if: matrix.python-version == '3.9' name: Check works with min requirements run: hatch run test_min:pytest tests - - if: matrix.python-version == '3.9' + - if: matrix.python-version == '3.14' name: Lint run: hatch run lint:check - name: Upload coverage to Codecov diff --git a/formulaic/materializers/base.py b/formulaic/materializers/base.py index a59b8d4..bf9c7ae 100644 --- a/formulaic/materializers/base.py +++ b/formulaic/materializers/base.py @@ -480,7 +480,7 @@ def _get_scoped_terms_spanned_by_evaled_factors( factors: list[tuple[Union[ScopedFactor, int], ...]] = [] for factor in evaled_factors: if factor.metadata.kind is Factor.Kind.CONSTANT: - scale *= factor.values + scale *= factor.values # type: ignore[operator] elif factor.metadata.spans_intercept: factors.append((ScopedFactor(factor, reduced=True), 1)) else: diff --git a/formulaic/materializers/narwhals.py b/formulaic/materializers/narwhals.py index e168618..2bd1ecc 100644 --- a/formulaic/materializers/narwhals.py +++ b/formulaic/materializers/narwhals.py @@ -4,7 +4,7 @@ import functools import itertools -from collections.abc import Sequence +from collections.abc import Mapping, Sequence from typing import TYPE_CHECKING, Any import narwhals.stable.v1 as nw @@ -42,7 +42,7 @@ def _init(self) -> None: @override # type: ignore @property - def data_context(self): + def data_context(self) -> Mapping[str, Any]: return self.__data_context @override diff --git a/formulaic/model_spec.py b/formulaic/model_spec.py index d00aed4..6495117 100644 --- a/formulaic/model_spec.py +++ b/formulaic/model_spec.py @@ -704,9 +704,9 @@ def get_model_matrix( from formulaic import ModelMatrices if attr_overrides: - return ModelSpec.from_spec(self, **attr_overrides).get_model_matrix( - data, context=context, drop_rows=drop_rows - ) + return cast( + ModelSpecs, ModelSpec.from_spec(self, **attr_overrides) + ).get_model_matrix(data, context=context, drop_rows=drop_rows) # Check whether we can generate model matrices jointly (i.e. all # materializers and their params are the same) diff --git a/formulaic/transforms/poly.py b/formulaic/transforms/poly.py index 7b66644..87d2eaf 100644 --- a/formulaic/transforms/poly.py +++ b/formulaic/transforms/poly.py @@ -126,4 +126,6 @@ def get_beta(k: int) -> float: out[nonnull_indices, :] = P[:, 1:] # Return basis dropping the first (constant) column - return FactorValues(out, column_names=tuple(str(i) for i in range(1, degree + 1))) + return FactorValues[numpy.ndarray]( # type: ignore[return-value] + out, column_names=tuple(str(i) for i in range(1, degree + 1)) + )