Skip to content

Commit b4e46ee

Browse files
committed
Refactor/rename.
Drop `parallel_execution` It’s just the `Executor` from now on. Shorten the middleware filenames. On Tox, run import-order on python3.5
1 parent a34e6e1 commit b4e46ee

File tree

8 files changed

+269
-252
lines changed

8 files changed

+269
-252
lines changed

graphql/core/execution/__init__.py

Lines changed: 5 additions & 227 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,4 @@
11
# -*- coding: utf-8 -*-
2-
from ..error import GraphQLError
3-
from ..language import ast
4-
from ..type.definition import (
5-
GraphQLInterfaceType,
6-
GraphQLUnionType,
7-
)
8-
from ..type.directives import (
9-
GraphQLIncludeDirective,
10-
GraphQLSkipDirective,
11-
)
12-
from ..type.introspection import (
13-
SchemaMetaFieldDef,
14-
TypeMetaFieldDef,
15-
TypeNameMetaFieldDef,
16-
)
17-
from ..utils import type_from_ast
18-
from .values import get_argument_values, get_variable_values
19-
20-
Undefined = object()
21-
222
"""
233
Terminology
244
@@ -39,219 +19,17 @@
3919
3) inline fragment "spreads" e.g. "...on Type { a }"
4020
"""
4121

42-
43-
class ExecutionContext(object):
44-
"""Data that must be available at all points during query execution.
45-
46-
Namely, schema of the type system that is currently executing,
47-
and the fragments defined in the query document"""
48-
49-
def __init__(self, schema, root, document_ast, operation_name, args):
50-
"""Constructs a ExecutionContext object from the arguments passed
51-
to execute, which we will pass throughout the other execution
52-
methods."""
53-
errors = []
54-
operations = {}
55-
fragments = {}
56-
for statement in document_ast.definitions:
57-
if isinstance(statement, ast.OperationDefinition):
58-
name = ''
59-
if statement.name:
60-
name = statement.name.value
61-
operations[name] = statement
62-
elif isinstance(statement, ast.FragmentDefinition):
63-
fragments[statement.name.value] = statement
64-
if not operation_name and len(operations) != 1:
65-
raise GraphQLError(
66-
'Must provide operation name '
67-
'if query contains multiple operations')
68-
op_name = operation_name or next(iter(operations.keys()))
69-
operation = operations.get(op_name)
70-
if not operation:
71-
raise GraphQLError('Unknown operation name: {}'.format(op_name))
72-
variables = get_variable_values(schema, operation.variable_definitions or [], args)
73-
74-
self.schema = schema
75-
self.fragments = fragments
76-
self.root = root
77-
self.operation = operation
78-
self.variables = variables
79-
self.errors = errors
80-
81-
82-
class ExecutionResult(object):
83-
"""The result of execution. `data` is the result of executing the
84-
query, `errors` is null if no errors occurred, and is a
85-
non-empty array if an error occurred."""
86-
87-
def __init__(self, data, errors=None):
88-
self.data = data
89-
self.errors = errors
22+
from .base import ExecutionResult
23+
from .executor import Executor
24+
from .middlewares.sync import SynchronousExecutionMiddleware
9025

9126

9227
def execute(schema, root, ast, operation_name='', args=None):
9328
"""
9429
Executes an AST synchronously. Assumes that the AST is already validated.
9530
"""
96-
from .parallel_execution import Executor
97-
from .middlewares import SynchronousExecutionMiddleware
98-
e = Executor(schema, [SynchronousExecutionMiddleware.SynchronousExecutionMiddleware()])
31+
e = Executor(schema, [SynchronousExecutionMiddleware()])
9932
return e.execute(ast, root, args, operation_name, validate_ast=False)
10033

10134

102-
def get_operation_root_type(schema, operation):
103-
op = operation.operation
104-
if op == 'query':
105-
return schema.get_query_type()
106-
elif op == 'mutation':
107-
mutation_type = schema.get_mutation_type()
108-
if not mutation_type:
109-
raise GraphQLError(
110-
'Schema is not configured for mutations',
111-
[operation]
112-
)
113-
return mutation_type
114-
raise GraphQLError(
115-
'Can only execute queries and mutations',
116-
[operation]
117-
)
118-
119-
120-
def collect_fields(ctx, type, selection_set, fields, prev_fragment_names):
121-
for selection in selection_set.selections:
122-
directives = selection.directives
123-
if isinstance(selection, ast.Field):
124-
if not should_include_node(ctx, directives):
125-
continue
126-
name = get_field_entry_key(selection)
127-
if name not in fields:
128-
fields[name] = []
129-
fields[name].append(selection)
130-
elif isinstance(selection, ast.InlineFragment):
131-
if not should_include_node(ctx, directives) or \
132-
not does_fragment_condition_match(ctx, selection, type):
133-
continue
134-
collect_fields(
135-
ctx, type, selection.selection_set,
136-
fields, prev_fragment_names)
137-
elif isinstance(selection, ast.FragmentSpread):
138-
frag_name = selection.name.value
139-
if frag_name in prev_fragment_names or \
140-
not should_include_node(ctx, directives):
141-
continue
142-
prev_fragment_names.add(frag_name)
143-
fragment = ctx.fragments.get(frag_name)
144-
frag_directives = fragment.directives
145-
if not fragment or \
146-
not should_include_node(ctx, frag_directives) or \
147-
not does_fragment_condition_match(ctx, fragment, type):
148-
continue
149-
collect_fields(
150-
ctx, type, fragment.selection_set,
151-
fields, prev_fragment_names)
152-
return fields
153-
154-
155-
def should_include_node(ctx, directives):
156-
"""Determines if a field should be included based on the @include and
157-
@skip directives, where @skip has higher precidence than @include."""
158-
if directives:
159-
skip_ast = None
160-
for directive in directives:
161-
if directive.name.value == GraphQLSkipDirective.name:
162-
skip_ast = directive
163-
break
164-
if skip_ast:
165-
args = get_argument_values(
166-
GraphQLSkipDirective.args,
167-
skip_ast.arguments,
168-
ctx.variables,
169-
)
170-
return not args.get('if')
171-
172-
include_ast = None
173-
for directive in directives:
174-
if directive.name.value == GraphQLIncludeDirective.name:
175-
include_ast = directive
176-
break
177-
if include_ast:
178-
args = get_argument_values(
179-
GraphQLIncludeDirective.args,
180-
include_ast.arguments,
181-
ctx.variables,
182-
)
183-
return bool(args.get('if'))
184-
185-
return True
186-
187-
188-
def does_fragment_condition_match(ctx, fragment, type_):
189-
conditional_type = type_from_ast(ctx.schema, fragment.type_condition)
190-
if type(conditional_type) == type(type_):
191-
return True
192-
if isinstance(conditional_type, (GraphQLInterfaceType, GraphQLUnionType)):
193-
return conditional_type.is_possible_type(type_)
194-
return False
195-
196-
197-
def get_field_entry_key(node):
198-
"""Implements the logic to compute the key of a given field’s entry"""
199-
if node.alias:
200-
return node.alias.value
201-
return node.name.value
202-
203-
204-
class ResolveInfo(object):
205-
def __init__(self, field_name, field_asts, return_type, parent_type, context):
206-
self.field_name = field_name
207-
self.field_asts = field_asts
208-
self.return_type = return_type
209-
self.parent_type = parent_type
210-
self.context = context
211-
212-
@property
213-
def schema(self):
214-
return self.context.schema
215-
216-
@property
217-
def fragments(self):
218-
return self.context.fragments
219-
220-
@property
221-
def root_value(self):
222-
return self.context.root_value
223-
224-
@property
225-
def operation(self):
226-
return self.context.operation
227-
228-
@property
229-
def variable_values(self):
230-
return self.context.variables
231-
232-
233-
def default_resolve_fn(source, args, info):
234-
"""If a resolve function is not given, then a default resolve behavior is used which takes the property of the source object
235-
of the same name as the field and returns it as the result, or if it's a function, returns the result of calling that function."""
236-
name = info.field_name
237-
property = getattr(source, name, None)
238-
if callable(property):
239-
return property()
240-
return property
241-
242-
243-
def get_field_def(schema, parent_type, field_name):
244-
"""This method looks up the field on the given type defintion.
245-
It has special casing for the two introspection fields, __schema
246-
and __typename. __typename is special because it can always be
247-
queried as a field, even in situations where no other fields
248-
are allowed, like on a Union. __schema could get automatically
249-
added to the query type, but that would require mutating type
250-
definitions, which would cause issues."""
251-
if field_name == SchemaMetaFieldDef.name and schema.get_query_type() == parent_type:
252-
return SchemaMetaFieldDef
253-
elif field_name == TypeMetaFieldDef.name and schema.get_query_type() == parent_type:
254-
return TypeMetaFieldDef
255-
elif field_name == TypeNameMetaFieldDef.name:
256-
return TypeNameMetaFieldDef
257-
return parent_type.get_fields().get(field_name)
35+
__all__ = ['ExecutionResult', 'Executor', 'execute']

0 commit comments

Comments
 (0)