From 1a172d1fc58bc4b26eb47bd15fdc28c881358d24 Mon Sep 17 00:00:00 2001 From: Leszek Hanusz Date: Sun, 28 Jul 2024 18:32:36 +0200 Subject: [PATCH 1/7] always import Literal from typing - this breaks Python 3.7 --- gql/client.py | 13 +------------ gql/transport/aiohttp_websockets.py | 12 +----------- 2 files changed, 2 insertions(+), 23 deletions(-) diff --git a/gql/client.py b/gql/client.py index a9a2c7e2..ce49cf0e 100644 --- a/gql/client.py +++ b/gql/client.py @@ -1,6 +1,5 @@ import asyncio import logging -import sys import time import warnings from concurrent.futures import Future @@ -13,6 +12,7 @@ Dict, Generator, List, + Literal, Optional, Tuple, TypeVar, @@ -44,17 +44,6 @@ from .utilities import serialize_variable_values from .utils import str_first_element -""" -Load the appropriate instance of the Literal type -Note: we cannot use try: except ImportError because of the following mypy issue: -https://github.com/python/mypy/issues/8520 -""" -if sys.version_info[:2] >= (3, 8): - from typing import Literal -else: - from typing_extensions import Literal # pragma: no cover - - log = logging.getLogger(__name__) diff --git a/gql/transport/aiohttp_websockets.py b/gql/transport/aiohttp_websockets.py index ff310a82..326938c1 100644 --- a/gql/transport/aiohttp_websockets.py +++ b/gql/transport/aiohttp_websockets.py @@ -1,7 +1,6 @@ import asyncio import json import logging -import sys import warnings from contextlib import suppress from ssl import SSLContext @@ -10,6 +9,7 @@ AsyncGenerator, Collection, Dict, + Literal, Mapping, Optional, Tuple, @@ -32,16 +32,6 @@ TransportServerError, ) -""" -Load the appropriate instance of the Literal type -Note: we cannot use try: except ImportError because of the following mypy issue: -https://github.com/python/mypy/issues/8520 -""" -if sys.version_info[:2] >= (3, 8): - from typing import Literal -else: - from typing_extensions import Literal # pragma: no cover - log = logging.getLogger("gql.transport.aiohttp_websockets") ParsedAnswer = Tuple[str, Optional[ExecutionResult]] From 3dcf49640769c55c91a7a10ed10d15dcdc14b897 Mon Sep 17 00:00:00 2001 From: Leszek Hanusz Date: Sun, 28 Jul 2024 18:37:41 +0200 Subject: [PATCH 2/7] Remove workaround needed for Python 3.6 --- gql/transport/aiohttp_websockets.py | 5 ----- gql/transport/websockets_base.py | 5 ----- 2 files changed, 10 deletions(-) diff --git a/gql/transport/aiohttp_websockets.py b/gql/transport/aiohttp_websockets.py index 326938c1..e7fb6815 100644 --- a/gql/transport/aiohttp_websockets.py +++ b/gql/transport/aiohttp_websockets.py @@ -1114,11 +1114,6 @@ async def execute( async for result in generator: first_result = result - - # Note: we need to run generator.aclose() here or the finally block in - # the subscribe will not be reached in pypy3 (python version 3.6.1) - await generator.aclose() - break if first_result is None: diff --git a/gql/transport/websockets_base.py b/gql/transport/websockets_base.py index 5c7713e9..accca275 100644 --- a/gql/transport/websockets_base.py +++ b/gql/transport/websockets_base.py @@ -431,11 +431,6 @@ async def execute( async for result in generator: first_result = result - - # Note: we need to run generator.aclose() here or the finally block in - # the subscribe will not be reached in pypy3 (python version 3.6.1) - await generator.aclose() - break if first_result is None: From bc39086614d40fb644e11b4763f0814035984457 Mon Sep 17 00:00:00 2001 From: Leszek Hanusz Date: Sun, 28 Jul 2024 18:44:53 +0200 Subject: [PATCH 3/7] Bump Python 3.7 to 3.8 in the documentation --- README.md | 2 +- docs/gql-cli/intro.rst | 2 +- docs/intro.rst | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a100e32d..cbc53af6 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # GQL -This is a GraphQL client for Python 3.7+. +This is a GraphQL client for Python 3.8+. Plays nicely with `graphene`, `graphql-core`, `graphql-js` and any other GraphQL implementation compatible with the spec. GQL architecture is inspired by `React-Relay` and `Apollo-Client`. diff --git a/docs/gql-cli/intro.rst b/docs/gql-cli/intro.rst index 925958ee..f88b60a1 100644 --- a/docs/gql-cli/intro.rst +++ b/docs/gql-cli/intro.rst @@ -3,7 +3,7 @@ gql-cli ======= -GQL provides a python 3.7+ script, called `gql-cli` which allows you to execute +GQL provides a python script, called `gql-cli` which allows you to execute GraphQL queries directly from the terminal. This script supports http(s) or websockets protocols. diff --git a/docs/intro.rst b/docs/intro.rst index 21de16bd..3151755d 100644 --- a/docs/intro.rst +++ b/docs/intro.rst @@ -1,7 +1,7 @@ Introduction ============ -`GQL 3`_ is a `GraphQL`_ Client for Python 3.7+ which plays nicely with other +`GQL 3`_ is a `GraphQL`_ Client for Python 3.8+ which plays nicely with other graphql implementations compatible with the spec. Under the hood, it uses `GraphQL-core`_ which is a Python port of `GraphQL.js`_, From a3fa8af69967e8befc9035d1364ad444048135c1 Mon Sep 17 00:00:00 2001 From: Leszek Hanusz Date: Sun, 28 Jul 2024 18:46:30 +0200 Subject: [PATCH 4/7] Remove Python 3.7 in tox.ini --- tox.ini | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tox.ini b/tox.ini index e4794be5..7a639572 100644 --- a/tox.ini +++ b/tox.ini @@ -1,11 +1,10 @@ [tox] envlist = black,flake8,import-order,mypy,manifest, - py{37,38,39,310,311,312,py3} + py{38,39,310,311,312,py3} [gh-actions] python = - 3.7: py37 3.8: py38 3.9: py39 3.10: py310 @@ -29,7 +28,7 @@ deps = -e.[test] commands = pip install -U setuptools ; run "tox -- tests -s" to show output for debugging - py{37,39,310,311,312,py3}: pytest {posargs:tests} + py{39,310,311,312,py3}: pytest {posargs:tests} py{38}: pytest {posargs:tests --cov-report=term-missing --cov=gql} [testenv:black] From 9d3567af48aafa86e5bcfe7d91c037f8fe89c8b1 Mon Sep 17 00:00:00 2001 From: Leszek Hanusz Date: Sun, 28 Jul 2024 18:51:37 +0200 Subject: [PATCH 5/7] Remove test skip for Python 3.7 --- tests/custom_scalars/test_datetime.py | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/tests/custom_scalars/test_datetime.py b/tests/custom_scalars/test_datetime.py index b3e717c5..5a36669c 100644 --- a/tests/custom_scalars/test_datetime.py +++ b/tests/custom_scalars/test_datetime.py @@ -1,7 +1,6 @@ from datetime import datetime, timedelta from typing import Any, Dict, Optional -import pytest from graphql.error import GraphQLError from graphql.language import ValueNode from graphql.pyutils import inspect @@ -110,9 +109,6 @@ def resolve_seconds(root, _info, interval): schema = GraphQLSchema(query=queryType) -@pytest.mark.skipif( - not hasattr(datetime, "fromisoformat"), reason="fromisoformat is new in Python 3.7+" -) def test_shift_days(): client = Client(schema=schema, parse_results=True, serialize_variables=True) @@ -132,9 +128,6 @@ def test_shift_days(): assert result["shiftDays"] == datetime.fromisoformat("2021-11-17T11:58:13.461161") -@pytest.mark.skipif( - not hasattr(datetime, "fromisoformat"), reason="fromisoformat is new in Python 3.7+" -) def test_shift_days_serialized_manually_in_query(): client = Client(schema=schema) @@ -152,9 +145,6 @@ def test_shift_days_serialized_manually_in_query(): assert result["shiftDays"] == datetime.fromisoformat("2021-11-17T11:58:13.461161") -@pytest.mark.skipif( - not hasattr(datetime, "fromisoformat"), reason="fromisoformat is new in Python 3.7+" -) def test_shift_days_serialized_manually_in_variables(): client = Client(schema=schema, parse_results=True) @@ -172,9 +162,6 @@ def test_shift_days_serialized_manually_in_variables(): assert result["shiftDays"] == datetime.fromisoformat("2021-11-17T11:58:13.461161") -@pytest.mark.skipif( - not hasattr(datetime, "fromisoformat"), reason="fromisoformat is new in Python 3.7+" -) def test_latest(): client = Client(schema=schema, parse_results=True) @@ -197,9 +184,6 @@ def test_latest(): assert result["latest"] == in_five_days -@pytest.mark.skipif( - not hasattr(datetime, "fromisoformat"), reason="fromisoformat is new in Python 3.7+" -) def test_seconds(): client = Client(schema=schema) @@ -221,9 +205,6 @@ def test_seconds(): assert result["seconds"] == 432000 -@pytest.mark.skipif( - not hasattr(datetime, "fromisoformat"), reason="fromisoformat is new in Python 3.7+" -) def test_seconds_omit_optional_start_argument(): client = Client(schema=schema) From 85066405c34f0ac9df4b8ded368a68826e0f0e3c Mon Sep 17 00:00:00 2001 From: Leszek Hanusz Date: Sun, 28 Jul 2024 19:05:00 +0200 Subject: [PATCH 6/7] Don't call session._generator.aclose() in the tests anymore This was only necessary for Python 3.6 --- .../test_aiohttp_websocket_graphqlws_subscription.py | 3 --- tests/test_aiohttp_websocket_subscription.py | 3 --- tests/test_graphqlws_subscription.py | 3 --- tests/test_phoenix_channel_subscription.py | 11 ----------- tests/test_websocket_subscription.py | 3 --- 5 files changed, 23 deletions(-) diff --git a/tests/test_aiohttp_websocket_graphqlws_subscription.py b/tests/test_aiohttp_websocket_graphqlws_subscription.py index e5db7ca1..86ff96ab 100644 --- a/tests/test_aiohttp_websocket_graphqlws_subscription.py +++ b/tests/test_aiohttp_websocket_graphqlws_subscription.py @@ -268,9 +268,6 @@ async def test_aiohttp_websocket_graphqlws_subscription_break( assert number == count if count <= 5: - # Note: the following line is only necessary for pypy3 v3.6.1 - if sys.version_info < (3, 7): - await session._generator.aclose() break count -= 1 diff --git a/tests/test_aiohttp_websocket_subscription.py b/tests/test_aiohttp_websocket_subscription.py index 3ebf4dbc..4bc6ad3c 100644 --- a/tests/test_aiohttp_websocket_subscription.py +++ b/tests/test_aiohttp_websocket_subscription.py @@ -258,9 +258,6 @@ async def test_aiohttp_websocket_subscription_break( assert number == count if count <= 5: - # Note: the following line is only necessary for pypy3 v3.6.1 - if sys.version_info < (3, 7): - await session._generator.aclose() break count -= 1 diff --git a/tests/test_graphqlws_subscription.py b/tests/test_graphqlws_subscription.py index cb705368..deeae395 100644 --- a/tests/test_graphqlws_subscription.py +++ b/tests/test_graphqlws_subscription.py @@ -268,9 +268,6 @@ async def test_graphqlws_subscription_break( assert number == count if count <= 5: - # Note: the following line is only necessary for pypy3 v3.6.1 - if sys.version_info < (3, 7): - await session._generator.aclose() break count -= 1 diff --git a/tests/test_phoenix_channel_subscription.py b/tests/test_phoenix_channel_subscription.py index 6367945d..34564c6d 100644 --- a/tests/test_phoenix_channel_subscription.py +++ b/tests/test_phoenix_channel_subscription.py @@ -1,6 +1,5 @@ import asyncio import json -import sys import pytest from parse import search @@ -208,11 +207,6 @@ async def test_phoenix_channel_subscription( assert number == count if number == end_count: - # Note: we need to run generator.aclose() here or the finally block in - # the subscribe will not be reached in pypy3 (python version 3.6.1) - # In more recent versions, 'break' will trigger __aexit__. - if sys.version_info < (3, 7): - await session._generator.aclose() print("break") break @@ -390,11 +384,6 @@ async def test_phoenix_channel_heartbeat(event_loop, server, subscription_str): assert heartbeat_count == i if heartbeat_count == 5: - # Note: we need to run generator.aclose() here or the finally block in - # the subscribe will not be reached in pypy3 (python version 3.6.1) - # In more recent versions, 'break' will trigger __aexit__. - if sys.version_info < (3, 7): - await session._generator.aclose() break i += 1 diff --git a/tests/test_websocket_subscription.py b/tests/test_websocket_subscription.py index 4419783b..38307349 100644 --- a/tests/test_websocket_subscription.py +++ b/tests/test_websocket_subscription.py @@ -189,9 +189,6 @@ async def test_websocket_subscription_break( assert number == count if count <= 5: - # Note: the following line is only necessary for pypy3 v3.6.1 - if sys.version_info < (3, 7): - await session._generator.aclose() break count -= 1 From 94a4156addd187336903e9f50e8918cb5db673ea Mon Sep 17 00:00:00 2001 From: Leszek Hanusz Date: Sun, 28 Jul 2024 19:05:42 +0200 Subject: [PATCH 7/7] Fix comment in client.py for the current purpose of the _generator ref --- gql/client.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gql/client.py b/gql/client.py index ce49cf0e..5fd038d0 100644 --- a/gql/client.py +++ b/gql/client.py @@ -1357,8 +1357,8 @@ async def _subscribe( **kwargs, ) - # Keep a reference to the inner generator to allow the user to call aclose() - # before a break if python version is too old (pypy3 py 3.6.1) + # Keep a reference to the inner generator + # This is only used for the tests to simulate a KeyboardInterrupt event self._generator = inner_generator try: