From 6ff8f4d803b1c88653a6e36e38afd72a60a7fe5c Mon Sep 17 00:00:00 2001 From: Tomasz Kontusz Date: Mon, 16 Sep 2019 20:36:47 +0200 Subject: [PATCH 1/3] format_error should return locations as a list of {"line", "column"} --- src/graphql/error/format_error.py | 6 +++++- tests/error/test_format_error.py | 5 +++-- tests/execution/test_abstract.py | 4 ++-- tests/execution/test_abstract_async.py | 8 ++++---- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/graphql/error/format_error.py b/src/graphql/error/format_error.py index d813ad2f..db3da29c 100644 --- a/src/graphql/error/format_error.py +++ b/src/graphql/error/format_error.py @@ -17,7 +17,11 @@ def format_error(error: "GraphQLError") -> Dict[str, Any]: raise TypeError("Received no error object.") formatted: Dict[str, Any] = dict( # noqa: E701 (pycqa/flake8#394) message=error.message or "An unknown error occurred.", - locations=error.locations, + locations=( + [{"line": l.line, "column": l.column} for l in error.locations] + if error.locations is not None + else None + ), path=error.path, ) if error.extensions: diff --git a/tests/error/test_format_error.py b/tests/error/test_format_error.py index 7f98fcb7..beac8e61 100644 --- a/tests/error/test_format_error.py +++ b/tests/error/test_format_error.py @@ -30,9 +30,10 @@ def format_graphql_error(): ValueError("original"), extensions=extensions, ) - assert error == { + formatted = format_error(error) + assert formatted == { "message": "test message", - "locations": [(2, 14), (3, 20)], + "locations": [{"line": 2, "column": 14}, {"line": 3, "column": 20}], "path": path, "extensions": extensions, } diff --git a/tests/execution/test_abstract.py b/tests/execution/test_abstract.py index 9ed24ee4..3c4b8996 100644 --- a/tests/execution/test_abstract.py +++ b/tests/execution/test_abstract.py @@ -254,7 +254,7 @@ def resolve_type_on_interface_yields_useful_error(): assert format_error(result.errors[0]) == { "message": "Runtime Object type 'Human'" " is not a possible type for 'Pet'.", - "locations": [(3, 15)], + "locations": [{"line": 3, "column": 15}], "path": ["pets", 2], } @@ -330,7 +330,7 @@ def resolve_type_on_union_yields_useful_error(): assert format_error(result.errors[0]) == { "message": "Runtime Object type 'Human'" " is not a possible type for 'Pet'.", - "locations": [(3, 15)], + "locations": [{"line": 3, "column": 15}], "path": ["pets", 2], } diff --git a/tests/execution/test_abstract_async.py b/tests/execution/test_abstract_async.py index 456933cc..69a4578d 100644 --- a/tests/execution/test_abstract_async.py +++ b/tests/execution/test_abstract_async.py @@ -182,12 +182,12 @@ async def is_type_of_with_async_error(): assert list(map(format_error, result.errors)) == [ # type: ignore { "message": "We are testing this error", - "locations": [(3, 15)], + "locations": [{"line": 3, "column": 15}], "path": ["pets", 0], }, { "message": "We are testing this error", - "locations": [(3, 15)], + "locations": [{"line": 3, "column": 15}], "path": ["pets", 1], }, ] @@ -334,7 +334,7 @@ async def resolve_type_on_interface_yields_useful_error(): assert format_error(result.errors[0]) == { "message": "Runtime Object type 'Human'" " is not a possible type for 'Pet'.", - "locations": [(3, 15)], + "locations": [{"line": 3, "column": 15}], "path": ["pets", 2], } @@ -411,7 +411,7 @@ async def resolve_type_on_union_yields_useful_error(): assert format_error(result.errors[0]) == { "message": "Runtime Object type 'Human'" " is not a possible type for 'Pet'.", - "locations": [(3, 15)], + "locations": [{"line": 3, "column": 15}], "path": ["pets", 2], } From 837ee6620fb83a343b056bccd741d0c1c989033b Mon Sep 17 00:00:00 2001 From: Tomasz Kontusz Date: Mon, 23 Sep 2019 22:02:28 +0200 Subject: [PATCH 2/3] Move SourceLocation formatting to SourceLocation.formatted --- src/graphql/error/format_error.py | 2 +- src/graphql/language/location.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/graphql/error/format_error.py b/src/graphql/error/format_error.py index db3da29c..9b768cf5 100644 --- a/src/graphql/error/format_error.py +++ b/src/graphql/error/format_error.py @@ -18,7 +18,7 @@ def format_error(error: "GraphQLError") -> Dict[str, Any]: formatted: Dict[str, Any] = dict( # noqa: E701 (pycqa/flake8#394) message=error.message or "An unknown error occurred.", locations=( - [{"line": l.line, "column": l.column} for l in error.locations] + [location.formatted for location in error.locations] if error.locations is not None else None ), diff --git a/src/graphql/language/location.py b/src/graphql/language/location.py index d59c9c44..76438163 100644 --- a/src/graphql/language/location.py +++ b/src/graphql/language/location.py @@ -12,6 +12,10 @@ class SourceLocation(NamedTuple): line: int column: int + @property + def formatted(self): + return dict(line=self.line, column=self.column) + def get_location(source: "Source", position: int) -> SourceLocation: """Get the line and column for a character position in the source. From de0b14fbafdc6aacd27a73e21965ed63c015b771 Mon Sep 17 00:00:00 2001 From: Tomasz Kontusz Date: Mon, 23 Sep 2019 22:03:35 +0200 Subject: [PATCH 3/3] Add SourceLocation.__eq__ to make it comparable to the formatted form --- src/graphql/language/location.py | 8 ++++++++ tests/language/test_location.py | 12 ++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 tests/language/test_location.py diff --git a/src/graphql/language/location.py b/src/graphql/language/location.py index 76438163..a0334fee 100644 --- a/src/graphql/language/location.py +++ b/src/graphql/language/location.py @@ -16,6 +16,14 @@ class SourceLocation(NamedTuple): def formatted(self): return dict(line=self.line, column=self.column) + def __eq__(self, other): + if isinstance(other, dict): + return other == self.formatted + return super().__eq__(other) + + def __ne__(self, other): + return not self == other + def get_location(source: "Source", position: int) -> SourceLocation: """Get the line and column for a character position in the source. diff --git a/tests/language/test_location.py b/tests/language/test_location.py new file mode 100644 index 00000000..0fd85a44 --- /dev/null +++ b/tests/language/test_location.py @@ -0,0 +1,12 @@ +from graphql import SourceLocation + + +def describe_SourceLocation(): + def equals_with_itself(): + assert SourceLocation(1, 2) == SourceLocation(1, 2) + assert (SourceLocation(1, 2) != SourceLocation(1, 2)) is False + + def equals_with_formatted_form(): + sl = SourceLocation(1, 2) + assert SourceLocation(1, 2) == sl.formatted + assert (SourceLocation(1, 2) != sl.formatted) is False