diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 020af7dc..1fd22dd6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,9 +34,9 @@ jobs: - name: typos uses: crate-ci/typos@v1.39.0 - - uses: astral-sh/setup-uv@v7.1.2 + - uses: astral-sh/setup-uv@v7.1.3 with: - python-version: "3.13" + python-version: "3.14" - name: ruff check run: uv run ruff check --output-format=github @@ -60,10 +60,13 @@ jobs: np: "1.25" - py: "3.13" np: "2.0" + include: + - py: "3.14" + np: "2.3" steps: - uses: actions/checkout@v5.0.0 - - uses: astral-sh/setup-uv@v7.1.2 + - uses: astral-sh/setup-uv@v7.1.3 with: activate-environment: true python-version: ${{ matrix.py }} @@ -108,7 +111,7 @@ jobs: steps: - uses: actions/checkout@v5.0.0 - - uses: astral-sh/setup-uv@v7.1.2 + - uses: astral-sh/setup-uv@v7.1.3 with: python-version: ${{ matrix.py }} diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml index 57bc1b7f..a918322d 100644 --- a/.github/workflows/publish-pypi.yml +++ b/.github/workflows/publish-pypi.yml @@ -21,9 +21,9 @@ jobs: steps: - uses: actions/checkout@v5.0.0 - - uses: astral-sh/setup-uv@v7.1.2 + - uses: astral-sh/setup-uv@v7.1.3 with: - python-version: "3.13" + python-version: "3.14" - name: uv build run: uv build diff --git a/pyproject.toml b/pyproject.toml index 7e30471c..f8bb13f2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["uv_build>=0.9.0,<0.10.0"] +requires = ["uv_build>=0.9.8,<0.10.0"] build-backend = "uv_build" [tool.uv.build-backend] @@ -68,19 +68,19 @@ extra = [ ] lint = [ "dprint-py>=0.50.2.0", - "ruff>=0.14.0", - "sp-repo-review[cli]>=2025.10.1", + "ruff>=0.14.4", + "sp-repo-review[cli]>=2025.11.10", ] test = [ { include-group = "extra" }, - "beartype>=0.22.2", - "pytest>=8.4.2", + "beartype>=0.22.5", + "pytest>=9.0.0", "typing-extensions>=4.15.0", ] type = [ { include-group = "extra" }, { include-group = "test" }, - "basedpyright>=1.31.7", + "basedpyright>=1.33.0", "mypy[faster-cache]>=1.18.2", "pyrefly==0.40.1", ] @@ -138,14 +138,14 @@ reportUnusedVariable = false # dupe of F841 # pytest -[tool.pytest.ini_options] -minversion = "8.0" +[tool.pytest] +minversion = "9.0" testpaths = ["optype", "examples", "tests"] -addopts = ["-ra", "--doctest-modules", "--strict-config", "--strict-markers"] +addopts = ["-ra", "--doctest-modules"] doctest_optionflags = ["NORMALIZE_WHITESPACE", "IGNORE_EXCEPTION_DETAIL", "ELLIPSIS"] filterwarnings = ["error"] log_cli_level = "INFO" -xfail_strict = true +strict = true # repo-review diff --git a/tests/numpy/test_any_array.py b/tests/numpy/test_any_array.py index 96a33dfc..a8edec01 100644 --- a/tests/numpy/test_any_array.py +++ b/tests/numpy/test_any_array.py @@ -13,46 +13,46 @@ # All allowed arguments that when passed to `np.array`, will result in an # array of the specified scalar type(s). -_UNSIGNED_INTEGER_NP: Final = ( +_UNSIGNED_INTEGER_NP: Final = { np.uint8, np.uint16, np.uint32, np.uint64, np.uintp, np.ubyte, np.ushort, np.uintc, ulong, np.ulonglong, -) # fmt: skip -_UNSIGNED_INTEGER_CT: Final = ( +} # fmt: skip +_UNSIGNED_INTEGER_CT: Final = { ct.c_uint8, ct.c_uint16, ct.c_uint32, ct.c_uint64, ct.c_size_t, ct.c_ubyte, ct.c_ushort, ct.c_uint, ct.c_ulong, ct.c_ulonglong, -) # fmt: skip -UNSIGNED_INTEGER: Final = *_UNSIGNED_INTEGER_NP, *_UNSIGNED_INTEGER_CT -_SIGNED_INTEGER_NP: Final = ( +} # fmt: skip +UNSIGNED_INTEGER: Final = _UNSIGNED_INTEGER_NP | _UNSIGNED_INTEGER_CT +_SIGNED_INTEGER_NP: Final = { np.int8, np.int16, np.int32, np.int64, np.intp, np.byte, np.short, np.intc, long, np.longlong, -) # fmt: skip -_SIGNED_INTEGER_CT: Final = ( +} # fmt: skip +_SIGNED_INTEGER_CT: Final = { ct.c_int8, ct.c_int16, ct.c_int32, ct.c_int64, ct.c_ssize_t, ct.c_byte, ct.c_short, ct.c_int, ct.c_long, ct.c_longlong, -) # fmt: skip -SIGNED_INTEGER: Final = *_SIGNED_INTEGER_NP, *_SIGNED_INTEGER_CT -INTEGER: Final = *UNSIGNED_INTEGER, *SIGNED_INTEGER +} # fmt: skip +SIGNED_INTEGER: Final = _SIGNED_INTEGER_NP | _SIGNED_INTEGER_CT +INTEGER: Final = UNSIGNED_INTEGER | SIGNED_INTEGER -_FLOATING_NP: Final = ( +_FLOATING_NP: Final = { np.float16, np.float32, np.float64, np.half, np.single, np.double, np.longdouble, -) # fmt: skip -_FLOATING_CT: Final = ct.c_float, ct.c_double -FLOATING: Final = *_FLOATING_NP, *_FLOATING_CT -COMPLEX_FLOATING: Final = ( +} # fmt: skip +_FLOATING_CT: Final = {ct.c_float, ct.c_double} +FLOATING: Final = _FLOATING_NP | _FLOATING_CT +COMPLEX_FLOATING: Final = { np.complex64, np.complex128, np.csingle, np.cdouble, np.clongdouble, -) # fmt: skip -DATETIME64: Final = np.datetime64, dt.datetime -TIMEDELTA64: Final = np.timedelta64, dt.timedelta -STR: Final = np.str_, str -BYTES: Final = np.bytes_, ct.c_char, bytes -CHARACTER: Final = *STR, *BYTES +} # fmt: skip +DATETIME64: Final = {np.datetime64, dt.datetime} +TIMEDELTA64: Final = {np.timedelta64, dt.timedelta} +STR: Final = {np.str_, str} +BYTES: Final = {np.bytes_, ct.c_char, bytes} +CHARACTER: Final = STR | BYTES # TODO(jorenham): structured dtype support # https://github.com/jorenham/optype/issues/371 -VOID: Final = (np.void,) -FLEXIBLE: Final = *VOID, *CHARACTER -BOOL: Final = np.bool_, ct.c_bool, bool -OBJECT: Final = np.object_, ct.py_object +VOID: Final = {np.void} +FLEXIBLE: Final = VOID | CHARACTER +BOOL: Final = {np.bool_, ct.c_bool, bool} +OBJECT: Final = {np.object_, ct.py_object} def _shape(a: object, /) -> tuple[int, ...]: @@ -223,7 +223,7 @@ def test_any_flexible_array( assert np.issubdtype(x.dtype, np.flexible) -@pytest.mark.parametrize("sctype", BOOL) +@pytest.mark.parametrize("sctype", BOOL, ids="{0.__module__}.{0.__qualname__}".format) def test_any_bool_array(sctype: type[bool | np.bool_ | _ct.Bool]) -> None: x = np.array(sctype(True)) x_any: onp.AnyBoolArray = x diff --git a/tests/numpy/test_is.py b/tests/numpy/test_is.py index f596ce40..be8894a3 100644 --- a/tests/numpy/test_is.py +++ b/tests/numpy/test_is.py @@ -14,7 +14,8 @@ else: CHARS = "?BbHhIiLlQqPpefdgFDGSUVOMm" # pyright: ignore[reportConstantRedefinition] -DTYPES = [np.dtype(char) for char in CHARS] +# dtypes aren't hashable on numpy<2 +DTYPES = set({str(np.dtype(char)): np.dtype(char) for char in CHARS}.values()) SCTYPES = {dtype.type for dtype in DTYPES if issubclass(dtype.type, np.generic)} NDARRAY_TYPES = np.ndarray, np.ma.MaskedArray diff --git a/uv.lock b/uv.lock index cc76a4a4..cb4a4035 100644 --- a/uv.lock +++ b/uv.lock @@ -308,36 +308,36 @@ provides-extras = ["numpy"] [package.metadata.requires-dev] dev = [ - { name = "basedpyright", specifier = ">=1.31.7" }, - { name = "beartype", specifier = ">=0.22.2" }, + { name = "basedpyright", specifier = ">=1.33.0" }, + { name = "beartype", specifier = ">=0.22.5" }, { name = "dprint-py", specifier = ">=0.50.2.0" }, { name = "mypy", extras = ["faster-cache"], specifier = ">=1.18.2" }, { name = "optype", extras = ["numpy"] }, { name = "pyrefly", specifier = "==0.40.1" }, - { name = "pytest", specifier = ">=8.4.2" }, - { name = "ruff", specifier = ">=0.14.0" }, - { name = "sp-repo-review", extras = ["cli"], specifier = ">=2025.10.1" }, + { name = "pytest", specifier = ">=9.0.0" }, + { name = "ruff", specifier = ">=0.14.4" }, + { name = "sp-repo-review", extras = ["cli"], specifier = ">=2025.11.10" }, { name = "typing-extensions", specifier = ">=4.15.0" }, ] extra = [{ name = "optype", extras = ["numpy"] }] lint = [ { name = "dprint-py", specifier = ">=0.50.2.0" }, - { name = "ruff", specifier = ">=0.14.0" }, - { name = "sp-repo-review", extras = ["cli"], specifier = ">=2025.10.1" }, + { name = "ruff", specifier = ">=0.14.4" }, + { name = "sp-repo-review", extras = ["cli"], specifier = ">=2025.11.10" }, ] test = [ - { name = "beartype", specifier = ">=0.22.2" }, + { name = "beartype", specifier = ">=0.22.5" }, { name = "optype", extras = ["numpy"] }, - { name = "pytest", specifier = ">=8.4.2" }, + { name = "pytest", specifier = ">=9.0.0" }, { name = "typing-extensions", specifier = ">=4.15.0" }, ] type = [ - { name = "basedpyright", specifier = ">=1.31.7" }, - { name = "beartype", specifier = ">=0.22.2" }, + { name = "basedpyright", specifier = ">=1.33.0" }, + { name = "beartype", specifier = ">=0.22.5" }, { name = "mypy", extras = ["faster-cache"], specifier = ">=1.18.2" }, { name = "optype", extras = ["numpy"] }, { name = "pyrefly", specifier = "==0.40.1" }, - { name = "pytest", specifier = ">=8.4.2" }, + { name = "pytest", specifier = ">=9.0.0" }, { name = "typing-extensions", specifier = ">=4.15.0" }, ] @@ -603,15 +603,15 @@ wheels = [ [[package]] name = "sp-repo-review" -version = "2025.10.1" +version = "2025.11.10" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pyyaml" }, { name = "repo-review" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/81/2c/b2e017b588114a8f4d9437d8ade805756bf479f429ad9fbbc05a34864264/sp_repo_review-2025.10.1.tar.gz", hash = "sha256:599e91e37a2d7fa6bd0446b1b434a2336f7dd3527162195cc5295af2b405c622", size = 169310, upload-time = "2025-10-01T16:29:40.075Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d5/d9/60315a38c7d8a5a67faaa9a0d6b3f67be155c8f463963ce318e1349a80ed/sp_repo_review-2025.11.10.tar.gz", hash = "sha256:9f1a2b534da70bec327e12cc7088499293dab78e7676436fcbf75be28401a6bc", size = 183103, upload-time = "2025-11-10T15:59:42.261Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/da/ca/c367c299c3e0c72270a13207e9b8dbb28ab8bc8e9cb42938aff93aece5f2/sp_repo_review-2025.10.1-py3-none-any.whl", hash = "sha256:6c2624ca47ed2a745fa4c00e6ead0ed44087bc6a1b0dbfe8d136bbbc0430f5b1", size = 22506, upload-time = "2025-10-01T16:29:38.499Z" }, + { url = "https://files.pythonhosted.org/packages/06/e8/d3e1f1bde3653775751c250f966496c4c9ab0bfbc1f53631e35e6804b886/sp_repo_review-2025.11.10-py3-none-any.whl", hash = "sha256:a7d882890b6ce083d66dc65e185a5efe8b207e92a6bee86359c772064a86ad7a", size = 30463, upload-time = "2025-11-10T15:59:40.962Z" }, ] [package.optional-dependencies]