Also drop from the test grid PostgreSQL 10, now unsupported.
matrix:
python-version:
- "3.11"
- - "3.7"
+ - "3.8"
sqlalchemy_label:
# what version of sqlalchemy to download is defined in the "include" section below,
# in the variable pip_sqlalchemy
fail-fast: false
matrix:
arch: [x86_64, i686, ppc64le, aarch64]
- pyver: [cp37, cp38, cp39, cp310, cp311, cp312]
+ pyver: [cp38, cp39, cp310, cp311, cp312]
platform: [manylinux, musllinux]
steps:
matrix:
# These archs require an Apple M1 runner: [arm64, universal2]
arch: [x86_64]
- pyver: [cp37, cp38, cp39, cp310, cp311, cp312]
+ pyver: [cp38, cp39, cp310, cp311, cp312]
steps:
- uses: actions/checkout@v3
matrix:
# Might want to add win32, untested at the moment.
arch: [win_amd64]
- pyver: [cp37, cp38, cp39, cp310, cp311, cp312]
+ pyver: [cp38, cp39, cp310, cp311, cp312]
steps:
- uses: actions/checkout@v3
matrix:
include:
# Test different combinations of Python, Postgres, libpq.
- - {impl: python, python: "3.7", postgres: "postgres:11", libpq: newest}
- - {impl: python, python: "3.8", postgres: "postgres:10"}
+ - {impl: python, python: "3.8", postgres: "postgres:11", libpq: newest}
- {impl: python, python: "3.9", postgres: "postgres:13"}
- {impl: python, python: "3.10", postgres: "postgres:14"}
- {impl: python, python: "3.11", postgres: "postgres:15", libpq: master}
- {impl: python, python: "3.12", postgres: "postgres:16", libpq: oldest}
- - {impl: c, python: "3.7", postgres: "postgres:16", libpq: newest}
- - {impl: c, python: "3.8", postgres: "postgres:14", libpq: master}
- - {impl: c, python: "3.9", postgres: "postgres:15"}
- - {impl: c, python: "3.10", postgres: "postgres:13"}
+ - {impl: c, python: "3.8", postgres: "postgres:16", libpq: newest}
+ - {impl: c, python: "3.9", postgres: "postgres:14", libpq: master}
+ - {impl: c, python: "3.10", postgres: "postgres:15"}
- {impl: c, python: "3.11", postgres: "postgres:12", libpq: oldest}
- - {impl: c, python: "3.12", postgres: "postgres:10", libpq: newest}
+ - {impl: c, python: "3.12", postgres: "postgres:11", libpq: newest}
- {impl: python, python: "3.9", ext: dns, postgres: "postgres:14"}
- {impl: python, python: "3.9", ext: postgis, postgres: "postgis/postgis"}
- {impl: c, python: "3.11", ext: numpy, postgres: "postgres:15"}
# Test with minimum dependencies versions
- - {impl: c, python: "3.7", ext: min, postgres: "postgres:15"}
+ - {impl: c, python: "3.8", ext: min, postgres: "postgres:15"}
env:
PSYCOPG_IMPL: ${{ matrix.impl }}
fail-fast: false
matrix:
include:
- - {impl: python, python: "3.7"}
- {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: c, python: "3.7"}
- {impl: c, python: "3.8"}
- {impl: c, python: "3.9"}
- {impl: c, python: "3.10"}
fail-fast: false
matrix:
include:
- - {impl: python, python: "3.7"}
- {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: c, python: "3.7"}
- {impl: c, python: "3.8"}
- {impl: c, python: "3.9"}
- {impl: c, python: "3.10"}
The Psycopg version documented here has *official and tested* support for:
-- Python: from version 3.7 to 3.12
+- Python: from version 3.8 to 3.12
- Python 3.6 supported before Psycopg 3.1
+ - Python 3.7 supported before Psycopg 3.2
- PostgreSQL: from version 10 to 16
- OS: Linux, macOS, Windows
# Copyright (C) 2021 The Psycopg Team
import sys
-import asyncio
-from typing import Any, Awaitable, Generator, Optional, Sequence, Union, TypeVar
-
-# NOTE: TypeAlias cannot be exported by this module, as pyright special-cases it.
-# For this raisin it must be imported directly from typing_extension where used.
-# See https://github.com/microsoft/pyright/issues/4197
-from typing_extensions import TypeAlias
-
-if sys.version_info >= (3, 8):
- from typing import Protocol
-else:
- from typing_extensions import Protocol
-
-T = TypeVar("T")
-FutureT: TypeAlias = Union["asyncio.Future[T]", Generator[Any, None, T], Awaitable[T]]
-
-if sys.version_info >= (3, 8):
- create_task = asyncio.create_task
- from math import prod
-
-else:
-
- def create_task(
- coro: FutureT[T], name: Optional[str] = None
- ) -> "asyncio.Future[T]":
- return asyncio.create_task(coro)
-
- from functools import reduce
-
- def prod(seq: Sequence[int]) -> int:
- return reduce(int.__mul__, seq, 1)
-
if sys.version_info >= (3, 9):
from zoneinfo import ZoneInfo
else:
from typing_extensions import LiteralString, assert_type
-if sys.version_info < (3, 8):
- import importlib_metadata as metadata
-else:
- from importlib import metadata
-
__all__ = [
"Counter",
"Deque",
"LiteralString",
- "Protocol",
"TypeGuard",
"ZoneInfo",
"assert_type",
"cache",
- "create_task",
- "prod",
- "metadata",
]
# Copyright (C) 2020 The Psycopg Team
import struct
-from typing import Callable, cast, Optional, Tuple
+from typing import Callable, cast, Optional, Protocol, Tuple
from typing_extensions import TypeAlias
from .abc import Buffer
from . import errors as e
-from ._compat import Protocol
PackInt: TypeAlias = Callable[[int], bytes]
UnpackInt: TypeAlias = Callable[[Buffer], Tuple[int]]
# Copyright (C) 2020 The Psycopg Team
from typing import Any, Callable, Generator, Mapping
-from typing import List, Optional, Sequence, Tuple, TypeVar, Union
+from typing import List, Optional, Protocol, Sequence, Tuple, TypeVar, Union
from typing import TYPE_CHECKING
from typing_extensions import TypeAlias
from . import pq
from ._enums import PyFormat as PyFormat
-from ._compat import Protocol, LiteralString
+from ._compat import LiteralString
if TYPE_CHECKING:
from . import sql
from . import adapt
from . import errors as e
from .abc import Buffer, ConnectionType, PQGen, Transformer
-from ._compat import create_task
from .pq.misc import connection_summary
from ._cmodule import _psycopg
from ._encodings import pgconn_encoding
async def write(self, data: Buffer) -> None:
if not self._worker:
- self._worker = create_task(self.worker())
+ self._worker = asyncio.create_task(self.worker())
if len(data) <= MAX_BUFFER_SIZE:
# Most used path: we don't need to split the buffer in smaller
# Copyright (C) 2020 The Psycopg Team
-from typing import Any, Callable, List, Optional, Sequence, Tuple
+from typing import Any, Callable, List, Optional, Protocol, Sequence, Tuple
from typing import Union, TYPE_CHECKING
from typing_extensions import TypeAlias
from ._enums import Format, Trace
-from .._compat import Protocol
if TYPE_CHECKING:
from .misc import PGnotify, ConninfoOption, PGresAttDesc
import functools
from typing import Any, Callable, Dict, List, Optional, NamedTuple, NoReturn
-from typing import TYPE_CHECKING, Sequence, Tuple, Type, TypeVar
+from typing import TYPE_CHECKING, Protocol, Sequence, Tuple, Type, TypeVar
from collections import namedtuple
from typing_extensions import TypeAlias
from . import pq
from . import errors as e
-from ._compat import Protocol
from ._encodings import _as_python_identifier
if TYPE_CHECKING:
import re
import struct
+from math import prod
from typing import Any, cast, Callable, List, Optional, Pattern, Set, Tuple, Type
from .. import pq
from ..abc import AdaptContext, Buffer, Dumper, DumperKey, NoneType, Loader, Transformer
from ..adapt import RecursiveDumper, RecursiveLoader, PyFormat
from .._oids import TEXT_OID, INVALID_OID, TEXT_ARRAY_OID
-from .._compat import cache, prod
+from .._compat import cache
from .._struct import pack_len, unpack_len
from .._cmodule import _psycopg
from .._typeinfo import TypeInfo
# Copyright (C) 2020 The Psycopg Team
-from ._compat import metadata
+from importlib import metadata
try:
__version__ = metadata.version("psycopg")
Operating System :: Microsoft :: Windows
Operating System :: POSIX
Programming Language :: Python :: 3
- Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
license_files = LICENSE.txt
[options]
-python_requires = >= 3.7
+python_requires = >= 3.8
packages = find:
zip_safe = False
install_requires =
backports.zoneinfo >= 0.2.0; python_version < "3.9"
typing-extensions >= 4.2
tzdata; sys_platform == "win32"
- importlib-metadata >= 1.4, < 6.8; python_version < "3.8"
[options.extras_require]
c =
+++ /dev/null
-"""
-compatibility functions for different Python versions
-"""
-
-# Copyright (C) 2021 The Psycopg Team
-
-import sys
-
-if sys.version_info < (3, 8):
- import importlib_metadata as metadata
-else:
- from importlib import metadata
-
-
-__all__ = ["metadata"]
# Copyright (C) 2020 The Psycopg Team
-from ._compat import metadata
+from importlib import metadata
try:
__version__ = metadata.version("psycopg-c")
Operating System :: Microsoft :: Windows
Operating System :: POSIX
Programming Language :: Python :: 3
- Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
license_files = LICENSE.txt
[options]
-python_requires = >= 3.7
+python_requires = >= 3.8
packages = find:
zip_safe = False
-install_requires =
- importlib-metadata >= 1.4, < 6.8; python_version < "3.8"
[options.package_data]
# NOTE: do not include .pyx files: they shouldn't be in the sdist
# Copyright (C) 2021 The Psycopg Team
import sys
-import asyncio
-from typing import Any, Awaitable, Generator, Optional, Union, Type, TypeVar
-from typing_extensions import TypeAlias
+from typing import Type
import psycopg.errors as e
-T = TypeVar("T")
-FutureT: TypeAlias = Union["asyncio.Future[T]", Generator[Any, None, T], Awaitable[T]]
-
-if sys.version_info >= (3, 8):
- create_task = asyncio.create_task
- Task = asyncio.Task
-
-else:
-
- def create_task(
- coro: FutureT[T], name: Optional[str] = None
- ) -> "asyncio.Future[T]":
- return asyncio.create_task(coro)
-
- Task = asyncio.Future
-
if sys.version_info >= (3, 9):
from collections import Counter, deque as Deque
else:
from typing import Counter, Deque
-if sys.version_info < (3, 8):
- import importlib_metadata as metadata
-else:
- from importlib import metadata
-
__all__ = [
"Counter",
"Deque",
- "Task",
- "create_task",
- "metadata",
]
# Workaround for psycopg < 3.0.8.
from typing import Any, AsyncIterator, Awaitable, Callable, cast, Generic
from typing import Dict, List, Optional, overload, Sequence, Type, TypeVar, Union
from typing_extensions import TypeAlias
+from asyncio import create_task, Task
from weakref import ref
from contextlib import asynccontextmanager
from .base import ConnectionAttempt, BasePool
from .sched import AsyncScheduler
from .errors import PoolClosed, PoolTimeout, TooManyRequests
-from ._compat import Task, create_task, Deque
+from ._compat import Deque
logger = logging.getLogger("psycopg.pool")
# Copyright (C) 2021 The Psycopg Team
-from ._compat import metadata
+from importlib import metadata
try:
__version__ = metadata.version("psycopg-pool")
Operating System :: Microsoft :: Windows
Operating System :: POSIX
Programming Language :: Python :: 3
- Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
license_files = LICENSE.txt
[options]
-python_requires = >= 3.7
+python_requires = >= 3.8
packages = find:
zip_safe = False
install_requires =
typing-extensions >= 3.10
- importlib-metadata >= 1.4, < 6.8; python_version < "3.8"
[options.package_data]
psycopg_pool = py.typed
$ docker run -ti --rm --volume `pwd`:/src --workdir /src \
-e PSYCOPG_TEST_DSN -e PGHOST=172.17.0.1 -e PGUSER=`whoami` \
- python:3.7 bash
+ python:3.8 bash
# pip install -e "./psycopg[test]" ./psycopg_pool ./psycopg_c
# pytest
asyncio_options: Dict[str, Any] = {}
-if sys.platform == "win32" and sys.version_info >= (3, 8):
+if sys.platform == "win32":
asyncio_options["policy"] = asyncio.WindowsSelectorEventLoopPolicy()
import psycopg.crdb
from psycopg import errors as e
from psycopg.crdb import AsyncCrdbConnection
-from psycopg._compat import create_task
import pytest
await asyncio.sleep(0.2)
await conn2.execute("cancel session %s", [session_id])
- t = create_task(closer())
+ t = asyncio.create_task(closer())
t0 = time.time()
try:
with pytest.raises(psycopg.OperationalError):
import pytest
from psycopg import pq, errors as e
from psycopg.rows import namedtuple_row
-from psycopg._compat import create_task
from .test_cursor import testfeed
except Exception as ex:
q.put_nowait(ex)
- t = create_task(worker())
+ t = asyncio.create_task(worker())
cur = aconn.cursor()
await cur.execute(f"insert into {testfeed} (data) values ('hello') returning id")
import logging
from time import time
from typing import Any, Dict, List, Tuple
+from asyncio import create_task
import pytest
from packaging.version import parse as ver # noqa: F401 # used in skipif
import psycopg
from psycopg.pq import TransactionStatus
from psycopg.rows import class_row, Row, TupleRow
-from psycopg._compat import assert_type, create_task
+from psycopg._compat import assert_type
from .test_pool_async import delay_connection, ensure_waiting
pytestmark = [pytest.mark.anyio]
assert 200 <= stats["connections_ms"] < 300
-@pytest.mark.skipif("sys.version_info < (3, 8)", reason="asyncio bug")
async def test_cancellation_in_queue(dsn):
# https://github.com/psycopg/psycopg/issues/509
pytest.fail("no client got in the queue")
[task.cancel() for task in reversed(tasks)]
- # Python 3.7 hangs on this statement, instead of timing out or returning
await asyncio.wait_for(asyncio.gather(*tasks, return_exceptions=True), 1.0)
stats = p.get_stats()
import logging
from time import time
from typing import Any, Dict, List, Tuple
+from asyncio import create_task
import pytest
import psycopg
from psycopg.pq import TransactionStatus
from psycopg.rows import class_row, Row, TupleRow
-from psycopg._compat import assert_type, create_task, Counter
+from psycopg._compat import assert_type, Counter
try:
import psycopg_pool as pool
logger.setLevel(old_level)
-@pytest.mark.skipif("sys.version_info < (3, 8)", reason="asyncio bug")
async def test_cancellation_in_queue(dsn):
# https://github.com/psycopg/psycopg/issues/509
pytest.fail("no client got in the queue")
[task.cancel() for task in reversed(tasks)]
- # Python 3.7 hangs on this statement, instead of timing out or returning
await asyncio.wait_for(asyncio.gather(*tasks, return_exceptions=True), 1.0)
stats = p.get_stats()
import asyncio
import logging
from time import time
+from asyncio import create_task
from functools import partial
import pytest
-from psycopg._compat import create_task
-
try:
from psycopg_pool.sched import AsyncScheduler
except ImportError:
import asyncio
import threading
import subprocess as sp
+from asyncio import create_task
from asyncio.queues import Queue
from typing import List, Tuple
import psycopg
from psycopg import errors as e
-from psycopg._compat import create_task
@pytest.mark.slow
from psycopg import Rollback
from psycopg import errors as e
-from psycopg._compat import create_task
from .test_transaction import in_transaction, insert_row, inserted, get_exc_info
from .test_transaction import ExpectedException, crdb_skip_external_observer
assert "transaction commit" in str(ex.value)
# Start a first transaction in a task
- t1 = create_task(worker(unlock=evs[0], wait_on=evs[1]))
+ t1 = asyncio.create_task(worker(unlock=evs[0], wait_on=evs[1]))
await evs[0].wait()
# Start a nested transaction in a task
- t2 = create_task(worker(unlock=evs[1], wait_on=evs[2]))
+ t2 = asyncio.create_task(worker(unlock=evs[1], wait_on=evs[2]))
# Terminate the first transaction before the second does
await asyncio.gather(t1)
import gc
+from math import prod
from typing import List, Any
from decimal import Decimal
from psycopg import sql
from psycopg.adapt import PyFormat, Transformer, Dumper
from psycopg.types import TypeInfo
-from psycopg._compat import prod
from psycopg.postgres import types as builtins
from psycopg.types.array import register_array