diff --git a/docs/howto/django.md b/docs/howto/django.md index 5629274e1..9649d1022 100644 --- a/docs/howto/django.md +++ b/docs/howto/django.md @@ -87,7 +87,7 @@ You can also use other subcommands such as `./manage.py procrastinate defer`. :::{note} Procrastinate generates an app for you using a `Psycopg` (by default) or -`Aiopg` connector depending on whether `psycopg3` or `aiopg` is +`Aiopg` connector depending on whether `psycopg` version 3 or `aiopg` is installed, and connects using the `DATABASES` settings. If neither library is installed, an error will be raised. ::: diff --git a/procrastinate/contrib/django/django_connector.py b/procrastinate/contrib/django/django_connector.py index e073acfc5..bea6b6789 100644 --- a/procrastinate/contrib/django/django_connector.py +++ b/procrastinate/contrib/django/django_connector.py @@ -127,7 +127,9 @@ def get_worker_connector(self) -> connector.BaseAsyncConnector: """ alias = utils.get_setting("DATABASE_ALIAS", default="default") - if utils.package_is_installed("psycopg3"): + if utils.package_is_installed("psycopg") and utils.package_is_version( + "psycopg", 3 + ): from procrastinate import psycopg_connector return psycopg_connector.PsycopgConnector( diff --git a/procrastinate/contrib/django/utils.py b/procrastinate/contrib/django/utils.py index 4bb7b8f77..b4742a6ca 100644 --- a/procrastinate/contrib/django/utils.py +++ b/procrastinate/contrib/django/utils.py @@ -1,5 +1,6 @@ from __future__ import annotations +import importlib.metadata import importlib.util from typing import Any @@ -36,3 +37,11 @@ def get_setting(name: str, *, default) -> Any: def package_is_installed(name: str) -> bool: return bool(importlib.util.find_spec(name)) + + +def package_is_version(name: str, major: int) -> bool: + """ + Check if package's (PEP440) version matches given major version number + """ + version = importlib.metadata.version(name) + return bool(version) and version.split(".")[0] == f"{major}" diff --git a/tests/integration/contrib/django/test_django_connector.py b/tests/integration/contrib/django/test_django_connector.py index e64e7ecdc..59c5cfd15 100644 --- a/tests/integration/contrib/django/test_django_connector.py +++ b/tests/integration/contrib/django/test_django_connector.py @@ -82,7 +82,7 @@ def test_execute_query_sync(django_connector): @pytest.mark.parametrize( "installed, type", [ - ({"psycopg3"}, psycopg_connector.PsycopgConnector), + ({"psycopg"}, psycopg_connector.PsycopgConnector), ({"aiopg"}, aiopg_connector.AiopgConnector), ], ) diff --git a/tests/unit/contrib/django/test_utils.py b/tests/unit/contrib/django/test_utils.py index ae3fa9f87..6a5c9b5d0 100644 --- a/tests/unit/contrib/django/test_utils.py +++ b/tests/unit/contrib/django/test_utils.py @@ -27,3 +27,18 @@ def test_get_settings_default(): ) def test_package_is_installed(package_name, expected): assert utils.package_is_installed(package_name) is expected + + +@pytest.mark.parametrize( + "version, version_wanted,expected", + [ + ("3.1.3", 3, True), + ("2.1.3", 3, False), + ("pytest", 3, False), + (None, 3, False), + ], +) +def test_package_is_version(version, version_wanted, expected, mocker): + mocker.patch("importlib.metadata.version", return_value=version) + + assert utils.package_is_version("abcd", version_wanted) is expected