]> git.ipfire.org Git - thirdparty/psycopg.git/commitdiff
Drop support for Python 3.6
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>
Sat, 8 Jan 2022 20:57:14 +0000 (21:57 +0100)
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>
Sat, 8 Jan 2022 20:57:14 +0000 (21:57 +0100)
26 files changed:
.github/workflows/packages.yml
.github/workflows/tests.yml
docs/basic/install.rst
docs/news.rst
psycopg/psycopg/_compat.py
psycopg/psycopg/_context.py [deleted file]
psycopg/psycopg/connection_async.py
psycopg/psycopg/cursor.py
psycopg/psycopg/cursor_async.py
psycopg/psycopg/types/datetime.py
psycopg/setup.cfg
psycopg/tox.ini
psycopg_c/psycopg_c/types/datetime.pyx
psycopg_c/setup.cfg
psycopg_c/tox.ini
psycopg_pool/psycopg_pool/_compat.py
psycopg_pool/psycopg_pool/pool_async.py
psycopg_pool/setup.cfg
pyproject.toml
tests/conftest.py
tests/fix_faker.py
tests/pool/test_pool.py
tests/pool/test_pool_async.py
tests/test_typing.py
tests/types/test_datetime.py
tests/types/test_net.py

index fc5c2c3744a9b57f59461649b46205ce2e32bf3a..56b04c38fcdbee34c5907fdc6b493013168679b8 100644 (file)
@@ -84,7 +84,7 @@ jobs:
       fail-fast: false
       matrix:
         arch: [x86_64, i686, ppc64le, aarch64]
-        pyver: [cp36, cp37, cp38, cp39, cp310]
+        pyver: [cp37, cp38, cp39, cp310]
         platform: [manylinux, musllinux]
 
     steps:
@@ -150,7 +150,7 @@ jobs:
       matrix:
         # These archs require an Apple M1 runner: [arm64, universal2]
         arch: [x86_64]
-        pyver: [cp36, cp37, cp38, cp39, cp310]
+        pyver: [cp37, cp38, cp39, cp310]
 
     steps:
       - uses: actions/checkout@v2
@@ -187,7 +187,7 @@ jobs:
       matrix:
         # Might want to add win32, untested at the moment.
         arch: [win_amd64]
-        pyver: [cp36, cp37, cp38, cp39, cp310]
+        pyver: [cp37, cp38, cp39, cp310]
 
     steps:
       - uses: actions/checkout@v2
index e22c7288020333d8c540dc3a8179e896e734221b..438fb88699398cbf3db40d838eba991514217145 100644 (file)
@@ -20,15 +20,13 @@ jobs:
       matrix:
         include:
           # Test different combinations of Python, Postgres, libpq.
-          - {impl: python, python: "3.6", postgres: "postgres:10", libpq: "newest"}
-          - {impl: python, python: "3.7", postgres: "postgres:11", libpq: ""}
+          - {impl: python, python: "3.7", postgres: "postgres:10", libpq: "newest"}
           - {impl: python, python: "3.8", postgres: "postgres:12", libpq: ""}
           - {impl: python, python: "3.9", postgres: "postgres:13", libpq: "newest"}
           - {impl: python, python: "3.10", postgres: "postgres:14", libpq: "oldest"}
-          - {impl: c, python: "3.6", postgres: "postgres:14", libpq: "oldest"}
-          - {impl: c, python: "3.7", postgres: "postgres:13", libpq: ""}
-          - {impl: c, python: "3.8", postgres: "postgres:12", libpq: "newest"}
-          - {impl: c, python: "3.9", postgres: "postgres:11", libpq: ""}
+          - {impl: c, python: "3.7", postgres: "postgres:14", libpq: "oldest"}
+          - {impl: c, python: "3.8", postgres: "postgres:13", libpq: "newest"}
+          - {impl: c, python: "3.9", postgres: "postgres:12", libpq: ""}
           - {impl: c, python: "3.10", postgres: "postgres:10", libpq: "oldest"}
           - {impl: dns, python: "3.9", postgres: "postgres:14", libpq: ""}
           - {impl: postgis, python: "3.9", postgres: "postgis/postgis", libpq: ""}
@@ -116,12 +114,10 @@ jobs:
       fail-fast: false
       matrix:
         include:
-          - {impl: python, python: "3.6"}
           - {impl: python, python: "3.7"}
           - {impl: python, python: "3.8"}
           - {impl: python, python: "3.9"}
           - {impl: python, python: "3.10"}
-          - {impl: c, python: "3.6"}
           - {impl: c, python: "3.7"}
           - {impl: c, python: "3.8"}
           - {impl: c, python: "3.9"}
@@ -169,12 +165,10 @@ jobs:
       fail-fast: false
       matrix:
         include:
-          - {impl: python, python: "3.6"}
           - {impl: python, python: "3.7"}
           - {impl: python, python: "3.8"}
           - {impl: python, python: "3.9"}
           - {impl: python, python: "3.10"}
-          - {impl: c, python: "3.6"}
           - {impl: c, python: "3.7"}
           - {impl: c, python: "3.8"}
           - {impl: c, python: "3.9"}
index a7c8a48abaa0a819691e8d15b1e232d35a6e9b6b..c7f395c7038d840e5a259aaf6c319a241e68e165 100644 (file)
@@ -19,7 +19,10 @@ Supported systems
 
 The Psycopg version documented here has *official and tested* support for:
 
-- Python: from version 3.6 to 3.10
+- Python: from version 3.7 to 3.10
+
+  - Python 3.6 supported before Psycopg 3.1
+
 - PostgreSQL: from version 10 to 14
 - OS: Linux, macOS, Windows
 
index 2be27824da9319d9f52e07aa6ec06fe302fb6c34..f6ae9468e1e7f50fe90750707e673f0b7df40357 100644 (file)
@@ -18,6 +18,7 @@ Psycopg 3.1 (unreleased)
   result set can be accessed by calling `~Cursor.nextset()` (:ticket:`#164`).
 - Add `pq.PGconn.trace()` and related trace functions (:ticket:`#167`).
 - Add *prepare_threshold* parameter to `Connection` init (:ticket:`#200`).
+- Drop support for Python 3.6.
 
 
 Current release
index 44053ee5d80871c5f33d90b141d45cd0d65ff298..36bc892fd24c4a4c160ba1ee5cd1ec6936fc18c6 100644 (file)
@@ -16,33 +16,15 @@ else:
 T = TypeVar("T")
 FutureT = Union["asyncio.Future[T]", Generator[Any, None, T], Awaitable[T]]
 
-if sys.version_info >= (3, 7):
-    from contextlib import asynccontextmanager
-
-    get_running_loop = asyncio.get_running_loop
-
-else:
-    from ._context import asynccontextmanager
-
-    get_running_loop = asyncio.get_event_loop
-
-
 if sys.version_info >= (3, 8):
     create_task = asyncio.create_task
 
-elif sys.version_info >= (3, 7):
-
-    def create_task(
-        coro: FutureT[T], name: Optional[str] = None
-    ) -> "asyncio.Future[T]":
-        return asyncio.create_task(coro)
-
 else:
 
     def create_task(
         coro: FutureT[T], name: Optional[str] = None
     ) -> "asyncio.Future[T]":
-        return asyncio.ensure_future(coro)
+        return asyncio.create_task(coro)
 
 
 if sys.version_info >= (3, 9):
@@ -57,7 +39,5 @@ __all__ = [
     "Deque",
     "Protocol",
     "ZoneInfo",
-    "asynccontextmanager",
     "create_task",
-    "get_running_loop",
 ]
diff --git a/psycopg/psycopg/_context.py b/psycopg/psycopg/_context.py
deleted file mode 100644 (file)
index 906fa0f..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-# type: ignore
-"""
-asynccontextmanager implementation for Python < 3.7
-"""
-
-from functools import wraps
-
-
-def asynccontextmanager(func):
-    @wraps(func)
-    def helper(*args, **kwds):
-        return _AsyncGeneratorContextManager(func, args, kwds)
-
-    return helper
-
-
-class _AsyncGeneratorContextManager:
-    """Helper for @asynccontextmanager."""
-
-    def __init__(self, func, args, kwds):
-        self.gen = func(*args, **kwds)
-        self.func, self.args, self.kwds = func, args, kwds
-        doc = getattr(func, "__doc__", None)
-        if doc is None:
-            doc = type(self).__doc__
-        self.__doc__ = doc
-
-    async def __aenter__(self):
-        try:
-            return await self.gen.__anext__()
-        except StopAsyncIteration:
-            raise RuntimeError("generator didn't yield") from None
-
-    async def __aexit__(self, typ, value, traceback):
-        if typ is None:
-            try:
-                await self.gen.__anext__()
-            except StopAsyncIteration:
-                return
-            else:
-                raise RuntimeError("generator didn't stop")
-        else:
-            if value is None:
-                value = typ()
-            try:
-                await self.gen.athrow(typ, value, traceback)
-                raise RuntimeError("generator didn't stop after athrow()")
-            except StopAsyncIteration as exc:
-                return exc is not value
-            except RuntimeError as exc:
-                if exc is value:
-                    return False
-                if isinstance(value, (StopIteration, StopAsyncIteration)):
-                    if exc.__cause__ is value:
-                        return False
-                raise
-            except BaseException as exc:
-                if exc is not value:
-                    raise
index c940b279bdcd307982ea656c1edb68e7c06ea3a6..3382c5d0f863bafb84a661096d03520a4bf7a57a 100644 (file)
@@ -10,6 +10,7 @@ import logging
 from types import TracebackType
 from typing import Any, AsyncGenerator, AsyncIterator, Dict, List, Optional
 from typing import Type, Union, cast, overload, TYPE_CHECKING
+from contextlib import asynccontextmanager
 
 from . import errors as e
 from . import waiting
@@ -19,7 +20,6 @@ from ._tpc import Xid
 from .rows import Row, AsyncRowFactory, tuple_row, TupleRow, args_row
 from .adapt import AdaptersMap
 from ._enums import IsolationLevel
-from ._compat import asynccontextmanager, get_running_loop
 from .conninfo import make_conninfo, conninfo_to_dict
 from ._encodings import pgconn_encoding
 from .connection import BaseConnection, CursorRow, Notify
@@ -97,7 +97,7 @@ class AsyncConnection(BaseConnection[Row]):
     ) -> "AsyncConnection[Any]":
 
         if sys.platform == "win32":
-            loop = get_running_loop()
+            loop = asyncio.get_running_loop()
             if isinstance(loop, asyncio.ProactorEventLoop):
                 raise e.InterfaceError(
                     "Psycopg cannot use the 'ProactorEventLoop' to run in async"
index 99dc9c14ee8f54309fc519b102296dd96af0bcef..ada4e8510f308b7c043442385ea3e3addc0c6da3 100644 (file)
@@ -4,7 +4,6 @@ psycopg cursor objects
 
 # Copyright (C) 2020 The Psycopg Team
 
-import sys
 from types import TracebackType
 from typing import Any, Generic, Iterable, Iterator, List
 from typing import Optional, NoReturn, Sequence, Type, TypeVar, TYPE_CHECKING
@@ -45,15 +44,12 @@ _C = TypeVar("_C", bound="Cursor[Any]")
 
 
 class BaseCursor(Generic[ConnectionType, Row]):
-    # Slots with __weakref__ and generic bases don't work on Py 3.6
-    # https://bugs.python.org/issue41451
-    if sys.version_info >= (3, 7):
-        __slots__ = """
-            _conn format _adapters arraysize _closed _results pgresult _pos
-            _iresult _rowcount _query _tx _last_query _row_factory _make_row
-            _pgconn _encoding
-            __weakref__
-            """.split()
+    __slots__ = """
+        _conn format _adapters arraysize _closed _results pgresult _pos
+        _iresult _rowcount _query _tx _last_query _row_factory _make_row
+        _pgconn _encoding
+        __weakref__
+        """.split()
 
     ExecStatus = pq.ExecStatus
 
index 7777d7445cc0780fdbdeced78d9065a32a861cfc..323b77a4de1611db19c66ed216e83b0225eba6da 100644 (file)
@@ -7,6 +7,7 @@ psycopg async cursor objects
 from types import TracebackType
 from typing import Any, AsyncIterator, Iterable, List
 from typing import Optional, Type, TypeVar, TYPE_CHECKING
+from contextlib import asynccontextmanager
 
 from . import errors as e
 
@@ -14,7 +15,6 @@ from .abc import Query, Params
 from .copy import AsyncCopy
 from .rows import Row, RowMaker, AsyncRowFactory
 from .cursor import BaseCursor
-from ._compat import asynccontextmanager
 
 if TYPE_CHECKING:
     from .connection_async import AsyncConnection
index 007e705f77e763078a95e4633793e419429132b2..7ba84044d1df86a548da735f66c0d0389e390a8c 100644 (file)
@@ -5,7 +5,6 @@ Adapters for date/time types.
 # Copyright (C) 2020 The Psycopg Team
 
 import re
-import sys
 import struct
 from datetime import date, datetime, time, timedelta, timezone
 from typing import Any, Callable, cast, Optional, Tuple, TYPE_CHECKING
@@ -334,8 +333,6 @@ class TimeBinaryLoader(Loader):
 
 class TimetzLoader(Loader):
 
-    _py37 = sys.version_info >= (3, 7)
-
     _re_format = re.compile(
         rb"""(?ix)
         ^
@@ -365,7 +362,7 @@ class TimetzLoader(Loader):
         off = 60 * 60 * int(oh)
         if om:
             off += 60 * int(om)
-        if os and self._py37:
+        if os:
             off += int(os)
         tz = timezone(timedelta(0, off if sgn == b"+" else -off))
 
@@ -388,26 +385,12 @@ class TimetzBinaryLoader(Loader):
         h, m = divmod(val, 60)
 
         try:
-            return time(h, m, s, us, self._tz_from_sec(off))
+            return time(h, m, s, us, timezone(timedelta(seconds=-off)))
         except ValueError:
             raise DataError(
                 f"time not supported by Python: hour={h}"
             ) from None
 
-    def _tz_from_sec(self, sec: int) -> timezone:
-        return timezone(timedelta(seconds=-sec))
-
-    def _tz_from_sec_36(self, sec: int) -> timezone:
-        if sec % 60:
-            sec = round(sec / 60.0) * 60
-        return timezone(timedelta(seconds=-sec))
-
-
-if sys.version_info < (3, 7):
-    setattr(
-        TimetzBinaryLoader, "_tz_from_sec", TimetzBinaryLoader._tz_from_sec_36
-    )
-
 
 class TimestampLoader(Loader):
 
index 81e157d2290ab169934571b47a251b20e0e322c9..f0d3b9f9736db038eca52c106abb062e5318482b 100644 (file)
@@ -20,7 +20,6 @@ classifiers =
     Operating System :: Microsoft :: Windows
     Operating System :: POSIX
     Programming Language :: Python :: 3
-    Programming Language :: Python :: 3.6
     Programming Language :: Python :: 3.7
     Programming Language :: Python :: 3.8
     Programming Language :: Python :: 3.9
@@ -35,12 +34,11 @@ long_description_content_type = text/x-rst
 license_file = LICENSE.txt
 
 [options]
-python_requires = >= 3.6
+python_requires = >= 3.7
 packages = find:
 zip_safe = False
 install_requires =
     backports.zoneinfo >= 0.2.0; python_version < "3.9"
-    dataclasses >= 0.8; python_version < "3.7"
     typing_extensions >= 3.10; python_version < "3.8"
 
 [options.package_data]
index 3ffe8c36b2c0c7e909a1f5014a26b0a5da5b7dfb..201a90eb4c5592989abc80147ff2446968164522 100644 (file)
@@ -1,5 +1,5 @@
 [tox]
-envlist = {3.6,3.7,3.8,3.9,3.10}
+envlist = {3.7,3.8,3.9,3.10}
 isolated_build = True
 
 [testenv]
index 448ddd173b73d018cf83ec8607184f3f2b72cbb5..ddb7eaf73e9a9e672419e8d25bf115398bc38c04 100644 (file)
@@ -8,7 +8,6 @@ from libc.string cimport memset, strchr
 from cpython cimport datetime as cdt
 from cpython.dict cimport PyDict_GetItem
 from cpython.object cimport PyObject, PyObject_CallFunctionObjArgs
-from cpython.version cimport PY_VERSION_HEX
 
 cdef extern from "Python.h":
     const char *PyUnicode_AsUTF8AndSize(unicode obj, Py_ssize_t *size) except NULL
@@ -16,11 +15,6 @@ cdef extern from "Python.h":
 
 cdef extern from *:
     """
-/* Hack to compile on Python 3.6 */
-#if PY_VERSION_HEX < 0x03070000
-#define PyTimeZone_FromOffset(x) x
-#endif
-
 /* Multipliers from fraction of seconds to microseconds */
 static int _uspad[] = {0, 100000, 10000, 1000, 100, 10, 1};
     """
@@ -502,10 +496,6 @@ cdef class TimetzLoader(CLoader):
             s = bytes(data).decode("utf8", "replace")
             raise e.DataError(f"can't parse timetz {s!r}")
 
-        # Python < 3.7 didn't support seconds in the timezones
-        if PY_VERSION_HEX < 0x03070000:
-            offsecs = round(offsecs / 60.0) * 60
-
         tz = _timezone_from_seconds(offsecs)
         try:
             return cdt.time_new(vals[0], vals[1], vals[2], us, tz)
@@ -534,10 +524,6 @@ cdef class TimetzBinaryLoader(CLoader):
             m = val % 60
             h = <int>(val // 60)
 
-            # Python < 3.7 didn't support seconds in the timezones
-            if PY_VERSION_HEX >= 0x03070000:
-                off = round(off / 60.0) * 60
-
         tz = _timezone_from_seconds(-off)
         try:
             return cdt.time_new(h, m, s, us, tz)
@@ -1097,10 +1083,7 @@ cdef object _timezone_from_seconds(int sec, __cache={}):
         return <object>ptr
 
     delta = cdt.timedelta_new(0, sec, 0)
-    if PY_VERSION_HEX >= 0x03070000:
-        tz = PyTimeZone_FromOffset(delta)
-    else:
-        tz = timezone(delta)
+    tz = timezone(delta)
     __cache[pysec] = tz
     return tz
 
@@ -1122,12 +1105,7 @@ cdef object _timezone_from_connection(pq.PGconn pgconn):
     sname = tzname.decode() if tzname else "UTC"
     try:
         zi = ZoneInfo(sname)
-    # Usually KeyError, but might be a DeprecationWarning raised by -Werror
-    # (experienced on Python 3.6.12, backport.zoneinfo 0.2.1).
-    # https://github.com/pganssle/zoneinfo/issues/109
-    # Curiously, not trapping the latter, causes a segfault.
-    # In such case the error message is wrong, but hey.
-    except Exception:
+    except KeyError:
         logger = logging.getLogger("psycopg")
         logger.warning(
             "unknown PostgreSQL timezone: %r; will use UTC", sname
index 45d17534929d17d929030a67f5a41ab1a0cde8b1..62f347ccf97dd45b55fc8cfab8ccd26bc4b9e5f2 100644 (file)
@@ -20,7 +20,6 @@ classifiers =
     Operating System :: Microsoft :: Windows
     Operating System :: POSIX
     Programming Language :: Python :: 3
-    Programming Language :: Python :: 3.6
     Programming Language :: Python :: 3.7
     Programming Language :: Python :: 3.8
     Programming Language :: Python :: 3.9
@@ -35,7 +34,7 @@ long_description_content_type = text/x-rst
 license_file = LICENSE.txt
 
 [options]
-python_requires = >= 3.6
+python_requires = >= 3.7
 setup_requires = Cython >= 3.0a5
 packages = find:
 zip_safe = False
index 421d3f88b081ab121ae047b07e2ab78c35e0e803..a1acf58206b678444b910f9ce97d2247e2151c16 100644 (file)
@@ -1,5 +1,5 @@
 [tox]
-envlist = {3.6,3.7,3.8,3.9,3.10}
+envlist = {3.7,3.8,3.9,3.10}
 isolated_build = True
 
 [testenv]
index d91ca7b3e4771acde1a5cc3122de1790b3ca1ee5..f666e677cd8656d590f315672a83afacdf2dc363 100644 (file)
@@ -11,38 +11,16 @@ from typing import Any, Awaitable, Generator, Optional, Union, TypeVar
 T = TypeVar("T")
 FutureT = Union["asyncio.Future[T]", Generator[Any, None, T], Awaitable[T]]
 
-if sys.version_info >= (3, 7):
-    from contextlib import asynccontextmanager
-else:
-
-    def asynccontextmanager(func):
-        def helper(*args, **kwds):
-            raise NotImplementedError(
-                "async pool not implemented on Python 3.6"
-            )
-
-        return helper
-
-
 if sys.version_info >= (3, 8):
     create_task = asyncio.create_task
     Task = asyncio.Task
 
-elif sys.version_info >= (3, 7):
-
-    def create_task(
-        coro: FutureT[T], name: Optional[str] = None
-    ) -> "asyncio.Future[T]":
-        return asyncio.create_task(coro)
-
-    Task = asyncio.Future
-
 else:
 
     def create_task(
         coro: FutureT[T], name: Optional[str] = None
     ) -> "asyncio.Future[T]":
-        return asyncio.ensure_future(coro)
+        return asyncio.create_task(coro)
 
     Task = asyncio.Future
 
@@ -55,6 +33,5 @@ __all__ = [
     "Counter",
     "Deque",
     "Task",
-    "asynccontextmanager",
     "create_task",
 ]
index e92209733ac22c8feac92104447a638f95344df4..b74bc5c5e47896a8dfe6c69f662aa74ec97ee878 100644 (file)
@@ -4,7 +4,6 @@ psycopg asynchronous connection pool
 
 # Copyright (C) 2021 The Psycopg Team
 
-import sys
 import asyncio
 import logging
 from abc import ABC, abstractmethod
@@ -13,6 +12,7 @@ from types import TracebackType
 from typing import Any, AsyncIterator, Awaitable, Callable
 from typing import Dict, List, Optional, Sequence, Type
 from weakref import ref
+from contextlib import asynccontextmanager
 
 from psycopg import errors as e
 from psycopg.pq import TransactionStatus
@@ -21,7 +21,7 @@ from psycopg.connection_async import AsyncConnection
 from .base import ConnectionAttempt, BasePool
 from .sched import AsyncScheduler
 from .errors import PoolClosed, PoolTimeout, TooManyRequests
-from ._compat import Task, asynccontextmanager, create_task, Deque
+from ._compat import Task, create_task, Deque
 
 logger = logging.getLogger("psycopg.pool")
 
@@ -41,12 +41,6 @@ class AsyncConnectionPool(BasePool[AsyncConnection[Any]]):
         ] = None,
         **kwargs: Any,
     ):
-        # https://bugs.python.org/issue42600
-        if sys.version_info < (3, 7):
-            raise e.NotSupportedError(
-                "async pool not supported before Python 3.7"
-            )
-
         self.connection_class = connection_class
         self._configure = configure
         self._reset = reset
index 25aced6798731ed5a6c42be43479afc8585a1101..8d142b5cfb6a36eb884de7055d5009dfaff4b232 100644 (file)
@@ -20,7 +20,6 @@ classifiers =
     Operating System :: Microsoft :: Windows
     Operating System :: POSIX
     Programming Language :: Python :: 3
-    Programming Language :: Python :: 3.6
     Programming Language :: Python :: 3.7
     Programming Language :: Python :: 3.8
     Programming Language :: Python :: 3.9
@@ -35,7 +34,7 @@ long_description_content_type = text/x-rst
 license_file = LICENSE.txt
 
 [options]
-python_requires = >= 3.6
+python_requires = >= 3.7
 packages = find:
 zip_safe = False
 # Maybe it can be useful after release, now it gets in the way.
index b05c86604fcb23e1c52a7f6c8478c5ee22e16cbc..cb9993946263af3d73c276e874f121e51b91d171 100644 (file)
@@ -8,8 +8,6 @@ line-length = 79
 [tool.pytest.ini_options]
 filterwarnings = [
     "error",
-    # The zoneinfo warning ignore is only required on Python 3.6
-    "ignore::DeprecationWarning:backports.zoneinfo._common",
 ]
 testpaths=[
     "tests",
index 588fa8affc4beb374739f559f15f6d70ea19e2e2..d22c86f860c556dc688ce44ad98c640340eb6d2d 100644 (file)
@@ -78,13 +78,7 @@ def event_loop(request):
 
     loop = None
     if sys.platform == "win32":
-        if sys.version_info < (3, 7):
-            loop = asyncio.SelectorEventLoop()
-            asyncio.set_event_loop(loop)
-        else:
-            asyncio.set_event_loop_policy(
-                asyncio.WindowsSelectorEventLoopPolicy()
-            )
+        asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
     if not loop:
         loop = asyncio.get_event_loop_policy().new_event_loop()
     yield loop
index 4d0f9a18745c2f531263f085737e7a42853cde5b..db26d4de573651c998a43456a91ecf22aac7fea5 100644 (file)
@@ -4,16 +4,16 @@ import ipaddress
 from math import isnan
 from uuid import UUID
 from random import choice, random, randrange
-from decimal import Decimal
-from contextlib import contextmanager
 from typing import Any, List, Set, Tuple, Union
+from decimal import Decimal
+from contextlib import contextmanager, asynccontextmanager
 
 import pytest
 
 import psycopg
 from psycopg import sql
 from psycopg.adapt import PyFormat
-from psycopg._compat import asynccontextmanager, Deque
+from psycopg._compat import Deque
 from psycopg.types.range import Range
 from psycopg.types.numeric import Int4, Int8
 from psycopg.types.multirange import Multirange
index 45cc33b4e9938d60e44a6a8906c5b886bf5390ff..f30d8513c4398b8661f5226ad8955f8cb41316eb 100644 (file)
@@ -1,4 +1,3 @@
-import sys
 import logging
 import weakref
 from time import sleep, time
@@ -1026,16 +1025,6 @@ def test_check_idle(dsn):
             assert conn.info.transaction_status == TransactionStatus.IDLE
 
 
-@pytest.mark.skipif(
-    sys.version_info >= (3, 7), reason="async pool supported from Python 3.7"
-)
-def test_async_pool_not_supported(dsn):
-    # note: this test is here because the all the ones in test_pool_async are
-    # skipped on Py 3.6
-    with pytest.raises(psycopg.NotSupportedError):
-        pool.AsyncConnectionPool(dsn)
-
-
 @pytest.mark.slow
 @pytest.mark.timing
 def test_stats_measures(dsn):
index 923fb84e0cdb231ae61b4f0f008f23151d2d0fee..d4aa5db8dde276b638ceb0a75c6260256280dde2 100644 (file)
@@ -1,4 +1,3 @@
-import sys
 import asyncio
 import logging
 from time import time
@@ -16,13 +15,7 @@ except ImportError:
     # Tests should have been skipped if the package is not available
     pass
 
-pytestmark = [
-    pytest.mark.asyncio,
-    pytest.mark.skipif(
-        sys.version_info < (3, 7),
-        reason="async pool not supported before Python 3.7",
-    ),
-]
+pytestmark = [pytest.mark.asyncio]
 
 
 async def test_defaults(dsn):
index 97e79577fb05d9c7a0ce2d1dd1dd4829c413c2c5..9937ff7d1a93b0d13f2fc0498b449d80461537e9 100644 (file)
@@ -1,5 +1,4 @@
 import os
-import sys
 
 import pytest
 
@@ -8,15 +7,7 @@ HERE = os.path.dirname(os.path.abspath(__file__))
 
 @pytest.mark.parametrize(
     "filename",
-    [
-        "adapters_example.py",
-        pytest.param(
-            "typing_example.py",
-            marks=pytest.mark.skipif(
-                sys.version_info < (3, 7), reason="no future annotations"
-            ),
-        ),
-    ],
+    ["adapters_example.py", "typing_example.py"],
 )
 def test_typing_example(mypy, filename):
     cp = mypy.run_on_file(os.path.join(HERE, filename))
index 7d51cfa028e6903dc1b6b96ff09e51e0b62eaf24..8d50a85aa583f683a2bb967d2cd66ea3d393d7cf 100644 (file)
@@ -351,16 +351,12 @@ class TestDateTimeTz:
         assert rec[0] == want
         assert rec[1] == 11111111
 
-    tz_sec = pytest.mark.skipif(
-        sys.version_info < (3, 7), reason="no seconds in tz offset"
-    )
-
     @pytest.mark.xfail(sys.platform == "win32", reason="no IANA db on Windows")
     @pytest.mark.parametrize(
         "valname, tzval, tzname",
         [
             ("max", "-06", "America/Chicago"),
-            pytest.param("min", "+09:18:59", "Asia/Tokyo", marks=[tz_sec]),
+            ("min", "+09:18:59", "Asia/Tokyo"),
         ],
     )
     @pytest.mark.parametrize("fmt_out", pq.Format)
index ca98d1f17ef73c73b8ae3e6662f6857c929aba05..1deaf2d73e82298e8fa3ec508635f13f8d592f10 100644 (file)
@@ -140,9 +140,7 @@ def test_lazy_load(dsn):
 import sys
 import psycopg
 
-# In 3.6 it seems already loaded (at least on Travis).
-if sys.version_info >= (3, 7):
-    assert 'ipaddress' not in sys.modules
+assert 'ipaddress' not in sys.modules
 
 conn = psycopg.connect({dsn!r})
 with conn.cursor() as cur: