From 4414c4ee4d511d6476b803968411953eab83029b Mon Sep 17 00:00:00 2001 From: Daniele Varrazzo Date: Sun, 23 Jun 2024 13:12:34 +0200 Subject: [PATCH] fix: fix compatibility with numpy 2.0 The only meaningful code change is with the bool class, whose type name changed from `numpy.bool_` to `numpy.bool`. Note that using `bool` causes a FutureWarning on import for numpy > 1.20, therefore we avoid testing it (we still successfully test the `bool_` alias). Other changes are related to tests: certain constant aliases are no more available, so we skip those tests conditionally to numpy version. Pin a minimum numpy version, to make sure we test also a numpy v1. Picking 1.18, released back in Dec 2019, as it's the first minor version offering binary packages for Python 3.8. This min dependency will need to be updated when dropping Python 3.8 support. --- .github/workflows/tests.yml | 3 +++ psycopg/psycopg/types/numpy.py | 2 ++ tests/constraints.txt | 4 ++++ tests/fix_faker.py | 4 ++++ tests/types/test_numpy.py | 18 ++++++++++++------ 5 files changed, 25 insertions(+), 6 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 94a29e67a..2cc496f1c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -46,6 +46,9 @@ jobs: - {impl: c, python: "3.11", ext: numpy, postgres: "postgres:15"} # Test with minimum dependencies versions + # WARNING: when bumping min version, make sure that the dependencies + # # in tests/constraints.txt are updated and that binary packages + # are available for such version. - {impl: c, python: "3.8", ext: min, postgres: "postgres:15"} # Test memory alignment diff --git a/psycopg/psycopg/types/numpy.py b/psycopg/psycopg/types/numpy.py index 261c1f133..9427a2213 100644 --- a/psycopg/psycopg/types/numpy.py +++ b/psycopg/psycopg/types/numpy.py @@ -71,6 +71,7 @@ def register_default_adapters(context: AdaptContext) -> None: adapters.register_dumper("numpy.int32", NPInt32Dumper) adapters.register_dumper("numpy.int64", NPInt64Dumper) adapters.register_dumper("numpy.longlong", NPInt64Dumper) + adapters.register_dumper("numpy.bool", BoolDumper) adapters.register_dumper("numpy.bool_", BoolDumper) adapters.register_dumper("numpy.uint8", NPInt16Dumper) adapters.register_dumper("numpy.uint16", NPInt32Dumper) @@ -86,6 +87,7 @@ def register_default_adapters(context: AdaptContext) -> None: adapters.register_dumper("numpy.int32", NPInt32BinaryDumper) adapters.register_dumper("numpy.int64", NPInt64BinaryDumper) adapters.register_dumper("numpy.longlong", NPInt64BinaryDumper) + adapters.register_dumper("numpy.bool", BoolBinaryDumper) adapters.register_dumper("numpy.bool_", BoolBinaryDumper) adapters.register_dumper("numpy.uint8", NPInt16BinaryDumper) adapters.register_dumper("numpy.uint16", NPInt32BinaryDumper) diff --git a/tests/constraints.txt b/tests/constraints.txt index 5c106971c..b90d9742a 100644 --- a/tests/constraints.txt +++ b/tests/constraints.txt @@ -36,4 +36,8 @@ Cython == 3.0.0 tomli == 2.0.1 # Undeclared extras to "unblock" extra features + shapely == 1.7.0 +# Warning: binary package only available up to python < 3.9. +# Bump to a higher version when min supported python version increases past it. +numpy == 1.20.0 diff --git a/tests/fix_faker.py b/tests/fix_faker.py index dc26d5edf..e9c8f0770 100644 --- a/tests/fix_faker.py +++ b/tests/fix_faker.py @@ -230,6 +230,10 @@ class Faker: rv = set() for cls in dumpers.keys(): if isinstance(cls, str): + if cls == "numpy.bool": + # An alias of numpy.bool_ for numpy > 2. + # Raises a warning in numpy > 1.20. + continue try: cls = deep_import(cls) except ImportError: diff --git a/tests/types/test_numpy.py b/tests/types/test_numpy.py index ba5856cda..f9fabc487 100644 --- a/tests/types/test_numpy.py +++ b/tests/types/test_numpy.py @@ -1,6 +1,8 @@ from math import isnan import pytest +from packaging.version import parse as ver # noqa: F401 # used in skipif + from psycopg.adapt import PyFormat from psycopg.pq import Format @@ -13,6 +15,10 @@ pytest.importorskip("numpy") pytestmark = [pytest.mark.numpy] +skip_numpy2 = pytest.mark.skipif( + "ver(np.__version__) >= ver('2.0.0')", reason="not available since numpy >= 2" +) + def test_classes_identities(): # Check if we know the class identities correctly. Maybe on different @@ -31,13 +37,13 @@ def test_classes_identities(): "name, equiv", [ ("inf", "inf"), - ("infty", "inf"), - ("NINF", "-inf"), + pytest.param("infty", "inf", marks=skip_numpy2), + pytest.param("NINF", "-inf", marks=skip_numpy2), ("nan", "nan"), - ("NaN", "nan"), - ("NAN", "nan"), - ("PZERO", "0.0"), - ("NZERO", "-0.0"), + pytest.param("NaN", "nan", marks=skip_numpy2), + pytest.param("NAN", "nan", marks=skip_numpy2), + pytest.param("PZERO", "0.0", marks=skip_numpy2), + pytest.param("NZERO", "-0.0", marks=skip_numpy2), ], ) def test_special_values(name, equiv): -- 2.47.2