Skip to content

Commit c496eed

Browse files
authored
Merge pull request #74 from graphql-python/features/next-query-builder
Query Builder + Promise 2.0 + DataLoader
2 parents 29aba38 + 8878e5c commit c496eed

30 files changed

+4233
-114
lines changed

.travis.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,7 @@ before_install:
2121
source "$HOME/virtualenvs/pypy-$PYPY_VERSION/bin/activate"
2222
fi
2323
install:
24-
- pip install pytest-cov pytest-mock coveralls flake8 gevent==1.1b5 six>=1.10.0 promise>=0.4.2
25-
pytest-benchmark
26-
- pip install pytest==2.9.2
27-
- pip install -e .
24+
- pip install -e .[test]
2825
script:
2926
- py.test --cov=graphql graphql tests
3027
after_success:
@@ -37,6 +34,7 @@ matrix:
3734
script:
3835
- py.test --cov=graphql graphql tests tests_py35
3936
- python: '2.7'
37+
install: pip install flake8
4038
script:
4139
- flake8
4240
deploy:

graphql/error/tests/test_base.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,14 @@ def resolver(context, *_):
4747
('resolve_or_error', 'return executor.execute(resolve_fn, source, args, context, info)'),
4848
('execute', 'return fn(*args, **kwargs)'), ('resolver', "raise Exception('Failed')")
4949
]
50+
# assert formatted_tb == [
51+
# ('test_reraise', 'result.errors[0].reraise()'),
52+
# ('reraise', 'six.reraise(type(self), self, self.stack)'),
53+
# ('on_complete_resolver', 'result = __resolver(*args, **kwargs)'),
54+
# # ('reraise', 'raise value.with_traceback(tb)'),
55+
# # ('resolve_or_error', 'return executor.execute(resolve_fn, source, args, context, info)'),
56+
# # ('execute', 'return fn(*args, **kwargs)'),
57+
# ('resolver', "raise Exception('Failed')")
58+
# ]
59+
5060
assert str(exc_info.value) == 'Failed'

graphql/execution/executor.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import sys
55

66
from six import string_types
7-
from promise import Promise, promise_for_dict, promisify, is_thenable
7+
from promise import Promise, promise_for_dict, is_thenable
88

99
from ..error import GraphQLError, GraphQLLocatedError
1010
from ..pyutils.default_ordered_dict import DefaultOrderedDict
@@ -16,6 +16,7 @@
1616
collect_fields, default_resolve_fn, get_field_def,
1717
get_operation_root_type)
1818
from .executors.sync import SyncExecutor
19+
from .experimental.executor import execute as experimental_execute
1920
from .middleware import MiddlewareManager
2021

2122
logger = logging.getLogger(__name__)
@@ -25,9 +26,19 @@ def is_promise(obj):
2526
return type(obj) == Promise
2627

2728

29+
use_experimental_executor = False
30+
31+
2832
def execute(schema, document_ast, root_value=None, context_value=None,
2933
variable_values=None, operation_name=None, executor=None,
3034
return_promise=False, middleware=None):
35+
if use_experimental_executor:
36+
return experimental_execute(
37+
schema, document_ast, root_value, context_value,
38+
variable_values, operation_name, executor,
39+
return_promise, middleware
40+
)
41+
3142
assert schema, 'Must provide schema'
3243
assert isinstance(schema, GraphQLSchema), (
3344
'Schema must be an instance of GraphQLSchema. Also ensure that there are ' +
@@ -106,7 +117,7 @@ def collect_result(resolved_result):
106117
results[response_name] = resolved_result
107118
return results
108119

109-
return promisify(result).then(collect_result, None)
120+
return result.then(collect_result, None)
110121

111122
results[response_name] = result
112123
return results
@@ -210,9 +221,9 @@ def complete_value_catching_error(exe_context, return_type, field_asts, info, re
210221
if is_thenable(completed):
211222
def handle_error(error):
212223
exe_context.errors.append(error)
213-
return Promise.fulfilled(None)
224+
return None
214225

215-
return promisify(completed).then(None, handle_error)
226+
return completed.catch(handle_error)
216227

217228
return completed
218229
except Exception as e:
@@ -242,7 +253,7 @@ def complete_value(exe_context, return_type, field_asts, info, result):
242253
# If field type is NonNull, complete for inner type, and throw field error if result is null.
243254

244255
if is_thenable(result):
245-
return promisify(result).then(
256+
return Promise.resolve(result).then(
246257
lambda resolved: complete_value(
247258
exe_context,
248259
return_type,

graphql/execution/executors/asyncio.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from asyncio import Future, get_event_loop, iscoroutine, wait
44

5-
from promise import promisify
5+
from promise import Promise
66

77
try:
88
from asyncio import ensure_future
@@ -49,5 +49,5 @@ def execute(self, fn, *args, **kwargs):
4949
if isinstance(result, Future) or iscoroutine(result):
5050
future = ensure_future(result, loop=self.loop)
5151
self.futures.append(future)
52-
return promisify(future)
52+
return Promise.resolve(future)
5353
return result

graphql/execution/executors/utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
def process(p, f, args, kwargs):
22
try:
33
val = f(*args, **kwargs)
4-
p.fulfill(val)
4+
p.do_resolve(val)
55
except Exception as e:
6-
p.reject(e)
6+
p.do_reject(e)

graphql/execution/experimental/__init__.py

Whitespace-only changes.
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
from promise import Promise
2+
3+
from ...type import GraphQLSchema
4+
from ..base import ExecutionContext, ExecutionResult, get_operation_root_type
5+
from ..executors.sync import SyncExecutor
6+
from ..middleware import MiddlewareManager
7+
from .fragment import Fragment
8+
9+
10+
def execute(schema, document_ast, root_value=None, context_value=None,
11+
variable_values=None, operation_name=None, executor=None,
12+
return_promise=False, middleware=None):
13+
assert schema, 'Must provide schema'
14+
assert isinstance(schema, GraphQLSchema), (
15+
'Schema must be an instance of GraphQLSchema. Also ensure that there are ' +
16+
'not multiple versions of GraphQL installed in your node_modules directory.'
17+
)
18+
if middleware:
19+
if not isinstance(middleware, MiddlewareManager):
20+
middleware = MiddlewareManager(*middleware)
21+
assert isinstance(middleware, MiddlewareManager), (
22+
'middlewares have to be an instance'
23+
' of MiddlewareManager. Received "{}".'.format(middleware)
24+
)
25+
26+
if executor is None:
27+
executor = SyncExecutor()
28+
29+
context = ExecutionContext(
30+
schema,
31+
document_ast,
32+
root_value,
33+
context_value,
34+
variable_values,
35+
operation_name,
36+
executor,
37+
middleware
38+
)
39+
40+
def executor(resolve, reject):
41+
return resolve(execute_operation(context, context.operation, root_value))
42+
43+
def on_rejected(error):
44+
context.errors.append(error)
45+
return None
46+
47+
def on_resolve(data):
48+
return ExecutionResult(data=data, errors=context.errors)
49+
50+
promise = Promise(executor).catch(on_rejected).then(on_resolve)
51+
if return_promise:
52+
return promise
53+
context.executor.wait_until_finished()
54+
return promise.get()
55+
56+
57+
def execute_operation(exe_context, operation, root_value):
58+
type = get_operation_root_type(exe_context.schema, operation)
59+
execute_serially = operation.operation == 'mutation'
60+
61+
fragment = Fragment(type=type, field_asts=[operation], context=exe_context)
62+
if execute_serially:
63+
return fragment.resolve_serially(root_value)
64+
return fragment.resolve(root_value)

0 commit comments

Comments
 (0)