diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 050de749..7c349b2c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -25,28 +25,17 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] + python-version: ["3.8", "3.9", "3.10", "3.11"] edgedb-version: [stable , nightly] - os: [ubuntu-20.04, ubuntu-latest, macos-latest, windows-2019] + os: [ubuntu-latest, macos-latest, windows-2019] loop: [asyncio, uvloop] exclude: # uvloop does not support windows - loop: uvloop os: windows-2019 - # Python 3.7 on ubuntu-22.04 has a broken OpenSSL 3.0 - - python-version: 3.7 - os: ubuntu-latest - - python-version: 3.8 - os: ubuntu-20.04 - - python-version: 3.9 - os: ubuntu-20.04 - - python-version: 3.10 - os: ubuntu-20.04 - - python-version: 3.11 - os: ubuntu-20.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: fetch-depth: 50 submodules: true @@ -109,7 +98,7 @@ jobs: regression-tests: name: "Regression Tests" needs: [test] - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - run: echo OK diff --git a/README.rst b/README.rst index 8b52d2ae..d58fff71 100644 --- a/README.rst +++ b/README.rst @@ -14,7 +14,7 @@ The Python driver for EdgeDB **edgedb-python** is the official EdgeDB driver for Python. It provides both blocking IO and asyncio implementations. -The library requires Python 3.7 or later. +The library requires Python 3.8 or later. Documentation diff --git a/edgedb/_testbase.py b/edgedb/_testbase.py index 47667add..5680036c 100644 --- a/edgedb/_testbase.py +++ b/edgedb/_testbase.py @@ -600,8 +600,3 @@ def gen_lock_key(): if os.environ.get('USE_UVLOOP'): import uvloop uvloop.install() -elif sys.platform == 'win32' and sys.version_info[:2] == (3, 7): - # The default policy on win32 of Python 3.7 is SelectorEventLoop, which - # does not implement some subprocess functions required by the tests, - # so we have to manually set it to the proactor one (default in 3.8). - asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy()) diff --git a/edgedb/asyncio_client.py b/edgedb/asyncio_client.py index c03c6423..45d8487d 100644 --- a/edgedb/asyncio_client.py +++ b/edgedb/asyncio_client.py @@ -26,7 +26,6 @@ from . import abstract from . import base_client -from . import compat from . import con_utils from . import errors from . import transaction @@ -54,7 +53,7 @@ def is_closed(self): async def connect_addr(self, addr, timeout): try: - await compat.wait_for(self._connect_addr(addr), timeout) + await asyncio.wait_for(self._connect_addr(addr), timeout) except asyncio.TimeoutError as e: raise TimeoutError from e @@ -205,7 +204,7 @@ async def _acquire_impl(): if timeout is None: return await _acquire_impl() else: - return await compat.wait_for( + return await asyncio.wait_for( _acquire_impl(), timeout=timeout) async def _release(self, holder): diff --git a/edgedb/codegen/generator.py b/edgedb/codegen/generator.py index 7f239b25..626e735e 100644 --- a/edgedb/codegen/generator.py +++ b/edgedb/codegen/generator.py @@ -459,11 +459,7 @@ def _generate_code( if link_props: print(file=buf) self._imports.add("typing") - if SYS_VERSION_INFO >= (3, 8): - typing_literal = "typing.Literal" - else: - self._imports.add("typing_extensions") - typing_literal = "typing_extensions.Literal" + typing_literal = "typing.Literal" for el_name, el_code in link_props: print(f"{INDENT}@typing.overload", file=buf) print( diff --git a/edgedb/compat.py b/edgedb/compat.py deleted file mode 100644 index 83277257..00000000 --- a/edgedb/compat.py +++ /dev/null @@ -1,55 +0,0 @@ -# -# This source file is part of the EdgeDB open source project. -# -# Copyright 2016-present MagicStack Inc. and the EdgeDB authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -import asyncio -import sys - - -if sys.version_info < (3, 7): - # Workaround for https://bugs.python.org/issue37658 - import functools - - async def _cancel_and_wait(fut): - def _release_waiter(waiter, *args): - if not waiter.done(): - waiter.set_result(None) - - waiter = asyncio.get_event_loop().create_future() - cb = functools.partial(_release_waiter, waiter) - fut.add_done_callback(cb) - - try: - fut.cancel() - await waiter - finally: - fut.remove_done_callback(cb) - - async def wait_for(fut, timeout): - fut = asyncio.ensure_future(fut) - - try: - return await asyncio.wait_for(fut, timeout) - except (asyncio.CancelledError, asyncio.TimeoutError): - if fut.done(): - return fut.result() - else: - await _cancel_and_wait(fut) - raise - -else: - wait_for = asyncio.wait_for diff --git a/edgedb/credentials.py b/edgedb/credentials.py index aa4fd244..aa6266bc 100644 --- a/edgedb/credentials.py +++ b/edgedb/credentials.py @@ -1,18 +1,12 @@ import os import pathlib -import sys import typing import json -if sys.version_info >= (3, 8): - from typing import TypedDict -else: - from typing_extensions import TypedDict - from . import platform -class RequiredCredentials(TypedDict, total=True): +class RequiredCredentials(typing.TypedDict, total=True): port: int user: str diff --git a/edgedb/datatypes/namedtuple.c b/edgedb/datatypes/namedtuple.c index 7228955e..de0fa8ea 100644 --- a/edgedb/datatypes/namedtuple.c +++ b/edgedb/datatypes/namedtuple.c @@ -92,10 +92,6 @@ EdgeNamedTuple_New(PyObject *type) if (nt == NULL) { return NULL; } -#if PY_VERSION_HEX < 0x03080000 - // Workaround for Python issue 35810; no longer necessary in Python 3.8 - Py_INCREF(type); -#endif } assert(nt != NULL); assert(Py_SIZE(nt) == size); diff --git a/edgedb/protocol/asyncio_proto.pyx b/edgedb/protocol/asyncio_proto.pyx index 5b6a13ae..db3f616f 100644 --- a/edgedb/protocol/asyncio_proto.pyx +++ b/edgedb/protocol/asyncio_proto.pyx @@ -20,7 +20,6 @@ import asyncio from edgedb import errors -from edgedb import compat from edgedb.pgproto.pgproto cimport ( WriteBuffer, ReadBuffer, diff --git a/setup.py b/setup.py index 27f3aa53..0d9b86c6 100644 --- a/setup.py +++ b/setup.py @@ -19,8 +19,8 @@ import sys -if sys.version_info < (3, 7): - raise RuntimeError('edgedb requires Python 3.7 or greater') +if sys.version_info < (3, 8): + raise RuntimeError('edgedb requires Python 3.8 or greater') import os import os.path @@ -48,10 +48,8 @@ 'pycodestyle~=2.6.0', 'pyflakes~=2.2.0', 'flake8-bugbear~=21.4.3', - # importlib-metadata pinned because flake 3.8.1 will grab a too new one - 'importlib-metadata<4.3,>=1.1.0; python_version < "3.8"', 'flake8~=3.8.1', - 'uvloop>=0.15.1; platform_system != "Windows" and python_version >= "3.7"', + 'uvloop>=0.15.1; platform_system != "Windows"', ] # Dependencies required to build documentation. @@ -339,7 +337,6 @@ def finalize_options(self): test_suite='tests.suite', python_requires=">=3.7", install_requires=[ - 'typing-extensions>=3.10.0; python_version < "3.8.0"', 'certifi>=2021.5.30; platform_system == "Windows"', ], extras_require=EXTRA_DEPENDENCIES, diff --git a/tests/codegen/test-project2/object/link_prop_async_edgeql.py.assert b/tests/codegen/test-project2/object/link_prop_async_edgeql.py.assert index c4e9ad8a..2185f9c7 100644 --- a/tests/codegen/test-project2/object/link_prop_async_edgeql.py.assert +++ b/tests/codegen/test-project2/object/link_prop_async_edgeql.py.assert @@ -7,7 +7,6 @@ import dataclasses import datetime import edgedb import typing -import typing_extensions import uuid @@ -34,11 +33,11 @@ class LinkPropResultFriendsItem(NoPydanticValidation): created_at: typing.Optional[datetime.datetime] @typing.overload - def __getitem__(self, key: typing_extensions.Literal["@created_at"]) -> typing.Optional[datetime.datetime]: + def __getitem__(self, key: typing.Literal["@created_at"]) -> typing.Optional[datetime.datetime]: ... @typing.overload - def __getitem__(self, key: typing_extensions.Literal["@strength"]) -> typing.Optional[float]: + def __getitem__(self, key: typing.Literal["@strength"]) -> typing.Optional[float]: ... def __getitem__(self, key: str) -> typing.Any: diff --git a/tests/test_async_query.py b/tests/test_async_query.py index 16a72d91..6ee122ff 100644 --- a/tests/test_async_query.py +++ b/tests/test_async_query.py @@ -29,12 +29,15 @@ import edgedb from edgedb import abstract -from edgedb import compat -from edgedb import _taskgroup as tg from edgedb import _testbase as tb from edgedb.options import RetryOptions from edgedb.protocol import protocol +try: + from asyncio import TaskGroup +except ImportError: + from edgedb._taskgroup import TaskGroup + class TestAsyncQuery(tb.AsyncQueryTestCase): @@ -904,7 +907,7 @@ async def test_async_wait_cancel_01(self): lock_key)) try: - async with tg.TaskGroup() as g: + async with TaskGroup() as g: fut = asyncio.Future() @@ -936,7 +939,7 @@ async def exec_to_fail(): # cancelled, which, in turn, will terminate the # connection rudely, and exec_to_fail() will get # ConnectionResetError. - await compat.wait_for( + await asyncio.wait_for( client2.aclose(), timeout=0.5 ) @@ -1055,7 +1058,7 @@ async def test_async_cancel_01(self): protocol_before = client._impl._holders[0]._con._protocol with self.assertRaises(asyncio.TimeoutError): - await compat.wait_for( + await asyncio.wait_for( client.query_single('SELECT sys::_sleep(10)'), timeout=0.1) diff --git a/tests/test_async_retry.py b/tests/test_async_retry.py index 6043d76a..d47c5603 100644 --- a/tests/test_async_retry.py +++ b/tests/test_async_retry.py @@ -22,7 +22,6 @@ import unittest.mock import edgedb -from edgedb import compat from edgedb import errors from edgedb import RetryOptions from edgedb import _testbase as tb @@ -195,7 +194,7 @@ async def transaction1(client): client = client.with_retry_options(options) client2 = client2.with_retry_options(options) - results = await compat.wait_for(asyncio.gather( + results = await asyncio.wait_for(asyncio.gather( transaction1(client), transaction1(client2), return_exceptions=True, diff --git a/tests/test_asyncio_client.py b/tests/test_asyncio_client.py index 850a3533..13e7c843 100644 --- a/tests/test_asyncio_client.py +++ b/tests/test_asyncio_client.py @@ -21,7 +21,6 @@ import edgedb -from edgedb import compat from edgedb import _testbase as tb from edgedb import errors from edgedb import asyncio_client @@ -304,7 +303,7 @@ async def worker(): with self.assertRaises(asyncio.TimeoutError): await flag - await compat.wait_for(client.aclose(), timeout=0.1) + await asyncio.wait_for(client.aclose(), timeout=0.1) with self.assertRaises(errors.ClientConnectionClosedError): await task @@ -335,7 +334,7 @@ async def close(self, timeout=None): async with tx: await tx.query("SELECT 42") with self.assertRaises(asyncio.TimeoutError): - await compat.wait_for(client.query("SELECT 42"), 1) + await asyncio.wait_for(client.query("SELECT 42"), 1) await client.aclose() @@ -445,7 +444,7 @@ async def cb(r: asyncio.StreamReader, w: asyncio.StreamWriter): finally: server.close() await server.wait_closed() - await compat.wait_for(client.aclose(), 5) + await asyncio.wait_for(client.aclose(), 5) broken.set() await done.wait() diff --git a/tests/test_codegen.py b/tests/test_codegen.py index a3663a98..ae3c0257 100644 --- a/tests/test_codegen.py +++ b/tests/test_codegen.py @@ -79,7 +79,7 @@ async def run(*args, extra_env=None): cmd = env.get("EDGEDB_PYTHON_TEST_CODEGEN_CMD", "edgedb-py") await run( - cmd, extra_env={"EDGEDB_PYTHON_CODEGEN_PY_VER": "3.7.5"} + cmd, extra_env={"EDGEDB_PYTHON_CODEGEN_PY_VER": "3.8.5"} ) await run( cmd,