Skip to content

Commit

Permalink
Check for __typename of objects (solves #25)
Browse files Browse the repository at this point in the history
  • Loading branch information
Cito committed Mar 7, 2019
1 parent 96aa6d5 commit ec998aa
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 30 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ a query language for APIs created by Facebook.
[![Code Style](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black)

The current version 1.0.1 of GraphQL-core-next is up-to-date with GraphQL.js version
14.0.2. All parts of the API are covered by an extensive test suite of currently 1679
14.0.2. All parts of the API are covered by an extensive test suite of currently 1681
unit tests.


Expand Down Expand Up @@ -187,9 +187,9 @@ Design goals for the GraphQL-core-next library are:
library and language versions
* to be very close to the GraphQL.js reference implementation, while still using a
Pythonic API and code style
* making use of Python type hints, similar to how GraphQL.js makes use of Flow
* using of [black](https://github.com/ambv/black) for automatic code formatting
* replicate the complete Mocha-based test suite of GraphQL.js using
* to make extensive use of Python type hints, similar to how GraphQL.js makes use of Flow
* to use [black](https://github.com/ambv/black) for automatic code formatting
* to replicate the complete Mocha-based test suite of GraphQL.js using
[pytest](https://docs.pytest.org/)

Some restrictions (mostly in line with the design goals):
Expand Down
10 changes: 8 additions & 2 deletions graphql/execution/execute.py
Original file line number Diff line number Diff line change
Expand Up @@ -1108,8 +1108,14 @@ def default_resolve_type_fn(
"""

# First, look for `__typename`.
if isinstance(value, dict) and isinstance(value.get("__typename"), str):
return value["__typename"]
type_name = (
value.get("__typename")
if isinstance(value, dict)
# need to de-mangle the attribute assumed to be "private" in Python
else getattr(value, f"_{value.__class__.__name__}__typename", None)
)
if isinstance(type_name, str):
return type_name

# Otherwise, test each possible type.
possible_types = info.schema.get_possible_types(abstract_type)
Expand Down
82 changes: 58 additions & 24 deletions tests/utilities/test_build_ast_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,8 @@ def can_build_recursive_union():
msg = str(exc_info.value)
assert msg == "Hello types must be GraphQLObjectType objects."

def specifying_union_type_using_typename():
def describe_specifying_union_type_using_typename():

schema = build_schema(
"""
type Query {
Expand Down Expand Up @@ -401,19 +402,33 @@ def specifying_union_type_using_typename():
}
"""

root = {
"fruits": [
{"color": "green", "__typename": "Apple"},
{"length": 5, "__typename": "Banana"},
]
}
expected = ({"fruits": [{"color": "green"}, {"length": 5}]}, None)

assert graphql_sync(schema, query, root) == (
{"fruits": [{"color": "green"}, {"length": 5}]},
None,
)
def using_dicts():
root = {
"fruits": [
{"color": "green", "__typename": "Apple"},
{"length": 5, "__typename": "Banana"},
]
}

assert graphql_sync(schema, query, root) == expected

def using_objects():
class Apple:
__typename = "Apple"
color = "green"

class Banana:
__typename = "Banana"
length = 5

class Root:
fruits = [Apple(), Banana()]

assert graphql_sync(schema, query, Root()) == expected

def specifying_interface_type_using_typename():
def describe_specifying_interface_type_using_typename():
schema = build_schema(
"""
type Query {
Expand Down Expand Up @@ -450,18 +465,7 @@ def specifying_interface_type_using_typename():
}
"""

root = {
"characters": [
{"name": "Han Solo", "totalCredits": 10, "__typename": "Human"},
{
"name": "R2-D2",
"primaryFunction": "Astromech",
"__typename": "Droid",
},
]
}

assert graphql_sync(schema, query, root) == (
expected = (
{
"characters": [
{"name": "Han Solo", "totalCredits": 10},
Expand All @@ -471,6 +475,36 @@ def specifying_interface_type_using_typename():
None,
)

def using_dicts():
root = {
"characters": [
{"name": "Han Solo", "totalCredits": 10, "__typename": "Human"},
{
"name": "R2-D2",
"primaryFunction": "Astromech",
"__typename": "Droid",
},
]
}

assert graphql_sync(schema, query, root) == expected

def using_objects():
class Human:
__typename = "Human"
name = "Han Solo"
totalCredits = 10

class Droid:
__typename = "Droid"
name = "R2-D2"
primaryFunction = "Astromech"

class Root:
characters = [Human(), Droid()]

assert graphql_sync(schema, query, Root()) == expected

def custom_scalar():
sdl = dedent(
"""
Expand Down

0 comments on commit ec998aa

Please sign in to comment.