diff --git a/.travis.yml b/.travis.yml index 1179422f..72e752a6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,7 +26,6 @@ install: - pip install pytest==2.9.2 - pip install -e . script: -- flake8 - py.test --cov=graphql graphql tests after_success: - coveralls @@ -36,8 +35,10 @@ matrix: after_install: - pip install pytest-asyncio script: - - flake8 - py.test --cov=graphql graphql tests tests_py35 + - python: '2.7' + script: + - flake8 deploy: provider: pypi user: syrusakbary diff --git a/graphql/error/base.py b/graphql/error/base.py index ccc75e24..44126cdd 100644 --- a/graphql/error/base.py +++ b/graphql/error/base.py @@ -1,3 +1,4 @@ +import six from ..language.location import get_location @@ -29,6 +30,12 @@ def positions(self): if any(node_positions): return node_positions + def reraise(self): + if self.stack: + six.reraise(type(self), self, self.stack) + else: + raise self + @property def locations(self): source = self.source diff --git a/graphql/error/tests/__init__.py b/graphql/error/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/graphql/error/tests/test_base.py b/graphql/error/tests/test_base.py new file mode 100644 index 00000000..0a070e2c --- /dev/null +++ b/graphql/error/tests/test_base.py @@ -0,0 +1,50 @@ +import pytest +import traceback + +from graphql.execution import execute +from graphql.language.parser import parse +from graphql.type import (GraphQLField, GraphQLObjectType, GraphQLSchema, + GraphQLString) + + +def test_raise(): + ast = parse('query Example { a }') + + def resolver(context, *_): + raise Exception('Failed') + + Type = GraphQLObjectType('Type', { + 'a': GraphQLField(GraphQLString, resolver=resolver), + }) + + result = execute(GraphQLSchema(Type), ast) + assert str(result.errors[0]) == 'Failed' + + +def test_reraise(): + ast = parse('query Example { a }') + + def resolver(context, *_): + raise Exception('Failed') + + Type = GraphQLObjectType('Type', { + 'a': GraphQLField(GraphQLString, resolver=resolver), + }) + + result = execute(GraphQLSchema(Type), ast) + with pytest.raises(Exception) as exc_info: + result.errors[0].reraise() + + extracted = traceback.extract_tb(exc_info.tb) + formatted_tb = [row[2:] for row in extracted] + if formatted_tb[2][0] == 'reraise': + formatted_tb[2:] = formatted_tb[3:] + + assert formatted_tb == [ + ('test_reraise', 'result.errors[0].reraise()'), + ('reraise', 'six.reraise(type(self), self, self.stack)'), + # ('reraise', 'raise value.with_traceback(tb)'), + ('resolve_or_error', 'return executor.execute(resolve_fn, source, args, context, info)'), + ('execute', 'return fn(*args, **kwargs)'), ('resolver', "raise Exception('Failed')") + ] + assert str(exc_info.value) == 'Failed' diff --git a/graphql/language/lexer.py b/graphql/language/lexer.py index 4eae3c2a..711525ef 100644 --- a/graphql/language/lexer.py +++ b/graphql/language/lexer.py @@ -183,6 +183,7 @@ def read_token(source, from_position): source, position, u'Unexpected character {}.'.format(print_char_code(code))) + ignored_whitespace_characters = frozenset([ # BOM 0xFEFF, diff --git a/graphql/type/directives.py b/graphql/type/directives.py index a09cad89..06c920de 100644 --- a/graphql/type/directives.py +++ b/graphql/type/directives.py @@ -68,6 +68,7 @@ def __init__(self, name, description=None, args=None, locations=None): _arg.type) self.args = args or OrderedDict() + """Used to conditionally include fields or fragments.""" GraphQLIncludeDirective = GraphQLDirective( name='include',