Skip to content

Commit 56d42c5

Browse files
committed
Added static typing with mypy
1 parent d60b180 commit 56d42c5

File tree

5 files changed

+126
-112
lines changed

5 files changed

+126
-112
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@
88
/build/
99

1010
/dist/
11+
/.mypy_cache
12+
/.pytest_cache

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ matrix:
1111
- python: '3.5'
1212
env: TOX_ENV=py35
1313
- python: '3.6'
14-
env: TOX_ENV=py36,import-order,flake8
14+
env: TOX_ENV=py36,import-order,flake8,mypy
1515
cache:
1616
directories:
1717
- $HOME/.cache/pip

graphql_server/__init__.py

Lines changed: 90 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -8,71 +8,79 @@
88

99
from .error import HttpQueryError
1010

11+
if False:
12+
from typing import List, Dict, Optional, Tuple, Any, Union, Callable, Type
13+
from graphql import GraphQLSchema, GraphQLBackend
14+
1115

1216
class SkipException(Exception):
1317
pass
1418

1519

16-
GraphQLParams = namedtuple('GraphQLParams', 'query,variables,operation_name')
17-
GraphQLResponse = namedtuple('GraphQLResponse', 'result,status_code')
20+
GraphQLParams = namedtuple("GraphQLParams", "query,variables,operation_name")
21+
GraphQLResponse = namedtuple("GraphQLResponse", "result,status_code")
1822

1923

20-
def run_http_query(schema, request_method, data, query_data=None, batch_enabled=False, catch=False, **execute_options):
21-
if request_method not in ('get', 'post'):
24+
def run_http_query(
25+
schema, # type: GraphQLSchema
26+
request_method, # type: str
27+
data, # type: Union[Dict, List[Dict]]
28+
query_data=None, # type: Optional[Dict]
29+
batch_enabled=False, # type: bool
30+
catch=False, # type: bool
31+
**execute_options # type: Dict
32+
):
33+
if request_method not in ("get", "post"):
2234
raise HttpQueryError(
2335
405,
24-
'GraphQL only supports GET and POST requests.',
25-
headers={
26-
'Allow': 'GET, POST'
27-
}
36+
"GraphQL only supports GET and POST requests.",
37+
headers={"Allow": "GET, POST"},
2838
)
2939
if catch:
30-
catch = HttpQueryError
40+
catch_exc = (
41+
HttpQueryError
42+
) # type: Union[Type[HttpQueryError], Type[SkipException]]
3143
else:
32-
catch = SkipException
44+
catch_exc = SkipException
3345
is_batch = isinstance(data, list)
3446

35-
is_get_request = request_method == 'get'
47+
is_get_request = request_method == "get"
3648
allow_only_query = is_get_request
3749

3850
if not is_batch:
3951
if not isinstance(data, (dict, MutableMapping)):
4052
raise HttpQueryError(
41-
400,
42-
'GraphQL params should be a dict. Received {}.'.format(data)
53+
400, "GraphQL params should be a dict. Received {}.".format(data)
4354
)
4455
data = [data]
4556
elif not batch_enabled:
46-
raise HttpQueryError(
47-
400,
48-
'Batch GraphQL requests are not enabled.'
49-
)
57+
raise HttpQueryError(400, "Batch GraphQL requests are not enabled.")
5058

5159
if not data:
52-
raise HttpQueryError(
53-
400,
54-
'Received an empty list in the batch request.'
55-
)
60+
raise HttpQueryError(400, "Received an empty list in the batch request.")
5661

57-
extra_data = {}
62+
extra_data = {} # type: Dict[str, Any]
5863
# If is a batch request, we don't consume the data from the query
5964
if not is_batch:
6065
extra_data = query_data or {}
6166

6267
all_params = [get_graphql_params(entry, extra_data) for entry in data]
6368

64-
responses = [get_response(
65-
schema,
66-
params,
67-
catch,
68-
allow_only_query,
69-
**execute_options
70-
) for params in all_params]
69+
responses = [
70+
get_response(schema, params, catch_exc, allow_only_query, **execute_options)
71+
for params in all_params
72+
]
7173

7274
return responses, all_params
7375

7476

75-
def encode_execution_results(execution_results, format_error, is_batch, encode):
77+
def encode_execution_results(
78+
execution_results, # type: List[Optional[ExecutionResult]]
79+
format_error, # type: Callable[[Exception], Dict]
80+
is_batch, # type: bool
81+
encode, # type: Callable[[Dict], Any]
82+
):
83+
# type: (...) -> Tuple[Any, int]
7684
responses = [
7785
format_execution_result(execution_result, format_error)
7886
for execution_result in execution_results
@@ -87,72 +95,77 @@ def encode_execution_results(execution_results, format_error, is_batch, encode):
8795

8896

8997
def json_encode(data, pretty=False):
98+
# type: (Dict, bool) -> str
9099
if not pretty:
91-
return json.dumps(data, separators=(',', ':'))
100+
return json.dumps(data, separators=(",", ":"))
92101

93-
return json.dumps(
94-
data,
95-
indent=2,
96-
separators=(',', ': ')
97-
)
102+
return json.dumps(data, indent=2, separators=(",", ": "))
98103

99104

100105
def load_json_variables(variables):
106+
# type: (Optional[Union[str, Dict]]) -> Optional[Dict]
101107
if variables and isinstance(variables, six.string_types):
102108
try:
103109
return json.loads(variables)
104110
except Exception:
105-
raise HttpQueryError(400, 'Variables are invalid JSON.')
106-
return variables
111+
raise HttpQueryError(400, "Variables are invalid JSON.")
112+
return variables # type: ignore
107113

108114

109115
def get_graphql_params(data, query_data):
110-
query = data.get('query') or query_data.get('query')
111-
variables = data.get('variables') or query_data.get('variables')
116+
# type: (Dict, Dict) -> GraphQLParams
117+
query = data.get("query") or query_data.get("query")
118+
variables = data.get("variables") or query_data.get("variables")
112119
# document_id = data.get('documentId')
113-
operation_name = data.get('operationName') or query_data.get('operationName')
120+
operation_name = data.get("operationName") or query_data.get("operationName")
114121

115122
return GraphQLParams(query, load_json_variables(variables), operation_name)
116123

117124

118-
def get_response(schema, params, catch=None, allow_only_query=False, **kwargs):
125+
def get_response(
126+
schema, # type: GraphQLSchema
127+
params, # type: GraphQLParams
128+
catch, # type: Type[BaseException]
129+
allow_only_query=False, # type: bool
130+
**kwargs # type: Dict
131+
):
132+
# type: (...) -> Optional[ExecutionResult]
119133
try:
120134
execution_result = execute_graphql_request(
121-
schema,
122-
params,
123-
allow_only_query,
124-
**kwargs
135+
schema, params, allow_only_query, **kwargs
125136
)
126137
except catch:
127138
return None
128139

129140
return execution_result
130141

131142

132-
def format_execution_result(execution_result, format_error):
143+
def format_execution_result(
144+
execution_result, # type: Optional[ExecutionResult]
145+
format_error, # type: Optional[Callable[[Exception], Dict]]
146+
):
147+
# type: (...) -> GraphQLResponse
133148
status_code = 200
134149

135150
if execution_result:
136-
response = {}
137-
138-
if execution_result.errors:
139-
response['errors'] = [format_error(e) for e in execution_result.errors]
140-
141151
if execution_result.invalid:
142152
status_code = 400
143-
else:
144-
status_code = 200
145-
response['data'] = execution_result.data
146-
153+
response = execution_result.to_dict(format_error=format_error)
147154
else:
148155
response = None
149156

150157
return GraphQLResponse(response, status_code)
151158

152159

153-
def execute_graphql_request(schema, params, allow_only_query=False, backend=None, **kwargs):
160+
def execute_graphql_request(
161+
schema, # type: GraphQLSchema
162+
params, # type: GraphQLParams
163+
allow_only_query=False, # type: bool
164+
backend=None, # type: GraphQLBackend
165+
**kwargs # type: Dict
166+
):
154167
if not params.query:
155-
raise HttpQueryError(400, 'Must provide query string.')
168+
raise HttpQueryError(400, "Must provide query string.")
156169

157170
try:
158171
if not backend:
@@ -163,45 +176,41 @@ def execute_graphql_request(schema, params, allow_only_query=False, backend=None
163176

164177
if allow_only_query:
165178
operation_type = document.get_operation_type(params.operation_name)
166-
if operation_type and operation_type != 'query':
179+
if operation_type and operation_type != "query":
167180
raise HttpQueryError(
168181
405,
169-
'Can only perform a {} operation from a POST request.'.format(operation_type),
170-
headers={
171-
'Allow': 'POST',
172-
}
182+
"Can only perform a {} operation from a POST request.".format(
183+
operation_type
184+
),
185+
headers={"Allow": "POST"},
173186
)
174187

175188
try:
176189
return document.execute(
177-
operation_name=params.operation_name,
178-
variables=params.variables,
179-
**kwargs
190+
operation_name=params.operation_name, variables=params.variables, **kwargs
180191
)
181192
except Exception as e:
182193
return ExecutionResult(errors=[e], invalid=True)
183194

184195

185196
def load_json_body(data):
197+
# type: (str) -> Dict
186198
try:
187199
return json.loads(data)
188200
except Exception:
189-
raise HttpQueryError(
190-
400,
191-
'POST body sent invalid JSON.'
192-
)
201+
raise HttpQueryError(400, "POST body sent invalid JSON.")
193202

194203

195204
__all__ = [
196-
'default_format_error',
197-
'SkipException',
198-
'run_http_query',
199-
'encode_execution_results',
200-
'json_encode',
201-
'load_json_variables',
202-
'get_graphql_params',
203-
'get_response',
204-
'format_execution_result',
205-
'execute_graphql_request',
206-
'load_json_body'
205+
"default_format_error",
206+
"SkipException",
207+
"run_http_query",
208+
"encode_execution_results",
209+
"json_encode",
210+
"load_json_variables",
211+
"get_graphql_params",
212+
"get_response",
213+
"format_execution_result",
214+
"execute_graphql_request",
215+
"load_json_body",
207216
]

setup.py

Lines changed: 25 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,35 @@
11
from setuptools import setup, find_packages
22

3-
required_packages = [
4-
'graphql-core>=2.1rc1',
5-
'promise'
6-
]
3+
required_packages = ["graphql-core>=2.1", "promise"]
74

85
setup(
9-
name='graphql-server-core',
10-
version='1.1rc0',
11-
description='GraphQL Server tools for powering your server',
12-
long_description=open('README.rst').read(),
13-
url='https://github.com/graphql-python/graphql-server-core',
14-
download_url='https://github.com/graphql-python/graphql-server-core/releases',
15-
author='Syrus Akbary',
16-
author_email='me@syrusakbary.com',
17-
license='MIT',
6+
name="graphql-server-core",
7+
version="1.1rc0",
8+
description="GraphQL Server tools for powering your server",
9+
long_description=open("README.rst").read(),
10+
url="https://github.com/graphql-python/graphql-server-core",
11+
download_url="https://github.com/graphql-python/graphql-server-core/releases",
12+
author="Syrus Akbary",
13+
author_email="me@syrusakbary.com",
14+
license="MIT",
1815
classifiers=[
19-
'Development Status :: 5 - Production/Stable',
20-
'Intended Audience :: Developers',
21-
'Topic :: Software Development :: Libraries',
22-
'Programming Language :: Python :: 2',
23-
'Programming Language :: Python :: 2.7',
24-
'Programming Language :: Python :: 3',
25-
'Programming Language :: Python :: 3.3',
26-
'Programming Language :: Python :: 3.4',
27-
'Programming Language :: Python :: 3.5',
28-
'Programming Language :: Python :: Implementation :: PyPy',
29-
'License :: OSI Approved :: MIT License',
16+
"Development Status :: 5 - Production/Stable",
17+
"Intended Audience :: Developers",
18+
"Topic :: Software Development :: Libraries",
19+
"Programming Language :: Python :: 2",
20+
"Programming Language :: Python :: 2.7",
21+
"Programming Language :: Python :: 3",
22+
"Programming Language :: Python :: 3.3",
23+
"Programming Language :: Python :: 3.4",
24+
"Programming Language :: Python :: 3.5",
25+
"Programming Language :: Python :: Implementation :: PyPy",
26+
"License :: OSI Approved :: MIT License",
3027
],
31-
keywords='api graphql protocol rest',
32-
packages=find_packages(exclude=['tests']),
28+
keywords="api graphql protocol rest",
29+
packages=find_packages(exclude=["tests"]),
3330
install_requires=required_packages,
34-
tests_require=['pytest>=2.7.3'],
31+
tests_require=["pytest>=2.7.3"],
3532
include_package_data=True,
3633
zip_safe=False,
37-
platforms='any',
34+
platforms="any",
3835
)

tox.ini

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ setenv =
77
PYTHONPATH = {toxinidir}
88
deps =
99
pytest>=2.7.2
10-
graphql-core>=2.1rc1
10+
graphql-core>=2.1
1111
pytest-cov
1212
commands =
1313
py{py,27,34,35,36}: py.test tests {posargs}
@@ -18,10 +18,16 @@ deps = flake8
1818
commands =
1919
flake8 graphql_server
2020

21+
[testenv:mypy]
22+
basepython=python3.6
23+
deps = mypy
24+
commands =
25+
mypy graphql_server --ignore-missing-imports
26+
2127
[testenv:import-order]
2228
basepython=python3.6
2329
deps =
2430
isort
25-
graphql-core>=2.1rc1
31+
graphql-core>=2.1
2632
commands =
2733
isort --check-only graphql_server/ -rc

0 commit comments

Comments
 (0)