]> git.ipfire.org Git - thirdparty/psycopg.git/commitdiff
chore: drop Python 3.8 support 977/head
authorstankudrow <stankudrow@reply.no>
Mon, 23 Dec 2024 16:52:26 +0000 (19:52 +0300)
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>
Thu, 26 Dec 2024 16:34:57 +0000 (17:34 +0100)
Close #976.

20 files changed:
.github/workflows/3rd-party-tests.yml
.github/workflows/packages-bin.yml
.github/workflows/tests.yml
docs/basic/install.rst
docs/news.rst
docs/release.rst
psycopg/psycopg/_acompat.py
psycopg/psycopg/abc.py
psycopg/psycopg/pq/abc.py
psycopg/psycopg/rows.py
psycopg/pyproject.toml
psycopg_c/pyproject.toml
psycopg_pool/psycopg_pool/_acompat.py
psycopg_pool/psycopg_pool/abc.py
psycopg_pool/pyproject.toml
tests/README.rst
tests/acompat.py
tests/constraints.txt
tools/build/build_macos_arm64.sh
tools/bump_version.py

index fe78ac414bbc24138edbe3e0f5050b8824d445e8..cab0c4019785763af4e482b8acb8c329fd910053 100644 (file)
@@ -137,7 +137,7 @@ jobs:
           #       Current logic is test oldest in lts and newest in main
           - django_label: lts
             pip_django: "'Django>=4.2,<4.3'"
-            python-version: "3.8"
+            python-version: "3.9"
 
     env:
       DEPS: ./psycopg ./psycopg_pool
index 6102be1074c6732542b8bec51e939a9a56c2454b..be3e14644023088d88a93a8b7f1f613277c07cce 100644 (file)
@@ -23,7 +23,7 @@ jobs:
       fail-fast: false
       matrix:
         arch: [x86_64, i686, ppc64le, aarch64]
-        pyver: [cp38, cp39, cp310, cp311, cp312, cp313]
+        pyver: [cp39, cp310, cp311, cp312, cp313]
         platform: [manylinux, musllinux]
 
     steps:
@@ -161,7 +161,7 @@ jobs:
       matrix:
         # These archs require an Apple M1 runner: [arm64, universal2]
         arch: [x86_64]
-        pyver: [cp38, cp39, cp310, cp311, cp312, cp313]
+        pyver: [cp39, cp310, cp311, cp312, cp313]
 
     env:
       PG_VERSION: "17"
@@ -215,7 +215,7 @@ jobs:
       matrix:
         # Might want to add win32, untested at the moment.
         arch: [win_amd64]
-        pyver: [cp38, cp39, cp310, cp311, cp312, cp313]
+        pyver: [cp39, cp310, cp311, cp312, cp313]
 
     defaults:
       run:
index f69fa8dcb04d8d30838db5583b930628a6de23e2..c21493c86cdb319069a0627cb27a36028602330c 100644 (file)
@@ -26,32 +26,30 @@ jobs:
       matrix:
         include:
           # Test different combinations of Python, Postgres, libpq.
-          - {impl: python, python: "3.8", postgres: "postgres:17", libpq: oldest}
-          - {impl: python, python: "3.9", postgres: "postgres:16", libpq: master}
-          - {impl: python, python: "3.10", postgres: "postgres:15"}
-          - {impl: python, python: "3.11", postgres: "postgres:14"}
-          - {impl: python, python: "3.12", postgres: "postgres:13", libpq: newest}
+          - {impl: python, python: "3.9", postgres: "postgres:17", libpq: oldest}
+          - {impl: python, python: "3.10", postgres: "postgres:16", libpq: master}
+          - {impl: python, python: "3.11", postgres: "postgres:15"}
+          - {impl: python, python: "3.12", postgres: "postgres:14", libpq: newest}
           - {impl: python, python: "3.13", postgres: "postgres:12"}
 
-          - {impl: c, python: "3.8", postgres: "postgres:12", libpq: master}
-          - {impl: c, python: "3.9", postgres: "postgres:13"}
-          - {impl: c, python: "3.10", postgres: "postgres:14"}
+          - {impl: c, python: "3.9", postgres: "postgres:12", libpq: master}
+          - {impl: c, python: "3.10", postgres: "postgres:13"}
           - {impl: c, python: "3.11", postgres: "postgres:15", libpq: oldest}
           - {impl: c, python: "3.12", postgres: "postgres:16", libpq: newest}
           - {impl: c, python: "3.13", postgres: "postgres:17"}
 
-          - {impl: python, python: "3.8", ext: gevent, postgres: "postgres:17"}
-          - {impl: c, python: "3.12", ext: gevent, postgres: "postgres:14"}
+          - {impl: python, python: "3.9", ext: gevent, postgres: "postgres:17"}
           - {impl: python, python: "3.9", ext: dns, postgres: "postgres:14"}
           - {impl: python, python: "3.9", ext: postgis, postgres: "postgis/postgis"}
           - {impl: python, python: "3.10", ext: numpy, postgres: "postgres:14"}
           - {impl: c, python: "3.11", ext: numpy, postgres: "postgres:15"}
+          - {impl: c, python: "3.12", ext: gevent, postgres: "postgres:14"}
 
           # 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"}
+          - {impl: c, python: "3.9", ext: min, postgres: "postgres:15"}
 
           # Test memory alignment
           - {impl: c, python: "3.12", ext: align, postgres: "postgres:16"}
@@ -220,9 +218,7 @@ jobs:
       fail-fast: false
       matrix:
         include:
-          - {impl: python, python: "3.8"}
           - {impl: python, python: "3.9"}
-          - {impl: c, python: "3.8"}
           - {impl: c, python: "3.9"}
 
     env:
@@ -281,13 +277,11 @@ jobs:
       fail-fast: false
       matrix:
         include:
-          - {impl: python, python: "3.8"}
           - {impl: python, python: "3.9"}
           - {impl: python, python: "3.10"}
           - {impl: python, python: "3.11"}
           - {impl: python, python: "3.12"}
           - {impl: python, python: "3.13"}
-          - {impl: c, python: "3.8"}
           - {impl: c, python: "3.9"}
           - {impl: c, python: "3.10"}
           - {impl: c, python: "3.11"}
index c239cb8a517e1bb7565341f989a0d68919b3f4bd..084b7b9b7b440791e785f4db3e94bb6c6227fc0e 100644 (file)
@@ -22,10 +22,11 @@ Supported systems
 
 The Psycopg version documented here has *official and tested* support for:
 
-- Python: from version 3.8 to 3.13
+- Python: from version 3.9 to 3.13
 
-  - Python 3.6 supported before Psycopg 3.1
+  - Python 3.8 supported before Psycopg 3.3
   - Python 3.7 supported before Psycopg 3.2
+  - Python 3.6 supported before Psycopg 3.1
 
 - PyPy: from version 3.9 to 3.10
 
index bedb457e202466b37f8722cf8591d19673573499..6028da26905158865a1f8d80077ef8539d012d64 100644 (file)
@@ -7,16 +7,25 @@
 ``psycopg`` release notes
 =========================
 
-Current release
+Future releases
 ---------------
 
-Psycopg 3.2.4
-^^^^^^^^^^^^^
+Python 3.3.0 (unreleased)
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+- Drop support for Python 3.8.
+
+
+Psycopg 3.2.4 (unreleased)
+^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 - Make sure that the notifies callback is called during the use of the
   `~Connection.notifies()` generator (:ticket:`#972`).
 
 
+Current release
+---------------
+
 Psycopg 3.2.3
 ^^^^^^^^^^^^^
 
index d6a44f7fffb7b49206cdc437ff51041e3389e301..c379934d0c48f7ee08635b16deeb2a1d770fb1b8 100644 (file)
@@ -32,7 +32,7 @@ How to make a psycopg release
   .. __: https://github.com/psycopg/psycopg/actions/workflows/packages-bin.yml
   .. __: https://github.com/psycopg/psycopg/actions/workflows/packages-pool.yml
 
-- Delete the ``wheelhouse`` directory there is one.
+- Delete the ``wheelhouse`` directory if there is one.
 
 - Build m1 packages by running ``./tools/build/run_build_macos_arm64.sh BRANCH``.
   On successful completion it will save built packages in ``wheelhouse``
@@ -110,3 +110,25 @@ When a new Python major version is released
 - Update the list of versions in ``tools/build/build_macos_arm64.sh`` to include
   the new version. Look for both the ``python_versions`` variable and the
   ``CIBW_BUILD`` environment variable.
+
+
+When dropping end-of-life Python versions
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+- Update project metadata, ``requires-python`` and (maybe) package dependencies
+  in ``pyproject.toml`` files of the corresponding ``psycopg`` directories.
+
+- Update GitHub Actions workflow files in the ``.github/workflows/`` directory,
+  e.g., ``tests.yml``, ``.3rd-party-tests.yml``, ``packages-bin.yml``.
+
+- Bump versions in the ``tests/constraints.txt`` file if it is necessary.
+
+- You may grep throughout the project for occurrences of a version to be dropped.
+  However, favouring smaller pull requests is convenient and easy to review.
+  An example for grepping `end-of-life <https://endoflife.date/python>` Python 3.8::
+
+     git grep -E -e '\b3\.8\b' -e '\b(cp)?38\b' -e '\b3, 8\b'
+
+Examples:
+
+- `PR #977 <https://github.com/psycopg/psycopg/pull/977>`_
index d7290889d7119f9c539aeffaadb0e62f8bb9df75..83aeba36dbd78a1995d8f3ccebda40d7287db5a8 100644 (file)
@@ -13,7 +13,7 @@ from __future__ import annotations
 import queue
 import asyncio
 import threading
-from typing import Any, Callable, Coroutine, TYPE_CHECKING
+from typing import Any, Callable, Coroutine
 
 from ._compat import TypeAlias, TypeVar
 
@@ -21,26 +21,8 @@ Worker: TypeAlias = threading.Thread
 AWorker: TypeAlias = "asyncio.Task[None]"
 T = TypeVar("T")
 
-# Hack required on Python 3.8 because subclassing Queue[T] fails at runtime.
-# https://stackoverflow.com/questions/45414066/mypy-how-to-define-a-generic-subclass
-if TYPE_CHECKING:
-    _GQueue: TypeAlias = queue.Queue
-    _AGQueue: TypeAlias = asyncio.Queue
 
-else:
-
-    class FakeGenericMeta(type):
-        def __getitem__(self, item):
-            return self
-
-    class _GQueue(queue.Queue, metaclass=FakeGenericMeta):
-        pass
-
-    class _AGQueue(asyncio.Queue, metaclass=FakeGenericMeta):
-        pass
-
-
-class Queue(_GQueue[T]):
+class Queue(queue.Queue[T]):
     """
     A Queue subclass with an interruptible get() method.
     """
@@ -52,7 +34,7 @@ class Queue(_GQueue[T]):
         return super().get(block=block, timeout=timeout)
 
 
-class AQueue(_AGQueue[T]):
+class AQueue(asyncio.Queue[T]):
     pass
 
 
index b1e403183184a9c514939f8d0371c325da57f128..470a23855c609a3e27de0eb790843cfdc29f45c3 100644 (file)
@@ -7,8 +7,7 @@ Protocol objects representing different implementations of the same classes.
 from __future__ import annotations
 
 from typing import Any, Callable, Generator, Mapping
-from typing import Protocol, Sequence, TYPE_CHECKING
-from typing import Dict, Union  # drop with Python 3.8
+from typing import Protocol, Sequence, TYPE_CHECKING, Union
 
 from . import pq
 from ._enums import PyFormat as PyFormat
@@ -33,7 +32,7 @@ ConnectionType = TypeVar("ConnectionType", bound="BaseConnection[Any]")
 PipelineCommand: TypeAlias = Callable[[], None]
 DumperKey: TypeAlias = Union[type, "tuple[DumperKey, ...]"]
 ConnParam: TypeAlias = Union[str, int, None]
-ConnDict: TypeAlias = Dict[str, ConnParam]
+ConnDict: TypeAlias = dict[str, ConnParam]
 ConnMapping: TypeAlias = Mapping[str, ConnParam]
 
 
index 8e91fd2f57ee9e27d3535d25a8a861c811bfdb6a..56cfe2762c30650b6a108353d9b885449d4580ca 100644 (file)
@@ -6,8 +6,7 @@ Protocol objects to represent objects exposed by different pq implementations.
 
 from __future__ import annotations
 
-from typing import Any, Callable, Protocol, Sequence, TYPE_CHECKING
-from typing import Union  # drop with Python 3.8
+from typing import Any, Callable, Protocol, Sequence, TYPE_CHECKING, Union
 
 from ._enums import Format, Trace
 from .._compat import Self, TypeAlias
index fe97b7d567f04c78ace55baf629111ed07eba1b7..61c3d610a3be36fd7659947b42c740cd9f2c8d5b 100644 (file)
@@ -9,7 +9,6 @@ from __future__ import annotations
 import functools
 from typing import Any, Callable, NamedTuple, NoReturn
 from typing import TYPE_CHECKING, Protocol, Sequence
-from typing import Dict, Tuple  # drop with Python 3.8
 from collections import namedtuple
 
 from . import pq
@@ -83,13 +82,13 @@ class BaseRowFactory(Protocol[Row]):
     def __call__(self, __cursor: BaseCursor[Any, Any]) -> RowMaker[Row]: ...
 
 
-TupleRow: TypeAlias = Tuple[Any, ...]
+TupleRow: TypeAlias = tuple[Any, ...]
 """
 An alias for the type returned by `tuple_row()` (i.e. a tuple of any content).
 """
 
 
-DictRow: TypeAlias = Dict[str, Any]
+DictRow: TypeAlias = dict[str, Any]
 """
 An alias for the type returned by `dict_row()`
 
index efa2eddb8fe73cedb3b7638a6f65f9b48149f5ee..9550c1a2e260651538061e39c1f715e7e8571a7c 100644 (file)
@@ -13,8 +13,7 @@ classifiers = [
     "Operating System :: MacOS :: MacOS X",
     "Operating System :: Microsoft :: Windows",
     "Operating System :: POSIX",
-    "Programming Language :: Python :: 3",
-    "Programming Language :: Python :: 3.8",
+    "Programming Language :: Python :: 3 :: Only",
     "Programming Language :: Python :: 3.9",
     "Programming Language :: Python :: 3.10",
     "Programming Language :: Python :: 3.11",
@@ -27,9 +26,8 @@ classifiers = [
     "Topic :: Software Development",
     "Topic :: Software Development :: Libraries :: Python Modules",
 ]
-requires-python = ">= 3.8"
+requires-python = ">= 3.9"
 dependencies = [
-    "backports.zoneinfo >= 0.2.0; python_version < '3.9'",
     "typing-extensions >= 4.6; python_version < '3.13'",
     "tzdata; sys_platform == 'win32'",
 ]
index 2c9cf1fc5f53375968f97c5cd4a9f72a95e686ea..aa24b989e67d6eef0135a25ff0a9503b718a8242 100644 (file)
@@ -34,8 +34,7 @@ classifiers = [
     "Operating System :: Microsoft :: Windows",
     "Operating System :: POSIX",
     "Programming Language :: Cython",
-    "Programming Language :: Python :: 3",
-    "Programming Language :: Python :: 3.8",
+    "Programming Language :: Python :: 3 :: Only",
     "Programming Language :: Python :: 3.9",
     "Programming Language :: Python :: 3.10",
     "Programming Language :: Python :: 3.11",
@@ -47,7 +46,7 @@ classifiers = [
     "Topic :: Software Development",
     "Topic :: Software Development :: Libraries :: Python Modules",
 ]
-requires-python = ">= 3.8"
+requires-python = ">= 3.9"
 
 [[project.authors]]
 name = "Daniele Varrazzo"
index 9081d3ecd8647ae22503f942d52a15a8e45adb45..6f111ebf7af9fe831981f7554bd2cc9df1883f5e 100644 (file)
@@ -15,7 +15,7 @@ import queue
 import asyncio
 import logging
 import threading
-from typing import Any, Callable, Coroutine, TYPE_CHECKING
+from typing import Any, Callable, Coroutine
 
 from ._compat import TypeAlias, TypeVar
 
@@ -32,24 +32,6 @@ sleep = time.sleep
 Worker: TypeAlias = threading.Thread
 AWorker: TypeAlias = "asyncio.Task[None]"
 
-# Hack required on Python 3.8 because subclassing Queue[T] fails at runtime.
-# https://stackoverflow.com/questions/45414066/mypy-how-to-define-a-generic-subclass
-if TYPE_CHECKING:
-    _GQueue: TypeAlias = queue.Queue
-    _AGQueue: TypeAlias = asyncio.Queue
-
-else:
-
-    class FakeGenericMeta(type):
-        def __getitem__(self, item):
-            return self
-
-    class _GQueue(queue.Queue, metaclass=FakeGenericMeta):
-        pass
-
-    class _AGQueue(asyncio.Queue, metaclass=FakeGenericMeta):
-        pass
-
 
 def current_thread_name() -> str:
     return threading.current_thread().name
@@ -60,7 +42,7 @@ def current_task_name() -> str:
     return t.get_name() if t else "<no task>"
 
 
-class Queue(_GQueue[T]):
+class Queue(queue.Queue[T]):
     """
     A Queue subclass with an interruptible get() method.
     """
@@ -102,7 +84,7 @@ class ACondition(asyncio.Condition):
             return False
 
 
-class AQueue(_AGQueue[T]):
+class AQueue(asyncio.Queue[T]):
     pass
 
 
index 1c13cad1d05e4e0a035ad0b2f98cd38acab60443..d79f82f87ed30bd4040a71634a8964dfcda01276 100644 (file)
@@ -6,8 +6,7 @@ Types used in the psycopg_pool package
 
 from __future__ import annotations
 
-from typing import Awaitable, Callable, TYPE_CHECKING
-from typing import Union  # drop with Python 3.8
+from typing import Awaitable, Callable, TYPE_CHECKING, Union
 
 from ._compat import TypeAlias, TypeVar
 
index ef74372695143c62e01a5961b2d9cb5cbca6699b..a1c83857d8aa6dadab89d08524202e71cd6ef9cf 100644 (file)
@@ -13,8 +13,7 @@ classifiers = [
     "Operating System :: MacOS :: MacOS X",
     "Operating System :: Microsoft :: Windows",
     "Operating System :: POSIX",
-    "Programming Language :: Python :: 3",
-    "Programming Language :: Python :: 3.8",
+    "Programming Language :: Python :: 3 :: Only",
     "Programming Language :: Python :: 3.9",
     "Programming Language :: Python :: 3.10",
     "Programming Language :: Python :: 3.11",
@@ -27,7 +26,7 @@ classifiers = [
     "Topic :: Software Development",
     "Topic :: Software Development :: Libraries :: Python Modules",
 ]
-requires-python = ">= 3.8"
+requires-python = ">= 3.9"
 dependencies = [
     "typing-extensions >= 4.6",
 ]
index 172b52d618a61afacac3e1b566570826045f04d8..9c1dc90d44405f7b0f25fee2b74e4f9d0bf8feb2 100644 (file)
@@ -21,7 +21,7 @@ Test options
 
       $ pytest
       ========================= test session starts =========================
-      platform linux -- Python 3.8.5, pytest-6.0.2, py-1.10.0, pluggy-0.13.1
+      platform linux -- Python 3.9, pytest-6.0.2, py-1.10.0, pluggy-0.13.1
       Using --randomly-seed=2416596601
       libpq available: 130002
       libpq wrapper implementation: c
@@ -80,7 +80,7 @@ a set of env vars working for your setup::
 
     $ docker run -ti --rm --volume `pwd`:/src --workdir /src \
       -e PSYCOPG_TEST_DSN -e PGHOST=172.17.0.1 -e PGUSER=`whoami` \
-      python:3.8 bash
+      python:3.9 bash
 
     # pip install -e "./psycopg[test]" ./psycopg_pool ./psycopg_c
     # pytest
index 868b682ec0e19d7e34ee748f46d7a40388840876..0605b5a6e1c77cfdadf52ce48979b7b8f3e6049a 100644 (file)
@@ -118,7 +118,7 @@ class AEvent(asyncio.Event):
         await asyncio.wait_for(self.wait(), timeout)
 
 
-class Queue(queue.Queue):  # type: ignore[type-arg]  # can be dropped after Python 3.8
+class Queue(queue.Queue):  # type: ignore[type-arg]
     """
     A Queue subclass with an interruptible get() method.
     """
index 5341d2a75a2cdc3c01250982fc69e36872cee0db..89ecac84d4964a10c79214e2da5fee844bb4bb10 100644 (file)
@@ -35,8 +35,13 @@ 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.8.
-# Bump to a higher version when min supported python version increases past it.
-numpy == 1.18.0
+#
+# Warning: the versions specified for these packages are the oldest versions
+# offering a binary package for the oldest Python version we support.
+#
+# When the minimum supported Python version is increased, these dependencies
+# might need to be updated.
+#
+# Grep help: the current minimum supported version is Python 3.9.
+shapely == 1.8.0
+numpy == 1.20.0
index e4e3b56a98305c1e5bdc17290799df4be17a3bcd..a4a889a9dd9fc9fe0b5bf826bfeb3deb189ec8fc 100755 (executable)
@@ -9,7 +9,7 @@
 
 set -euo pipefail
 
-python_versions="3.8.19 3.9.19 3.10.14 3.11.9 3.12.5 3.13.0"
+python_versions="3.9.19 3.10.14 3.11.9 3.12.5 3.13.0"
 pg_version=17
 
 function log {
index 37dae36d31811c047f79b056c8aecb733c91f6ca..8c6c5a60b8d527c0d0cec543f5a2c6a89912850e 100755 (executable)
@@ -1,6 +1,5 @@
 #!/usr/bin/env python
-"""Bump the version number of the project.
-"""
+"""Bump the version number of the project."""
 
 from __future__ import annotations