diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c5430a54c..83259a154 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -51,7 +51,7 @@ jobs: python -m mypy thinc --no-implicit-reexport tests: - name: ${{ matrix.os }} - Python ${{ matrix.python_version }} + name: ${{ matrix.os }} - Python ${{ matrix.python_version }} ${{ matrix.nightly }} strategy: fail-fast: false matrix: @@ -62,7 +62,13 @@ jobs: - macos-latest - windows-latest - windows-11-arm + # FIXME Python 3.14 requires confection git tip python_version: ["3.10", "3.11", "3.12", "3.13"] + nightly: [""] # Use only official releases + include: + - os: ubuntu-latest + python_version: "3.14" + nightly: "nightly" # Use nightly wheels and git tips exclude: - os: windows-11-arm python_version: "3.10" @@ -83,9 +89,29 @@ jobs: - name: Install build dependencies run: python -m pip install --upgrade build pip wheel + - name: Install nightly build dependencies + if: matrix.nightly == 'nightly' + run: | + pip install --upgrade --pre --extra-index-url https://pypi.anaconda.org/scientific-python-nightly-wheels/simple/ numpy blis + + # Install dependencies for --no-isolation + pip install setuptools \ + "cython>=3.0,<4.0" \ + "cymem>=2.0.2,<3" \ + "murmurhash>=1.0.2,<2" + + # TODO this won't be necessary long term after release 3.0.13 + # (replace with "preshed>=3.0.2,<3.1.0" above) + pip install git+https://github.com/explosion/preshed.git@v3.0.x + - name: Build sdist and wheel + if: matrix.nightly == '' run: python -m build + - name: Build sdist and wheel (no build isolation) + if: matrix.nightly == 'nightly' + run: python -m build --no-isolation + - name: Delete source directory run: rm -rf thinc shell: bash @@ -109,6 +135,34 @@ jobs: - name: Install notebook test requirements run: python -m ipykernel install --name thinc-notebook-tests --user + - name: Install nightly runtime dependencies + if: matrix.nightly == 'nightly' + run: | + pip install --upgrade --pre --extra-index-url https://pypi.anaconda.org/scientific-python-nightly-wheels/simple/ numpy blis + + # TODO this won't be necessary long term after release 3.0.13 + pip install --upgrade git+https://github.com/explosion/preshed.git@v3.0.x + + # TODO this won't be necessary long term after a free-threading release + # TODO merge https://github.com/ultrajson/ultrajson/pull/689 + # pip install --upgrade git+https://github.com/ultrajson/ultrajson.git + pip install --upgrade git+https://github.com/crusaderky/ultrajson.git@free-threading + + # FIXME msgpack-python is not fully compatible with free-threading at the + # moment of writing; naive pip install from git tip fails: + # https://github.com/msgpack/msgpack-python/issues/613 + + # TODO this won't be necessary long term after release 1.0.0 + pip install --upgrade git+https://github.com/explosion/confection.git + + # TODO this won't be necessary long term after release 0.2.1 + pip install --upgrade git+https://github.com/explosion/ml-datasets + + # TODO this won't be necessary long term after release 3.0 + # TODO merge https://github.com/explosion/srsly/pull/120 + # pip install --upgrade git+https://github.com/explosion/srsly.git + pip install --upgrade git+https://github.com/crusaderky/srsly.git@ft + - name: List installed packages run: python -m pip list diff --git a/pyproject.toml b/pyproject.toml index 243a60209..22ab26c57 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -78,4 +78,7 @@ filterwarnings = [ "ignore:Module thinc was previously imported, but not measured:coverage.exceptions.CoverageWarning", # https://github.com/coveragepy/coveragepy/issues/1790 "ignore:Plugin file tracers:coverage.exceptions.CoverageWarning", + # FIXME Pydantic V2 migration + "ignore::pydantic.warnings.PydanticDeprecatedSince20", + "ignore:Core Pydantic V1 functionality isn't compatible with Python 3.14 or greater:UserWarning", ] diff --git a/thinc/tests/layers/test_basic_tagger.py b/thinc/tests/layers/test_basic_tagger.py index 3131ebb91..8469f27f2 100644 --- a/thinc/tests/layers/test_basic_tagger.py +++ b/thinc/tests/layers/test_basic_tagger.py @@ -60,6 +60,7 @@ def get_shuffled_batches(Xs, Ys, batch_size): yield list(batch_X), list(batch_Y) +@pytest.mark.slow @pytest.mark.parametrize( ("depth", "width", "vector_width", "nb_epoch"), [(2, 32, 16, 5)] ) diff --git a/thinc/tests/layers/test_mnist.py b/thinc/tests/layers/test_mnist.py index 8fdb74fa3..70d014c39 100644 --- a/thinc/tests/layers/test_mnist.py +++ b/thinc/tests/layers/test_mnist.py @@ -86,6 +86,8 @@ def create_model(request): reason="SSL: CERTIFICATE_VERIFY_FAILED", strict=False, # Works on macos-15-intel Python 3.10, for some reason ) +# NumPy >=2.4 issues a warning when unpacking mnist pickle +@pytest.mark.filterwarnings("ignore::numpy.exceptions.VisibleDeprecationWarning") @pytest.mark.parametrize(("width", "nb_epoch", "min_score"), [(32, 20, 0.8)]) def test_small_end_to_end(width, nb_epoch, min_score, create_model, mnist): batch_size = 128 diff --git a/thinc/tests/model/test_model.py b/thinc/tests/model/test_model.py index 2284e93b2..40a941fb2 100644 --- a/thinc/tests/model/test_model.py +++ b/thinc/tests/model/test_model.py @@ -256,6 +256,7 @@ def test_plus_chain(): assert m.name == "a" +@pytest.mark.slow def test_overload_operators_in_subthread(): """Test we can create a model in a child thread with overloaded operators.""" # Worker1 will start and run, while worker 2 sleeps after Model.define_operators. @@ -514,11 +515,14 @@ def dummy_model(name, layers): assert a.layers[1].get_ref("y") == y_debug +# NumPy >=2.4 issues a warning when unpacking mnist pickle +@pytest.mark.filterwarnings("ignore::numpy.exceptions.VisibleDeprecationWarning") @pytest.mark.xfail( platform.system() == "Darwin", reason="SSL: CERTIFICATE_VERIFY_FAILED", strict=False, # Works on macos-15-intel Python 3.10, for some reason ) +@pytest.mark.slow def test_with_debug(): pytest.importorskip("ml_datasets") import ml_datasets diff --git a/thinc/tests/test_config.py b/thinc/tests/test_config.py index a3f4ede46..2302777ae 100644 --- a/thinc/tests/test_config.py +++ b/thinc/tests/test_config.py @@ -1,24 +1,9 @@ -import inspect -import pickle -from types import GeneratorType -from typing import Any, Callable, Dict, Iterable, List, Optional, Union - import catalogue import numpy -import pytest - -try: - from pydantic.v1 import BaseModel, PositiveInt, StrictBool, StrictFloat, constr -except ImportError: - from pydantic import BaseModel, PositiveInt, StrictBool, StrictFloat, constr # type: ignore +from pydantic import BaseModel, StrictBool import thinc.config -from thinc.api import Config, Model, NumpyOps, RAdam -from thinc.config import ConfigValidationError -from thinc.types import Generator, Ragged -from thinc.util import partial - -from .util import make_tempdir +from thinc.api import Config, Model, RAdam EXAMPLE_CONFIG = """ [optimizer] @@ -175,11 +160,11 @@ def test_objects_from_config(): } @thinc.registry.optimizers.register("my_cool_optimizer.v1") - def make_my_optimizer(learn_rate: List[float], beta1: float): + def make_my_optimizer(learn_rate: list[float], beta1: float): return RAdam(learn_rate, beta1=beta1) @thinc.registry.schedules("my_cool_repetitive_schedule.v1") - def decaying(base_rate: float, repeat: int) -> List[float]: + def decaying(base_rate: float, repeat: int) -> list[float]: return repeat * [base_rate] optimizer = my_registry.resolve(config)["optimizer"] diff --git a/thinc/tests/test_types.py b/thinc/tests/test_types.py index 1a3310d30..7a53e7aad 100644 --- a/thinc/tests/test_types.py +++ b/thinc/tests/test_types.py @@ -1,11 +1,6 @@ import numpy import pytest - -try: - from pydantic.v1 import ValidationError, create_model -except ImportError: - from pydantic import ValidationError, create_model # type: ignore - +from pydantic import ValidationError, create_model from thinc.types import ( Floats1d, diff --git a/thinc/util.py b/thinc/util.py index f32f10344..80887715d 100644 --- a/thinc/util.py +++ b/thinc/util.py @@ -23,8 +23,6 @@ ) import numpy -from packaging.version import Version -from pydantic import ConfigDict, ValidationError, create_model from wasabi import table # type: ignore from .compat import (