Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

100% tests coverage! #107

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion gql/dsl.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def select(self, *fields):
added_selections = selections(*fields)
if selection_set:
selection_set.selections = FrozenList(
selection_set.selections + added_selections
selection_set.selections + list(added_selections)
)
else:
self.ast_field.selection_set = SelectionSetNode(
Expand Down
21 changes: 5 additions & 16 deletions gql/transport/local_schema.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from inspect import isawaitable
from typing import Any, AsyncGenerator, AsyncIterator, Awaitable, Coroutine, cast
from typing import AsyncGenerator, Awaitable, cast

from graphql import DocumentNode, ExecutionResult, GraphQLSchema, execute, subscribe

Expand Down Expand Up @@ -50,27 +50,16 @@ async def execute(
async def subscribe(
self, document: DocumentNode, *args, **kwargs,
) -> AsyncGenerator[ExecutionResult, None]:
"""Send a query and receive the results using an async generator

The query can be a graphql query, mutation or subscription
"""Send a subscription and receive the results using an async generator

The results are sent as an ExecutionResult object
"""

subscribe_result = subscribe(self.schema, document, *args, **kwargs)
subscribe_result = await subscribe(self.schema, document, *args, **kwargs)

if isinstance(subscribe_result, ExecutionResult):
yield ExecutionResult
yield subscribe_result
leszekhanusz marked this conversation as resolved.
Show resolved Hide resolved

else:
# if we don't get an ExecutionResult, then we should receive
# a Coroutine returning an AsyncIterator[ExecutionResult]

subscribe_coro = cast(
Coroutine[Any, Any, AsyncIterator[ExecutionResult]], subscribe_result
)

subscribe_generator = await subscribe_coro

async for result in subscribe_generator:
async for result in subscribe_result:
yield result
2 changes: 1 addition & 1 deletion gql/transport/transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def execute(self, document: DocumentNode, *args, **kwargs) -> ExecutionResult:
def connect(self):
"""Establish a session with the transport.
"""
pass
pass # pragma: no cover

def close(self):
"""Close the transport
Expand Down
6 changes: 6 additions & 0 deletions tests/starwars/fixtures.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import asyncio
from collections import namedtuple

Human = namedtuple("Human", "id name friends appearsIn homePlanet")
Expand Down Expand Up @@ -94,6 +95,11 @@ def getHero(episode):
return artoo


async def getHeroAsync(episode):
await asyncio.sleep(0.001)
return getHero(episode)


def getHuman(id):
return humanData.get(id)

Expand Down
4 changes: 2 additions & 2 deletions tests/starwars/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
getCharacters,
getDroid,
getFriends,
getHero,
getHeroAsync,
getHuman,
reviews,
)
Expand Down Expand Up @@ -146,7 +146,7 @@
type_=episodeEnum, # type: ignore
)
},
resolve=lambda root, info, **args: getHero(args.get("episode")),
resolve=lambda root, info, **args: getHeroAsync(args.get("episode")),
),
"human": GraphQLField(
humanType,
Expand Down
12 changes: 12 additions & 0 deletions tests/starwars/test_dsl.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,18 @@ def test_hero_name_and_friends_query(ds):
assert query == str(query_dsl)


def test_hero_id_and_name(ds):
query = """
hero {
id
name
}
""".strip()
query_dsl = ds.Query.hero.select(ds.Character.id)
query_dsl = query_dsl.select(ds.Character.name)
assert query == str(query_dsl)


def test_nested_query(ds):
query = """
hero {
Expand Down
37 changes: 36 additions & 1 deletion tests/starwars/test_subscription.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import pytest
from graphql import subscribe
from graphql import ExecutionResult, GraphQLError, subscribe

from gql import Client, gql

Expand Down Expand Up @@ -57,3 +57,38 @@ async def test_subscription_support_using_client():
]

assert results == expected


subscription_invalid_str = """
subscription ListenEpisodeReviews($ep: Episode!) {
qsdfqsdfqsdf
}
"""


@pytest.mark.asyncio
async def test_subscription_support_using_client_invalid_field():

subs = gql(subscription_invalid_str)

params = {"ep": "JEDI"}

async with Client(schema=StarWarsSchema) as session:

# We subscribe directly from the transport to avoid local validation
results = [
result
async for result in session.transport.subscribe(
subs, variable_values=params
)
]

assert len(results) == 1
result = results[0]
assert isinstance(result, ExecutionResult)
assert result.data is None
assert isinstance(result.errors, list)
assert len(result.errors) == 1
error = result.errors[0]
assert isinstance(error, GraphQLError)
assert error.message == "The subscription field 'qsdfqsdfqsdf' is not defined."