mirror of
https://github.com/graphql-python/graphene-django.git
synced 2025-04-25 03:13:47 +03:00
Dump
This commit is contained in:
parent
1e79165a7e
commit
c2e4f4169e
|
@ -23,7 +23,7 @@ from graphene import (
|
|||
)
|
||||
from graphene.types.json import JSONString
|
||||
from graphene.utils.str_converters import to_camel_case, to_const
|
||||
from graphql import assert_valid_name
|
||||
from graphql import assert_valid_name, GraphQLError
|
||||
|
||||
from .settings import graphene_settings
|
||||
from .compat import ArrayField, HStoreField, JSONField, RangeField
|
||||
|
@ -34,7 +34,7 @@ def convert_choice_name(name):
|
|||
name = to_const(force_str(name))
|
||||
try:
|
||||
assert_valid_name(name)
|
||||
except AssertionError:
|
||||
except GraphQLError:
|
||||
name = "A_%s" % name
|
||||
return name
|
||||
|
||||
|
@ -64,7 +64,7 @@ def convert_choices_to_named_enum_with_descriptions(name, choices):
|
|||
class EnumWithDescriptionsType(object):
|
||||
@property
|
||||
def description(self):
|
||||
return named_choices_descriptions[self.name]
|
||||
return str(named_choices_descriptions[self.name])
|
||||
|
||||
return Enum(name, list(named_choices), type=EnumWithDescriptionsType)
|
||||
|
||||
|
@ -276,3 +276,12 @@ def convert_postgres_range_to_string(field, registry=None):
|
|||
if not isinstance(inner_type, (List, NonNull)):
|
||||
inner_type = type(inner_type)
|
||||
return List(inner_type, description=field.help_text, required=not field.null)
|
||||
|
||||
|
||||
from django.utils.functional import Promise
|
||||
from graphql.pyutils import register_description
|
||||
|
||||
|
||||
# Register Django lazy()-wrapped values as GraphQL description/help_text.
|
||||
# This is needed for using lazy translations, see https://github.com/graphql-python/graphql-core-next/issues/58.
|
||||
register_description(Promise)
|
||||
|
|
|
@ -17,7 +17,7 @@ class DjangoDebugContext(object):
|
|||
if not self.debug_promise:
|
||||
self.debug_promise = Promise.all(self.promises)
|
||||
self.promises = []
|
||||
return self.debug_promise.then(self.on_resolve_all_promises)
|
||||
return self.debug_promise.then(self.on_resolve_all_promises).get()
|
||||
|
||||
def on_resolve_all_promises(self, values):
|
||||
if self.promises:
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
from functools import partial
|
||||
|
||||
from django.db.models.query import QuerySet
|
||||
from graphene.relay.connection import page_info_adapter, connection_adapter
|
||||
|
||||
from graphql_relay.connection.arrayconnection import connection_from_array_slice
|
||||
from promise import Promise
|
||||
|
||||
from graphene import NonNull
|
||||
from graphene.relay import ConnectionField, PageInfo
|
||||
from graphene.relay import ConnectionField
|
||||
from graphene.types import Field, List
|
||||
|
||||
from .settings import graphene_settings
|
||||
|
@ -127,11 +128,11 @@ class DjangoConnectionField(ConnectionField):
|
|||
iterable,
|
||||
args,
|
||||
slice_start=0,
|
||||
connection_type=connection,
|
||||
array_length=_len,
|
||||
array_slice_length=_len,
|
||||
connection_type=partial(connection_adapter, connection),
|
||||
edge_type=connection.Edge,
|
||||
page_info_type=PageInfo,
|
||||
page_info_type=page_info_adapter,
|
||||
)
|
||||
connection.iterable = iterable
|
||||
connection.length = _len
|
||||
|
|
|
@ -806,38 +806,56 @@ def test_integer_field_filter_type():
|
|||
|
||||
assert str(schema) == dedent(
|
||||
"""\
|
||||
schema {
|
||||
query: Query
|
||||
}
|
||||
|
||||
interface Node {
|
||||
id: ID!
|
||||
}
|
||||
|
||||
type PageInfo {
|
||||
hasNextPage: Boolean!
|
||||
hasPreviousPage: Boolean!
|
||||
startCursor: String
|
||||
endCursor: String
|
||||
}
|
||||
|
||||
type PetType implements Node {
|
||||
age: Int!
|
||||
id: ID!
|
||||
type Query {
|
||||
pets(before: String = null, after: String = null, first: Int = null, last: Int = null, age: Int = null): PetTypeConnection
|
||||
}
|
||||
|
||||
type PetTypeConnection {
|
||||
\"""Pagination data for this connection.\"""
|
||||
pageInfo: PageInfo!
|
||||
|
||||
\"""Contains the nodes in this connection.\"""
|
||||
edges: [PetTypeEdge]!
|
||||
}
|
||||
|
||||
\"""
|
||||
The Relay compliant `PageInfo` type, containing data necessary to paginate this connection.
|
||||
\"""
|
||||
type PageInfo {
|
||||
\"""When paginating forwards, are there more items?\"""
|
||||
hasNextPage: Boolean!
|
||||
|
||||
\"""When paginating backwards, are there more items?\"""
|
||||
hasPreviousPage: Boolean!
|
||||
|
||||
\"""When paginating backwards, the cursor to continue.\"""
|
||||
startCursor: String
|
||||
|
||||
\"""When paginating forwards, the cursor to continue.\"""
|
||||
endCursor: String
|
||||
}
|
||||
|
||||
\"""A Relay edge containing a `PetType` and its cursor.\"""
|
||||
type PetTypeEdge {
|
||||
\"""The item at the end of the edge\"""
|
||||
node: PetType
|
||||
|
||||
\"""A cursor for use in pagination\"""
|
||||
cursor: String!
|
||||
}
|
||||
|
||||
type Query {
|
||||
pets(before: String, after: String, first: Int, last: Int, age: Int): PetTypeConnection
|
||||
|
||||
type PetType implements Node {
|
||||
\"""\"""
|
||||
age: Int!
|
||||
|
||||
\"""The ID of the object\"""
|
||||
id: ID!
|
||||
}
|
||||
|
||||
\"""An object with an ID\"""
|
||||
interface Node {
|
||||
\"""The ID of the object\"""
|
||||
id: ID!
|
||||
}
|
||||
"""
|
||||
)
|
||||
|
@ -858,40 +876,58 @@ def test_other_filter_types():
|
|||
|
||||
assert str(schema) == dedent(
|
||||
"""\
|
||||
schema {
|
||||
query: Query
|
||||
}
|
||||
|
||||
interface Node {
|
||||
id: ID!
|
||||
}
|
||||
|
||||
type PageInfo {
|
||||
hasNextPage: Boolean!
|
||||
hasPreviousPage: Boolean!
|
||||
startCursor: String
|
||||
endCursor: String
|
||||
}
|
||||
|
||||
type PetType implements Node {
|
||||
age: Int!
|
||||
id: ID!
|
||||
type Query {
|
||||
pets(before: String = null, after: String = null, first: Int = null, last: Int = null, age: Int = null, age_Isnull: Boolean = null, age_Lt: Int = null): PetTypeConnection
|
||||
}
|
||||
|
||||
type PetTypeConnection {
|
||||
\"""Pagination data for this connection.\"""
|
||||
pageInfo: PageInfo!
|
||||
|
||||
\"""Contains the nodes in this connection.\"""
|
||||
edges: [PetTypeEdge]!
|
||||
}
|
||||
|
||||
\"""
|
||||
The Relay compliant `PageInfo` type, containing data necessary to paginate this connection.
|
||||
\"""
|
||||
type PageInfo {
|
||||
\"""When paginating forwards, are there more items?\"""
|
||||
hasNextPage: Boolean!
|
||||
|
||||
\"""When paginating backwards, are there more items?\"""
|
||||
hasPreviousPage: Boolean!
|
||||
|
||||
\"""When paginating backwards, the cursor to continue.\"""
|
||||
startCursor: String
|
||||
|
||||
\"""When paginating forwards, the cursor to continue.\"""
|
||||
endCursor: String
|
||||
}
|
||||
|
||||
\"""A Relay edge containing a `PetType` and its cursor.\"""
|
||||
type PetTypeEdge {
|
||||
\"""The item at the end of the edge\"""
|
||||
node: PetType
|
||||
|
||||
\"""A cursor for use in pagination\"""
|
||||
cursor: String!
|
||||
}
|
||||
|
||||
type Query {
|
||||
pets(before: String, after: String, first: Int, last: Int, age: Int, age_Isnull: Boolean, age_Lt: Int): PetTypeConnection
|
||||
type PetType implements Node {
|
||||
\"""\"""
|
||||
age: Int!
|
||||
|
||||
\"""The ID of the object\"""
|
||||
id: ID!
|
||||
}
|
||||
"""
|
||||
|
||||
\"""An object with an ID\"""
|
||||
interface Node {
|
||||
\"""The ID of the object\"""
|
||||
id: ID!
|
||||
}
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ class Command(CommandArguments):
|
|||
|
||||
def save_graphql_file(self, out, schema):
|
||||
with open(out, "w") as outfile:
|
||||
outfile.write(print_schema(schema))
|
||||
outfile.write(print_schema(schema.graphql_schema))
|
||||
|
||||
def get_schema(self, schema, out, indent):
|
||||
schema_dict = {"data": schema.introspect()}
|
||||
|
|
|
@ -17,6 +17,7 @@ def mock_info():
|
|||
None,
|
||||
None,
|
||||
None,
|
||||
path=None,
|
||||
schema=None,
|
||||
fragments=None,
|
||||
root_value=None,
|
||||
|
|
|
@ -51,10 +51,6 @@ def test_generate_graphql_file_on_call_graphql_schema():
|
|||
schema_output = handle.write.call_args[0][0]
|
||||
assert schema_output == dedent(
|
||||
"""\
|
||||
schema {
|
||||
query: Query
|
||||
}
|
||||
|
||||
type Query {
|
||||
hi: String
|
||||
}
|
||||
|
|
|
@ -612,9 +612,9 @@ def test_should_enforce_first_or_last(graphene_settings):
|
|||
|
||||
result = schema.execute(query)
|
||||
assert len(result.errors) == 1
|
||||
assert str(result.errors[0]) == (
|
||||
assert str(result.errors[0]).startswith(
|
||||
"You must provide a `first` or `last` value to properly "
|
||||
"paginate the `allReporters` connection."
|
||||
"paginate the `allReporters` connection.\n"
|
||||
)
|
||||
assert result.data == expected
|
||||
|
||||
|
@ -653,9 +653,9 @@ def test_should_error_if_first_is_greater_than_max(graphene_settings):
|
|||
|
||||
result = schema.execute(query)
|
||||
assert len(result.errors) == 1
|
||||
assert str(result.errors[0]) == (
|
||||
assert str(result.errors[0]).startswith(
|
||||
"Requesting 101 records on the `allReporters` connection "
|
||||
"exceeds the `first` limit of 100 records."
|
||||
"exceeds the `first` limit of 100 records.\n"
|
||||
)
|
||||
assert result.data == expected
|
||||
|
||||
|
@ -694,9 +694,9 @@ def test_should_error_if_last_is_greater_than_max(graphene_settings):
|
|||
|
||||
result = schema.execute(query)
|
||||
assert len(result.errors) == 1
|
||||
assert str(result.errors[0]) == (
|
||||
assert str(result.errors[0]).startswith(
|
||||
"Requesting 101 records on the `allReporters` connection "
|
||||
"exceeds the `last` limit of 100 records."
|
||||
"exceeds the `last` limit of 100 records.\n"
|
||||
)
|
||||
assert result.data == expected
|
||||
|
||||
|
@ -713,7 +713,7 @@ def test_should_query_promise_connectionfields():
|
|||
all_reporters = DjangoConnectionField(ReporterType)
|
||||
|
||||
def resolve_all_reporters(self, info, **args):
|
||||
return Promise.resolve([Reporter(id=1)])
|
||||
return Promise.resolve([Reporter(id=1)]).get()
|
||||
|
||||
schema = graphene.Schema(query=Query)
|
||||
query = """
|
||||
|
@ -842,7 +842,7 @@ def test_should_query_dataloader_fields():
|
|||
articles = DjangoConnectionField(ArticleType)
|
||||
|
||||
def resolve_articles(self, info, **args):
|
||||
return article_loader.load(self.id)
|
||||
return article_loader.load(self.id).get()
|
||||
|
||||
class Query(graphene.ObjectType):
|
||||
all_reporters = DjangoConnectionField(ReporterType)
|
||||
|
@ -1105,6 +1105,7 @@ def test_should_preserve_prefetch_related(django_assert_num_queries):
|
|||
}
|
||||
"""
|
||||
schema = graphene.Schema(query=Query)
|
||||
|
||||
with django_assert_num_queries(3) as captured:
|
||||
result = schema.execute(query)
|
||||
assert not result.errors
|
||||
|
|
|
@ -111,83 +111,165 @@ def test_django_objecttype_with_custom_meta():
|
|||
|
||||
|
||||
def test_schema_representation():
|
||||
expected = """
|
||||
schema {
|
||||
query: RootQuery
|
||||
}
|
||||
expected = dedent(
|
||||
"""\
|
||||
schema {
|
||||
query: RootQuery
|
||||
}
|
||||
|
||||
type Article implements Node {
|
||||
id: ID!
|
||||
headline: String!
|
||||
pubDate: Date!
|
||||
pubDateTime: DateTime!
|
||||
reporter: Reporter!
|
||||
editor: Reporter!
|
||||
lang: ArticleLang!
|
||||
importance: ArticleImportance
|
||||
}
|
||||
\"""Article description\"""
|
||||
type Article implements Node {
|
||||
\"""The ID of the object\"""
|
||||
id: ID!
|
||||
|
||||
type ArticleConnection {
|
||||
pageInfo: PageInfo!
|
||||
edges: [ArticleEdge]!
|
||||
test: String
|
||||
}
|
||||
\"""\"""
|
||||
headline: String!
|
||||
|
||||
type ArticleEdge {
|
||||
node: Article
|
||||
cursor: String!
|
||||
}
|
||||
\"""\"""
|
||||
pubDate: Date!
|
||||
|
||||
enum ArticleImportance {
|
||||
A_1
|
||||
A_2
|
||||
}
|
||||
\"""\"""
|
||||
pubDateTime: DateTime!
|
||||
|
||||
enum ArticleLang {
|
||||
ES
|
||||
EN
|
||||
}
|
||||
\"""\"""
|
||||
reporter: Reporter!
|
||||
|
||||
scalar Date
|
||||
\"""\"""
|
||||
editor: Reporter!
|
||||
|
||||
scalar DateTime
|
||||
\"""Language\"""
|
||||
lang: ArticleLang!
|
||||
|
||||
interface Node {
|
||||
id: ID!
|
||||
}
|
||||
\"""\"""
|
||||
importance: ArticleImportance
|
||||
}
|
||||
|
||||
type PageInfo {
|
||||
hasNextPage: Boolean!
|
||||
hasPreviousPage: Boolean!
|
||||
startCursor: String
|
||||
endCursor: String
|
||||
}
|
||||
\"""An object with an ID\"""
|
||||
interface Node {
|
||||
\"""The ID of the object\"""
|
||||
id: ID!
|
||||
}
|
||||
|
||||
type Reporter {
|
||||
id: ID!
|
||||
firstName: String!
|
||||
lastName: String!
|
||||
email: String!
|
||||
pets: [Reporter!]!
|
||||
aChoice: ReporterAChoice
|
||||
reporterType: ReporterReporterType
|
||||
articles(before: String, after: String, first: Int, last: Int): ArticleConnection!
|
||||
}
|
||||
\"""
|
||||
The `Date` scalar type represents a Date
|
||||
value as specified by
|
||||
[iso8601](https://en.wikipedia.org/wiki/ISO_8601).
|
||||
\"""
|
||||
scalar Date
|
||||
|
||||
enum ReporterAChoice {
|
||||
A_1
|
||||
A_2
|
||||
}
|
||||
\"""
|
||||
The `DateTime` scalar type represents a DateTime
|
||||
value as specified by
|
||||
[iso8601](https://en.wikipedia.org/wiki/ISO_8601).
|
||||
\"""
|
||||
scalar DateTime
|
||||
|
||||
enum ReporterReporterType {
|
||||
A_1
|
||||
A_2
|
||||
}
|
||||
\"""An enumeration.\"""
|
||||
enum ArticleLang {
|
||||
\"""Spanish\"""
|
||||
ES
|
||||
|
||||
type RootQuery {
|
||||
node(id: ID!): Node
|
||||
}
|
||||
""".lstrip()
|
||||
\"""English\"""
|
||||
EN
|
||||
}
|
||||
|
||||
\"""An enumeration.\"""
|
||||
enum ArticleImportance {
|
||||
\"""Very important\"""
|
||||
A_1
|
||||
|
||||
\"""Not as important\"""
|
||||
A_2
|
||||
}
|
||||
|
||||
\"""Reporter description\"""
|
||||
type Reporter {
|
||||
\"""\"""
|
||||
id: ID!
|
||||
|
||||
\"""\"""
|
||||
firstName: String!
|
||||
|
||||
\"""\"""
|
||||
lastName: String!
|
||||
|
||||
\"""\"""
|
||||
email: String!
|
||||
|
||||
\"""\"""
|
||||
pets: [Reporter!]!
|
||||
|
||||
\"""\"""
|
||||
aChoice: ReporterAChoice
|
||||
|
||||
\"""\"""
|
||||
reporterType: ReporterReporterType
|
||||
|
||||
\"""\"""
|
||||
articles(before: String = null, after: String = null, first: Int = null, last: Int = null): ArticleConnection!
|
||||
}
|
||||
|
||||
\"""An enumeration.\"""
|
||||
enum ReporterAChoice {
|
||||
\"""this\"""
|
||||
A_1
|
||||
|
||||
\"""that\"""
|
||||
A_2
|
||||
}
|
||||
|
||||
\"""An enumeration.\"""
|
||||
enum ReporterReporterType {
|
||||
\"""Regular\"""
|
||||
A_1
|
||||
|
||||
\"""CNN Reporter\"""
|
||||
A_2
|
||||
}
|
||||
|
||||
type ArticleConnection {
|
||||
\"""Pagination data for this connection.\"""
|
||||
pageInfo: PageInfo!
|
||||
|
||||
\"""Contains the nodes in this connection.\"""
|
||||
edges: [ArticleEdge]!
|
||||
test: String
|
||||
}
|
||||
|
||||
\"""
|
||||
The Relay compliant `PageInfo` type, containing data necessary to paginate this connection.
|
||||
\"""
|
||||
type PageInfo {
|
||||
\"""When paginating forwards, are there more items?\"""
|
||||
hasNextPage: Boolean!
|
||||
|
||||
\"""When paginating backwards, are there more items?\"""
|
||||
hasPreviousPage: Boolean!
|
||||
|
||||
\"""When paginating backwards, the cursor to continue.\"""
|
||||
startCursor: String
|
||||
|
||||
\"""When paginating forwards, the cursor to continue.\"""
|
||||
endCursor: String
|
||||
}
|
||||
|
||||
\"""A Relay edge containing a `Article` and its cursor.\"""
|
||||
type ArticleEdge {
|
||||
\"""The item at the end of the edge\"""
|
||||
node: Article
|
||||
|
||||
\"""A cursor for use in pagination\"""
|
||||
cursor: String!
|
||||
}
|
||||
|
||||
type RootQuery {
|
||||
node(
|
||||
\"""The ID of the object\"""
|
||||
id: ID!
|
||||
): Node
|
||||
}
|
||||
"""
|
||||
)
|
||||
assert str(schema) == expected
|
||||
|
||||
|
||||
|
@ -415,20 +497,21 @@ class TestDjangoObjectType:
|
|||
|
||||
assert str(schema) == dedent(
|
||||
"""\
|
||||
schema {
|
||||
query: Query
|
||||
}
|
||||
type Query {
|
||||
pet: Pet
|
||||
}
|
||||
|
||||
type Pet {
|
||||
id: ID!
|
||||
kind: String!
|
||||
cuteness: Int!
|
||||
}
|
||||
type Pet {
|
||||
\"""\"""
|
||||
id: ID!
|
||||
|
||||
type Query {
|
||||
pet: Pet
|
||||
}
|
||||
"""
|
||||
\"""\"""
|
||||
kind: String!
|
||||
|
||||
\"""\"""
|
||||
cuteness: Int!
|
||||
}
|
||||
"""
|
||||
)
|
||||
|
||||
def test_django_objecttype_convert_choices_enum_list(self, PetModel):
|
||||
|
@ -444,25 +527,30 @@ class TestDjangoObjectType:
|
|||
|
||||
assert str(schema) == dedent(
|
||||
"""\
|
||||
schema {
|
||||
query: Query
|
||||
}
|
||||
type Query {
|
||||
pet: Pet
|
||||
}
|
||||
|
||||
type Pet {
|
||||
id: ID!
|
||||
kind: PetModelKind!
|
||||
cuteness: Int!
|
||||
}
|
||||
type Pet {
|
||||
\"""\"""
|
||||
id: ID!
|
||||
|
||||
enum PetModelKind {
|
||||
CAT
|
||||
DOG
|
||||
}
|
||||
\"""\"""
|
||||
kind: PetModelKind!
|
||||
|
||||
type Query {
|
||||
pet: Pet
|
||||
}
|
||||
"""
|
||||
\"""\"""
|
||||
cuteness: Int!
|
||||
}
|
||||
|
||||
\"""An enumeration.\"""
|
||||
enum PetModelKind {
|
||||
\"""Cat\"""
|
||||
CAT
|
||||
|
||||
\"""Dog\"""
|
||||
DOG
|
||||
}
|
||||
"""
|
||||
)
|
||||
|
||||
def test_django_objecttype_convert_choices_enum_empty_list(self, PetModel):
|
||||
|
@ -478,20 +566,21 @@ class TestDjangoObjectType:
|
|||
|
||||
assert str(schema) == dedent(
|
||||
"""\
|
||||
schema {
|
||||
query: Query
|
||||
}
|
||||
type Query {
|
||||
pet: Pet
|
||||
}
|
||||
|
||||
type Pet {
|
||||
id: ID!
|
||||
kind: String!
|
||||
cuteness: Int!
|
||||
}
|
||||
type Pet {
|
||||
\"""\"""
|
||||
id: ID!
|
||||
|
||||
type Query {
|
||||
pet: Pet
|
||||
}
|
||||
"""
|
||||
\"""\"""
|
||||
kind: String!
|
||||
|
||||
\"""\"""
|
||||
cuteness: Int!
|
||||
}
|
||||
"""
|
||||
)
|
||||
|
||||
def test_django_objecttype_convert_choices_enum_naming_collisions(
|
||||
|
@ -511,24 +600,27 @@ class TestDjangoObjectType:
|
|||
|
||||
assert str(schema) == dedent(
|
||||
"""\
|
||||
schema {
|
||||
query: Query
|
||||
}
|
||||
type Query {
|
||||
pet: PetModelKind
|
||||
}
|
||||
|
||||
type PetModelKind {
|
||||
id: ID!
|
||||
kind: TestsPetModelKindChoices!
|
||||
}
|
||||
type PetModelKind {
|
||||
\"""\"""
|
||||
id: ID!
|
||||
|
||||
type Query {
|
||||
pet: PetModelKind
|
||||
}
|
||||
\"""\"""
|
||||
kind: TestsPetModelKindChoices!
|
||||
}
|
||||
|
||||
enum TestsPetModelKindChoices {
|
||||
CAT
|
||||
DOG
|
||||
}
|
||||
"""
|
||||
\"""An enumeration.\"""
|
||||
enum TestsPetModelKindChoices {
|
||||
\"""Cat\"""
|
||||
CAT
|
||||
|
||||
\"""Dog\"""
|
||||
DOG
|
||||
}
|
||||
"""
|
||||
)
|
||||
|
||||
def test_django_objecttype_choices_custom_enum_name(
|
||||
|
@ -550,22 +642,25 @@ class TestDjangoObjectType:
|
|||
|
||||
assert str(schema) == dedent(
|
||||
"""\
|
||||
schema {
|
||||
query: Query
|
||||
}
|
||||
type Query {
|
||||
pet: PetModelKind
|
||||
}
|
||||
|
||||
enum CustomEnumKind {
|
||||
CAT
|
||||
DOG
|
||||
}
|
||||
type PetModelKind {
|
||||
\"""\"""
|
||||
id: ID!
|
||||
|
||||
type PetModelKind {
|
||||
id: ID!
|
||||
kind: CustomEnumKind!
|
||||
}
|
||||
\"""\"""
|
||||
kind: CustomEnumKind!
|
||||
}
|
||||
|
||||
type Query {
|
||||
pet: PetModelKind
|
||||
}
|
||||
"""
|
||||
\"""An enumeration.\"""
|
||||
enum CustomEnumKind {
|
||||
\"""Cat\"""
|
||||
CAT
|
||||
|
||||
\"""Dog\"""
|
||||
DOG
|
||||
}
|
||||
"""
|
||||
)
|
||||
|
|
|
@ -99,12 +99,14 @@ def test_reports_validation_errors(client):
|
|||
assert response_json(response) == {
|
||||
"errors": [
|
||||
{
|
||||
"message": 'Cannot query field "unknownOne" on type "QueryRoot".',
|
||||
"message": "Cannot query field 'unknownOne' on type 'QueryRoot'.",
|
||||
"locations": [{"line": 1, "column": 9}],
|
||||
"path": None,
|
||||
},
|
||||
{
|
||||
"message": 'Cannot query field "unknownTwo" on type "QueryRoot".',
|
||||
"message": "Cannot query field 'unknownTwo' on type 'QueryRoot'.",
|
||||
"locations": [{"line": 1, "column": 21}],
|
||||
"path": None,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
@ -124,7 +126,9 @@ def test_errors_when_missing_operation_name(client):
|
|||
assert response_json(response) == {
|
||||
"errors": [
|
||||
{
|
||||
"message": "Must provide operation name if query contains multiple operations."
|
||||
"message": "Must provide operation name if query contains multiple operations.",
|
||||
"locations": None,
|
||||
"path": None,
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -464,8 +468,8 @@ def test_handles_syntax_errors_caught_by_graphql(client):
|
|||
"errors": [
|
||||
{
|
||||
"locations": [{"column": 1, "line": 1}],
|
||||
"message": "Syntax Error GraphQL (1:1) "
|
||||
'Unexpected Name "syntaxerror"\n\n1: syntaxerror\n ^\n',
|
||||
"message": "Syntax Error: Unexpected Name 'syntaxerror'.",
|
||||
"path": None,
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -6,14 +6,14 @@ from django.http import HttpResponse, HttpResponseNotAllowed
|
|||
from django.http.response import HttpResponseBadRequest
|
||||
from django.shortcuts import render
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.views.generic import View
|
||||
from django.views.decorators.csrf import ensure_csrf_cookie
|
||||
from django.views.generic import View
|
||||
|
||||
from graphql import get_default_backend
|
||||
from graphql.error import format_error as format_graphql_error
|
||||
from graphene import Schema
|
||||
from graphql import parse, get_operation_ast, OperationType, execute, validate
|
||||
from graphql.error import GraphQLError
|
||||
from graphql.error import format_error as format_graphql_error
|
||||
from graphql.execution import ExecutionResult
|
||||
from graphql.type.schema import GraphQLSchema
|
||||
|
||||
from .settings import graphene_settings
|
||||
|
||||
|
@ -66,35 +66,28 @@ class GraphQLView(View):
|
|||
def __init__(
|
||||
self,
|
||||
schema=None,
|
||||
executor=None,
|
||||
middleware=None,
|
||||
root_value=None,
|
||||
graphiql=False,
|
||||
pretty=False,
|
||||
batch=False,
|
||||
backend=None,
|
||||
):
|
||||
if not schema:
|
||||
schema = graphene_settings.SCHEMA
|
||||
|
||||
if backend is None:
|
||||
backend = get_default_backend()
|
||||
|
||||
if middleware is None:
|
||||
middleware = graphene_settings.MIDDLEWARE
|
||||
|
||||
self.schema = self.schema or schema
|
||||
if middleware is not None:
|
||||
self.middleware = list(instantiate_middleware(middleware))
|
||||
self.executor = executor
|
||||
self.root_value = root_value
|
||||
self.pretty = self.pretty or pretty
|
||||
self.graphiql = self.graphiql or graphiql
|
||||
self.batch = self.batch or batch
|
||||
self.backend = backend
|
||||
|
||||
assert isinstance(
|
||||
self.schema, GraphQLSchema
|
||||
self.schema, Schema
|
||||
), "A Schema is required to be provided to GraphQLView."
|
||||
assert not all((graphiql, batch)), "Use either graphiql or batch processing"
|
||||
|
||||
|
@ -108,9 +101,6 @@ class GraphQLView(View):
|
|||
def get_context(self, request):
|
||||
return request
|
||||
|
||||
def get_backend(self, request):
|
||||
return self.backend
|
||||
|
||||
@method_decorator(ensure_csrf_cookie)
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
try:
|
||||
|
@ -172,7 +162,9 @@ class GraphQLView(View):
|
|||
self.format_error(e) for e in execution_result.errors
|
||||
]
|
||||
|
||||
if execution_result.invalid:
|
||||
if execution_result.errors and any(
|
||||
not e.path for e in execution_result.errors
|
||||
):
|
||||
status_code = 400
|
||||
else:
|
||||
response["data"] = execution_result.data
|
||||
|
@ -245,14 +237,13 @@ class GraphQLView(View):
|
|||
raise HttpError(HttpResponseBadRequest("Must provide query string."))
|
||||
|
||||
try:
|
||||
backend = self.get_backend(request)
|
||||
document = backend.document_from_string(self.schema, query)
|
||||
document = parse(query)
|
||||
except Exception as e:
|
||||
return ExecutionResult(errors=[e], invalid=True)
|
||||
return ExecutionResult(errors=[e])
|
||||
|
||||
if request.method.lower() == "get":
|
||||
operation_type = document.get_operation_type(operation_name)
|
||||
if operation_type and operation_type != "query":
|
||||
operation_ast = get_operation_ast(document, operation_name)
|
||||
if operation_ast and operation_ast.operation != OperationType.QUERY:
|
||||
if show_graphiql:
|
||||
return None
|
||||
|
||||
|
@ -260,28 +251,23 @@ class GraphQLView(View):
|
|||
HttpResponseNotAllowed(
|
||||
["POST"],
|
||||
"Can only perform a {} operation from a POST request.".format(
|
||||
operation_type
|
||||
operation_ast.operation.value
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
try:
|
||||
extra_options = {}
|
||||
if self.executor:
|
||||
# We only include it optionally since
|
||||
# executor is not a valid argument in all backends
|
||||
extra_options["executor"] = self.executor
|
||||
validation_errors = validate(self.schema.graphql_schema, document)
|
||||
if validation_errors:
|
||||
return ExecutionResult(data=None, errors=validation_errors)
|
||||
|
||||
return document.execute(
|
||||
root_value=self.get_root_value(request),
|
||||
variable_values=variables,
|
||||
operation_name=operation_name,
|
||||
context_value=self.get_context(request),
|
||||
middleware=self.get_middleware(request),
|
||||
**extra_options
|
||||
)
|
||||
except Exception as e:
|
||||
return ExecutionResult(errors=[e], invalid=True)
|
||||
return self.schema.execute(
|
||||
source=query,
|
||||
root_value=self.get_root_value(request),
|
||||
variable_values=variables,
|
||||
operation_name=operation_name,
|
||||
context_value=self.get_context(request),
|
||||
middleware=self.get_middleware(request),
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def can_display_graphiql(cls, request, data):
|
||||
|
|
Loading…
Reference in New Issue
Block a user