Skip to content

Commit d16ce14

Browse files
committed
Extend type checks to functions without type annotations
1 parent c3f47da commit d16ce14

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+425
-274
lines changed

mypy.ini

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
[mypy]
22
python_version = 3.7
3-
warn_redundant_casts = true
3+
check_untyped_defs = True
4+
warn_redundant_casts = True
45
warn_unused_ignores = True
56
# https://github.com/python/mypy/issues/7203
67
new_semantic_analyzer = False

src/graphql/execution/execute.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ def build_response(
306306
if isawaitable(data):
307307

308308
async def build_response_async():
309-
return self.build_response(await data)
309+
return self.build_response(await data) # type: ignore
310310

311311
return build_response_async()
312312
data = cast(Optional[Dict[str, Any]], data)
@@ -353,7 +353,7 @@ def execute_operation(
353353
# noinspection PyShadowingNames
354354
async def await_result():
355355
try:
356-
return await result
356+
return await result # type: ignore
357357
except GraphQLError as error:
358358
self.errors.append(error)
359359
except Exception as error:
@@ -872,15 +872,19 @@ def complete_abstract_value(
872872
async def await_complete_object_value():
873873
value = self.complete_object_value(
874874
self.ensure_valid_runtime_type(
875-
await runtime_type, return_type, field_nodes, info, result
875+
await runtime_type, # type: ignore
876+
return_type,
877+
field_nodes,
878+
info,
879+
result,
876880
),
877881
field_nodes,
878882
info,
879883
path,
880884
result,
881885
)
882886
if isawaitable(value):
883-
return await value
887+
return await value # type: ignore
884888
return value
885889

886890
return await_complete_object_value()
@@ -950,7 +954,7 @@ def complete_object_value(
950954
if isawaitable(is_type_of):
951955

952956
async def collect_and_execute_subfields_async():
953-
if not await is_type_of:
957+
if not await is_type_of: # type: ignore
954958
raise invalid_return_type_error(
955959
return_type, result, field_nodes
956960
)

src/graphql/language/ast.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from copy import copy, deepcopy
22
from enum import Enum
3-
from typing import NamedTuple, Optional, Union
3+
from typing import List, NamedTuple, Optional, Union
44

55
from .source import Source
66
from .token_kind import TokenKind
@@ -230,13 +230,13 @@ def __deepcopy__(self, memo):
230230
**{key: deepcopy(getattr(self, key), memo) for key in self.keys}
231231
)
232232

233-
def __init_subclass__(cls, **kwargs):
234-
super().__init_subclass__(**kwargs)
233+
def __init_subclass__(cls):
234+
super().__init_subclass__()
235235
name = cls.__name__
236236
if name.endswith("Node"):
237237
name = name[:-4]
238238
cls.kind = camel_to_snake(name)
239-
keys = []
239+
keys: List[str] = []
240240
for base in cls.__bases__:
241241
# noinspection PyUnresolvedReferences
242242
keys.extend(base.keys)

src/graphql/language/visitor.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,9 @@ def enter(self, node, key, parent, path, ancestors):
151151
# Provide special return values as attributes
152152
BREAK, SKIP, REMOVE, IDLE = BREAK, SKIP, REMOVE, IDLE
153153

154-
def __init_subclass__(cls, **kwargs):
154+
def __init_subclass__(cls):
155155
"""Verify that all defined handlers are valid."""
156-
super().__init_subclass__(**kwargs)
156+
super().__init_subclass__()
157157
for attr, val in cls.__dict__.items():
158158
if attr.startswith("_"):
159159
continue

src/graphql/pyutils/frozen_dict.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@ def __delitem__(self, key):
1818
def __setitem__(self, key, value):
1919
raise FrozenError
2020

21-
def __add__(self, value):
22-
return dict.__add__(self, value)
23-
2421
def __iadd__(self, value):
2522
raise FrozenError
2623

src/graphql/type/directives.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ def __repr__(self):
108108
def __eq__(self, other):
109109
return self is other or (
110110
isinstance(other, GraphQLDirective)
111-
and self.type == other.type
111+
and self.name == other.name
112112
and self.locations == other.locations
113113
and self.args == other.args
114114
and self.is_repeatable == other.is_repeatable

src/graphql/type/validate.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ def validate_directives(self):
152152
self.validate_name(directive)
153153

154154
# Ensure the arguments are valid.
155-
arg_names = set()
155+
arg_names: Set[str] = set()
156156
for arg_name, arg in directive.args.items():
157157
# Ensure they are named correctly.
158158
self.validate_name(arg_name, arg)

tests/error/test_format_error.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from typing import List, Union
2+
13
from pytest import raises # type: ignore
24

35
from graphql.error import GraphQLError, format_error
@@ -8,7 +10,7 @@ def describe_format_error():
810
def throw_if_not_an_error():
911
with raises(TypeError):
1012
# noinspection PyTypeChecker
11-
format_error(None)
13+
format_error(None) # type: ignore
1214

1315
def format_graphql_error():
1416
source = Source(
@@ -17,7 +19,7 @@ def format_graphql_error():
1719
something
1820
}"""
1921
)
20-
path = ["one", 2]
22+
path: List[Union[int, str]] = ["one", 2]
2123
extensions = {"ext": None}
2224
error = GraphQLError(
2325
"test message",
@@ -37,5 +39,5 @@ def format_graphql_error():
3739

3840
def add_default_message():
3941
# noinspection PyTypeChecker
40-
error = format_error(GraphQLError(None))
42+
error = format_error(GraphQLError(None)) # type: ignore
4143
assert error["message"] == "An unknown error occurred."

tests/error/test_graphql_error.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import cast
1+
from typing import cast, List, Union
22

33
from graphql.error import GraphQLError, format_error, print_error
44
from graphql.language import (
@@ -109,13 +109,13 @@ def serializes_to_include_message_and_locations():
109109
)
110110

111111
def serializes_to_include_path():
112-
path = ["path", 3, "to", "field"]
112+
path: List[Union[int, str]] = ["path", 3, "to", "field"]
113113
e = GraphQLError("msg", path=path)
114114
assert e.path is path
115115
assert repr(e) == "GraphQLError('msg', path=['path', 3, 'to', 'field'])"
116116

117117
def default_error_formatter_includes_path():
118-
path = ["path", 3, "to", "field"]
118+
path: List[Union[int, str]] = ["path", 3, "to", "field"]
119119
e = GraphQLError("msg", path=path)
120120
formatted = format_error(e)
121121
assert formatted == e.formatted

tests/error/test_located_error.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
1+
from typing import cast, Any
2+
13
from graphql.error import GraphQLError, located_error
24

35

46
def describe_located_error():
57
def passes_graphql_error_through():
68
path = ["path", 3, "to", "field"]
79
# noinspection PyArgumentEqualDefault
8-
e = GraphQLError("msg", None, None, None, path)
10+
e = GraphQLError("msg", None, None, None, path) # type: ignore
911
assert located_error(e, [], []) == e
1012

1113
def passes_graphql_error_ish_through():
12-
e = Exception("I am an ordinary exception")
14+
e = cast(GraphQLError, Exception("I am an ordinary exception"))
1315
e.locations = []
1416
e.path = []
1517
e.nodes = []
@@ -18,6 +20,6 @@ def passes_graphql_error_ish_through():
1820
assert located_error(e, [], []) == e
1921

2022
def does_not_pass_through_elasticsearch_like_errors():
21-
e = Exception("I am from elasticsearch")
23+
e = cast(Any, Exception("I am from elasticsearch"))
2224
e.path = "/something/feed/_search"
2325
assert located_error(e, [], []) != e

tests/execution/test_abstract.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ def resolve_type_on_interface_yields_useful_error():
249249
]
250250
}
251251

252+
assert result.errors
252253
assert len(result.errors) == 1
253254
assert format_error(result.errors[0]) == {
254255
"message": "Runtime Object type 'Human'"
@@ -324,6 +325,7 @@ def resolve_type_on_union_yields_useful_error():
324325
]
325326
}
326327

328+
assert result.errors
327329
assert len(result.errors) == 1
328330
assert format_error(result.errors[0]) == {
329331
"message": "Runtime Object type 'Human'"
@@ -333,20 +335,22 @@ def resolve_type_on_union_yields_useful_error():
333335
}
334336

335337
def returning_invalid_value_from_resolve_type_yields_useful_error():
336-
fooInterface = GraphQLInterfaceType(
338+
foo_interface = GraphQLInterfaceType( # type: ignore
337339
"FooInterface",
338340
{"bar": GraphQLField(GraphQLString)},
339341
resolve_type=lambda *_args: [],
340342
)
341343

342344
foo_object = GraphQLObjectType(
343-
"FooObject", {"bar": GraphQLField(GraphQLString)}, interfaces=[fooInterface]
345+
"FooObject",
346+
{"bar": GraphQLField(GraphQLString)},
347+
interfaces=[foo_interface],
344348
)
345349

346350
schema = GraphQLSchema(
347351
GraphQLObjectType(
348352
"Query",
349-
{"foo": GraphQLField(fooInterface, resolve=lambda *_args: "dummy")},
353+
{"foo": GraphQLField(foo_interface, resolve=lambda *_args: "dummy")},
350354
),
351355
types=[foo_object],
352356
)

tests/execution/test_abstract_async.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ async def is_type_of_with_async_error():
179179
# Note: we get two errors, because first all types are resolved
180180
# and only then they are checked sequentially
181181
assert result.data == {"pets": [None, None]}
182-
assert list(map(format_error, result.errors)) == [
182+
assert list(map(format_error, result.errors)) == [ # type: ignore
183183
{
184184
"message": "We are testing this error",
185185
"locations": [(3, 15)],
@@ -329,6 +329,7 @@ async def resolve_type_on_interface_yields_useful_error():
329329
]
330330
}
331331

332+
assert result.errors
332333
assert len(result.errors) == 1
333334
assert format_error(result.errors[0]) == {
334335
"message": "Runtime Object type 'Human'"
@@ -405,6 +406,7 @@ async def resolve_type_on_union_yields_useful_error():
405406
]
406407
}
407408

409+
assert result.errors
408410
assert len(result.errors) == 1
409411
assert format_error(result.errors[0]) == {
410412
"message": "Runtime Object type 'Human'"

tests/execution/test_customize.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def uses_a_custom_execution_context_class():
3333
class TestExecutionContext(ExecutionContext):
3434
def resolve_field(self, parent_type, source, field_nodes, path):
3535
result = super().resolve_field(parent_type, source, field_nodes, path)
36-
return result * 2
36+
return result * 2 # type: ignore
3737

3838
assert execute(schema, query, execution_context_class=TestExecutionContext) == (
3939
{"foo": "barbar"},

tests/execution/test_executor.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def throws_if_no_document_is_provided():
3232
)
3333

3434
with raises(TypeError) as exc_info:
35-
assert execute(schema=schema, document=None)
35+
assert execute(schema=schema, document=None) # type: ignore
3636

3737
assert str(exc_info.value) == "Must provide document"
3838

@@ -41,7 +41,7 @@ def throws_if_no_schema_is_provided():
4141
document = parse("{ field }")
4242

4343
with raises(TypeError) as exc_info:
44-
assert execute(schema=None, document=document)
44+
assert execute(schema=None, document=document) # type: ignore
4545

4646
assert str(exc_info.value) == "Expected None to be a GraphQL schema."
4747

@@ -84,10 +84,10 @@ def pic(self, _info, size=50):
8484
return f"Pic of size: {size}"
8585

8686
def deep(self, _info):
87-
return DeepData()
87+
return DeepData() # type: ignore
8888

8989
def promise(self, _info):
90-
return promise_data()
90+
return promise_data() # type: ignore
9191

9292
# noinspection PyMethodMayBeStatic,PyMethodMayBeStatic
9393
class DeepData:
@@ -266,7 +266,7 @@ def resolve(_obj, info):
266266
field_name="test",
267267
field_nodes=[field],
268268
return_type=GraphQLString,
269-
parent_type=schema.query_type,
269+
parent_type=cast(GraphQLObjectType, schema.query_type),
270270
path=ResponsePath(None, "result"),
271271
schema=schema,
272272
fragments={},

0 commit comments

Comments
 (0)