From 9777184721d390fc52e2f027b28f73df50f9b48b Mon Sep 17 00:00:00 2001 From: Daniel Gallagher Date: Tue, 22 May 2018 10:56:58 -0700 Subject: [PATCH 01/45] Add pre-commit tool to repository, and run on all files --- .pre-commit-config.yaml | 17 +++++++ UPGRADE-v2.0.md | 2 +- examples/complex_example.py | 2 +- graphene/pyutils/enum.py | 22 ++++++++++ graphene/pyutils/signature.py | 44 +++++++++---------- graphene/relay/tests/test_node_custom.py | 1 + graphene/types/tests/test_base.py | 2 +- graphene/types/tests/test_datetime.py | 10 +++-- graphene/types/tests/test_json.py | 1 + graphene/types/tests/test_uuid.py | 1 + graphene/utils/tests/test_annotate.py | 5 +++ graphene/utils/tests/test_deprecated.py | 12 ++--- .../utils/tests/test_resolve_only_args.py | 1 + tox.ini | 11 ++++- 14 files changed, 96 insertions(+), 35 deletions(-) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..b6bb6ee3 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,17 @@ +- repo: git://github.com/pre-commit/pre-commit-hooks + sha: v0.8.0 + hooks: + - id: autopep8-wrapper + args: + - -i + - --ignore=E128,E309,E501 + exclude: ^docs/.*$ + - id: check-json + - id: check-yaml + - id: debug-statements + - id: end-of-file-fixer + exclude: ^docs/.*$ + - id: trailing-whitespace + - id: pretty-format-json + args: + - --autofix diff --git a/UPGRADE-v2.0.md b/UPGRADE-v2.0.md index 8ef09343..48432b02 100644 --- a/UPGRADE-v2.0.md +++ b/UPGRADE-v2.0.md @@ -278,7 +278,7 @@ Now you can create abstact types super easily, without the need of subclassing t class Base(ObjectType): class Meta: abstract = True - + id = ID() def resolve_id(self, info): diff --git a/examples/complex_example.py b/examples/complex_example.py index f9c8dbc4..c9a4bb75 100644 --- a/examples/complex_example.py +++ b/examples/complex_example.py @@ -22,7 +22,7 @@ class Query(graphene.ObjectType): class CreateAddress(graphene.Mutation): - + class Arguments: geo = GeoInput(required=True) diff --git a/graphene/pyutils/enum.py b/graphene/pyutils/enum.py index 928d0be2..076b6a9d 100644 --- a/graphene/pyutils/enum.py +++ b/graphene/pyutils/enum.py @@ -662,6 +662,8 @@ def __new__(cls, value): if member.value == value: return member raise ValueError("%s is not a valid %s" % (value, cls.__name__)) + + temp_enum_dict['__new__'] = __new__ del __new__ @@ -669,12 +671,16 @@ del __new__ def __repr__(self): return "<%s.%s: %r>" % ( self.__class__.__name__, self._name_, self._value_) + + temp_enum_dict['__repr__'] = __repr__ del __repr__ def __str__(self): return "%s.%s" % (self.__class__.__name__, self._name_) + + temp_enum_dict['__str__'] = __str__ del __str__ @@ -705,6 +711,8 @@ def __format__(self, format_spec): cls = self._member_type_ val = self.value return cls.__format__(val, format_spec) + + temp_enum_dict['__format__'] = __format__ del __format__ @@ -751,6 +759,8 @@ def __eq__(self, other): if isinstance(other, self.__class__): return self is other return NotImplemented + + temp_enum_dict['__eq__'] = __eq__ del __eq__ @@ -759,18 +769,24 @@ def __ne__(self, other): if isinstance(other, self.__class__): return self is not other return NotImplemented + + temp_enum_dict['__ne__'] = __ne__ del __ne__ def __hash__(self): return hash(self._name_) + + temp_enum_dict['__hash__'] = __hash__ del __hash__ def __reduce_ex__(self, proto): return self.__class__, (self._value_, ) + + temp_enum_dict['__reduce_ex__'] = __reduce_ex__ del __reduce_ex__ @@ -785,6 +801,8 @@ del __reduce_ex__ @_RouteClassAttributeToGetattr def name(self): return self._name_ + + temp_enum_dict['name'] = name del name @@ -792,6 +810,8 @@ del name @_RouteClassAttributeToGetattr def value(self): return self._value_ + + temp_enum_dict['value'] = value del value @@ -817,6 +837,8 @@ def _convert(cls, name, module, filter, source=None): module_globals.update(cls.__members__) module_globals[name] = cls return cls + + temp_enum_dict['_convert'] = _convert del _convert diff --git a/graphene/pyutils/signature.py b/graphene/pyutils/signature.py index 1308ded9..9d94a6ef 100644 --- a/graphene/pyutils/signature.py +++ b/graphene/pyutils/signature.py @@ -28,7 +28,7 @@ def formatannotation(annotation, base_module=None): if isinstance(annotation, type): if annotation.__module__ in ('builtins', '__builtin__', base_module): return annotation.__name__ - return annotation.__module__+'.'+annotation.__name__ + return annotation.__module__ + '.' + annotation.__name__ return repr(annotation) @@ -126,7 +126,7 @@ def signature(obj): _partial_kwarg=True) elif (param.kind not in (_VAR_KEYWORD, _VAR_POSITIONAL) and - not param._partial_kwarg): + not param._partial_kwarg): new_params.pop(arg_name) return sig.replace(parameters=new_params.values()) @@ -193,11 +193,11 @@ class _ParameterKind(int): return '<_ParameterKind: {0!r}>'.format(self._name) -_POSITIONAL_ONLY = _ParameterKind(0, name='POSITIONAL_ONLY') -_POSITIONAL_OR_KEYWORD = _ParameterKind(1, name='POSITIONAL_OR_KEYWORD') -_VAR_POSITIONAL = _ParameterKind(2, name='VAR_POSITIONAL') -_KEYWORD_ONLY = _ParameterKind(3, name='KEYWORD_ONLY') -_VAR_KEYWORD = _ParameterKind(4, name='VAR_KEYWORD') +_POSITIONAL_ONLY = _ParameterKind(0, name='POSITIONAL_ONLY') +_POSITIONAL_OR_KEYWORD = _ParameterKind(1, name='POSITIONAL_OR_KEYWORD') +_VAR_POSITIONAL = _ParameterKind(2, name='VAR_POSITIONAL') +_KEYWORD_ONLY = _ParameterKind(3, name='KEYWORD_ONLY') +_VAR_KEYWORD = _ParameterKind(4, name='VAR_KEYWORD') class Parameter(object): @@ -220,11 +220,11 @@ class Parameter(object): __slots__ = ('_name', '_kind', '_default', '_annotation', '_partial_kwarg') - POSITIONAL_ONLY = _POSITIONAL_ONLY - POSITIONAL_OR_KEYWORD = _POSITIONAL_OR_KEYWORD - VAR_POSITIONAL = _VAR_POSITIONAL - KEYWORD_ONLY = _KEYWORD_ONLY - VAR_KEYWORD = _VAR_KEYWORD + POSITIONAL_ONLY = _POSITIONAL_ONLY + POSITIONAL_OR_KEYWORD = _POSITIONAL_OR_KEYWORD + VAR_POSITIONAL = _VAR_POSITIONAL + KEYWORD_ONLY = _KEYWORD_ONLY + VAR_KEYWORD = _VAR_KEYWORD empty = _empty @@ -366,7 +366,7 @@ class BoundArguments(object): args = [] for param_name, param in self._signature.parameters.items(): if (param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY) or - param._partial_kwarg): + param._partial_kwarg): # Keyword arguments mapped by 'functools.partial' # (Parameter._partial_kwarg is True) are mapped # in 'BoundArguments.kwargs', along with VAR_KEYWORD & @@ -396,7 +396,7 @@ class BoundArguments(object): for param_name, param in self._signature.parameters.items(): if not kwargs_started: if (param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY) or - param._partial_kwarg): + param._partial_kwarg): kwargs_started = True else: if param_name not in self.arguments: @@ -494,7 +494,7 @@ class Signature(object): params[name] = param else: params = OrderedDict(((param.name, param) - for param in parameters)) + for param in parameters)) self._parameters = params self._return_annotation = return_annotation @@ -604,8 +604,8 @@ class Signature(object): def __eq__(self, other): if (not issubclass(type(other), Signature) or - self.return_annotation != other.return_annotation or - len(self.parameters) != len(other.parameters)): + self.return_annotation != other.return_annotation or + len(self.parameters) != len(other.parameters)): return False other_positions = dict((param, idx) @@ -627,7 +627,7 @@ class Signature(object): return False else: if (idx != other_idx or - param != other.parameters[param_name]): + param != other.parameters[param_name]): return False return True @@ -680,7 +680,7 @@ class Signature(object): parameters_ex = (param,) break elif (param.kind == _VAR_KEYWORD or - param.default is not _empty): + param.default is not _empty): # That's fine too - we have a default value for this # parameter. So, lets start parsing `kwargs`, starting # with the current parameter @@ -730,7 +730,7 @@ class Signature(object): # Signature object (but let's have this check here # to ensure correct behaviour just in case) raise TypeError('{arg!r} parameter is positional only, ' - 'but was passed as a keyword'. \ + 'but was passed as a keyword'. format(arg=param.name)) if param.kind == _VAR_KEYWORD: @@ -747,8 +747,8 @@ class Signature(object): # parameter, left alone by the processing of positional # arguments. if (not partial and param.kind != _VAR_POSITIONAL and - param.default is _empty): - raise TypeError('{arg!r} parameter lacking default value'. \ + param.default is _empty): + raise TypeError('{arg!r} parameter lacking default value'. format(arg=param_name)) else: diff --git a/graphene/relay/tests/test_node_custom.py b/graphene/relay/tests/test_node_custom.py index cc4e910c..80124c0d 100644 --- a/graphene/relay/tests/test_node_custom.py +++ b/graphene/relay/tests/test_node_custom.py @@ -54,6 +54,7 @@ photo_data = { class RootQuery(ObjectType): node = CustomNode.Field() + schema = Schema(query=RootQuery, types=[User, Photo]) diff --git a/graphene/types/tests/test_base.py b/graphene/types/tests/test_base.py index 2ea3dcce..18ba6774 100644 --- a/graphene/types/tests/test_base.py +++ b/graphene/types/tests/test_base.py @@ -17,7 +17,7 @@ class CustomType(BaseType): def test_basetype(): class MyBaseType(CustomType): pass - + assert isinstance(MyBaseType._meta, CustomOptions) assert MyBaseType._meta.name == "MyBaseType" assert MyBaseType._meta.description is None diff --git a/graphene/types/tests/test_datetime.py b/graphene/types/tests/test_datetime.py index b516e497..2d79d9f7 100644 --- a/graphene/types/tests/test_datetime.py +++ b/graphene/types/tests/test_datetime.py @@ -55,24 +55,27 @@ def test_time_query(): assert not result.errors assert result.data == {'time': isoformat} + def test_bad_datetime_query(): not_a_date = "Some string that's not a date" result = schema.execute('''{ datetime(in: "%s") }''' % not_a_date) - + assert len(result.errors) == 1 assert isinstance(result.errors[0], GraphQLError) assert result.data == None + def test_bad_date_query(): not_a_date = "Some string that's not a date" - + result = schema.execute('''{ date(in: "%s") }''' % not_a_date) - + assert len(result.errors) == 1 assert isinstance(result.errors[0], GraphQLError) assert result.data == None + def test_bad_time_query(): not_a_date = "Some string that's not a date" @@ -82,6 +85,7 @@ def test_bad_time_query(): assert isinstance(result.errors[0], GraphQLError) assert result.data == None + def test_datetime_query_variable(): now = datetime.datetime.now().replace(tzinfo=pytz.utc) isoformat = now.isoformat() diff --git a/graphene/types/tests/test_json.py b/graphene/types/tests/test_json.py index cadc729f..c33bd696 100644 --- a/graphene/types/tests/test_json.py +++ b/graphene/types/tests/test_json.py @@ -10,6 +10,7 @@ class Query(ObjectType): def resolve_json(self, info, input): return input + schema = Schema(query=Query) diff --git a/graphene/types/tests/test_uuid.py b/graphene/types/tests/test_uuid.py index c1419750..f1499e35 100644 --- a/graphene/types/tests/test_uuid.py +++ b/graphene/types/tests/test_uuid.py @@ -9,6 +9,7 @@ class Query(ObjectType): def resolve_uuid(self, info, input): return input + schema = Schema(query=Query) diff --git a/graphene/utils/tests/test_annotate.py b/graphene/utils/tests/test_annotate.py index 760a8bf5..e4930b62 100644 --- a/graphene/utils/tests/test_annotate.py +++ b/graphene/utils/tests/test_annotate.py @@ -1,9 +1,11 @@ import pytest from ..annotate import annotate + def func(a, b, *c, **d): pass + annotations = { 'a': int, 'b': str, @@ -11,8 +13,11 @@ annotations = { 'd': dict } + def func_with_annotations(a, b, *c, **d): pass + + func_with_annotations.__annotations__ = annotations diff --git a/graphene/utils/tests/test_deprecated.py b/graphene/utils/tests/test_deprecated.py index d196744f..cd0e2dcb 100644 --- a/graphene/utils/tests/test_deprecated.py +++ b/graphene/utils/tests/test_deprecated.py @@ -5,14 +5,14 @@ from ..deprecated import deprecated as deprecated_decorator, warn_deprecation def test_warn_deprecation(mocker): mocker.patch.object(deprecated.warnings, 'warn') - + warn_deprecation("OH!") deprecated.warnings.warn.assert_called_with('OH!', stacklevel=2, category=DeprecationWarning) def test_deprecated_decorator(mocker): mocker.patch.object(deprecated, 'warn_deprecation') - + @deprecated_decorator def my_func(): return True @@ -24,7 +24,7 @@ def test_deprecated_decorator(mocker): def test_deprecated_class(mocker): mocker.patch.object(deprecated, 'warn_deprecation') - + @deprecated_decorator class X: pass @@ -36,7 +36,7 @@ def test_deprecated_class(mocker): def test_deprecated_decorator_text(mocker): mocker.patch.object(deprecated, 'warn_deprecation') - + @deprecated_decorator("Deprecation text") def my_func(): return True @@ -48,7 +48,7 @@ def test_deprecated_decorator_text(mocker): def test_deprecated_class_text(mocker): mocker.patch.object(deprecated, 'warn_deprecation') - + @deprecated_decorator("Deprecation text") class X: pass @@ -60,6 +60,6 @@ def test_deprecated_class_text(mocker): def test_deprecated_other_object(mocker): mocker.patch.object(deprecated, 'warn_deprecation') - + with pytest.raises(TypeError) as exc_info: deprecated_decorator({}) diff --git a/graphene/utils/tests/test_resolve_only_args.py b/graphene/utils/tests/test_resolve_only_args.py index f5b77de1..35554e9b 100644 --- a/graphene/utils/tests/test_resolve_only_args.py +++ b/graphene/utils/tests/test_resolve_only_args.py @@ -4,6 +4,7 @@ from .. import deprecated def test_resolve_only_args(mocker): mocker.patch.object(deprecated, 'warn_deprecation') + def resolver(root, **args): return root, args diff --git a/tox.ini b/tox.ini index f2eccefb..849f581c 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = flake8,py27,py33,py34,py35,py36,pypy +envlist = flake8,py27,py33,py34,py35,py36,pre-commit,pypy skipsdist = true [testenv] @@ -20,6 +20,15 @@ setenv = commands= py.test +[testenv:pre-commit] +basepython=python3.6 +deps = + pre-commit>0.12.0 +setenv = + LC_CTYPE=en_US.UTF-8 +commands = + pre-commit {posargs:run --all-files} + [testenv:flake8] deps = flake8 commands = From 5d084cf2eaab63c2310ac863c622ba2500a72ea7 Mon Sep 17 00:00:00 2001 From: Felipe Mesquita Date: Wed, 23 May 2018 20:13:03 -0300 Subject: [PATCH 02/45] Update UPGRADE-v2.0.md Migration docs improvement --- UPGRADE-v2.0.md | 73 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/UPGRADE-v2.0.md b/UPGRADE-v2.0.md index 8ef09343..715baa66 100644 --- a/UPGRADE-v2.0.md +++ b/UPGRADE-v2.0.md @@ -122,6 +122,13 @@ def resolve_my_field(self, info, my_arg): return ... ``` +**PS.: Take care with receiving args like `my_arg` as above. This doesn't work for optional (non-required) arguments as stantard `Connection`'s arguments (first, before, after, before).** +You may need something like this: + +```python +def resolve_my_field(self, info, known_field1, known_field2, **args): ## get other args with: args.get('arg_key') +``` + And, if you need the context in the resolver, you can use `info.context`: ```python @@ -193,7 +200,42 @@ class MyObject(ObjectType): ## Mutation.mutate -Now only receives (`root`, `info`, `**args`) +Now only receives (`self`, `info`, `**args`) and if not a @classmethod + +Before: + +```python +class SomeMutation(Mutation): + ... + + @classmethod + def mutate(cls, instance, args, context, info): + ... +``` + +With 2.0: + +```python +class SomeMutation(Mutation): + ... + + def mutate(self, info, **args): + ... +``` + +With 2.0 you can also get your declared (as above) `args` this way: + +```python +class SomeMutation(Mutation): + class Arguments: + first_name = String(required=True) + last_name = String(required=True) + ... + + def mutate(self, info, first_name, last_name): + ... +``` + ## ClientIDMutation.mutate_and_get_payload @@ -201,6 +243,35 @@ Now only receives (`root`, `info`, `**args`) Now only receives (`root`, `info`, `**input`) +### Middlewares + +If you are using Middelwares, you need to some adjustments: + +Before: + +```python +class MyGrapheneMiddleware(object): + def resolve(self, next_mw, root, args, context, info): + + ## Middleware code + + return next_mw(root, args, context, info) +``` + +With 2.0: + +```python +class MyGrapheneMiddleware(object): + def resolve(self, next_mw, root, info, **args): + context = info.context + + ## Middleware code + + info.context = context +        return next_mw(root, info, **args)``` +``` + + ## New Features ### InputObjectType From ead24a94c2acb6ee5cc19abd86500a75f1576960 Mon Sep 17 00:00:00 2001 From: Felipe Mesquita Date: Wed, 23 May 2018 20:20:55 -0300 Subject: [PATCH 03/45] Update UPGRADE-v2.0.md type correction --- UPGRADE-v2.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UPGRADE-v2.0.md b/UPGRADE-v2.0.md index 715baa66..57b94630 100644 --- a/UPGRADE-v2.0.md +++ b/UPGRADE-v2.0.md @@ -200,7 +200,7 @@ class MyObject(ObjectType): ## Mutation.mutate -Now only receives (`self`, `info`, `**args`) and if not a @classmethod +Now only receives (`self`, `info`, `**args`) and is not a @classmethod Before: From 013c9e5077481eeb7d6c5d41bf5e78081fd7e047 Mon Sep 17 00:00:00 2001 From: Daniel Gallagher Date: Thu, 24 May 2018 23:33:32 -0700 Subject: [PATCH 04/45] Update .travis.yml file to use tox as script for running tests --- .travis.yml | 75 ++++++++++++----------------------------------------- 1 file changed, 17 insertions(+), 58 deletions(-) diff --git a/.travis.yml b/.travis.yml index a1357c91..b24ba5c4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,64 +1,23 @@ language: python -sudo: false -python: -- 2.7 -- 3.5 -- 3.6 -# - "pypy-5.3.1" -before_install: -- | - if [ "$TRAVIS_PYTHON_VERSION" = "pypy" ]; then - export PYENV_ROOT="$HOME/.pyenv" - if [ -f "$PYENV_ROOT/bin/pyenv" ]; then - cd "$PYENV_ROOT" && git pull - else - rm -rf "$PYENV_ROOT" && git clone --depth 1 https://github.com/yyuu/pyenv.git "$PYENV_ROOT" - fi - export PYPY_VERSION="4.0.1" - "$PYENV_ROOT/bin/pyenv" install "pypy-$PYPY_VERSION" - virtualenv --python="$PYENV_ROOT/versions/pypy-$PYPY_VERSION/bin/python" "$HOME/virtualenvs/pypy-$PYPY_VERSION" - source "$HOME/virtualenvs/pypy-$PYPY_VERSION/bin/activate" - fi -install: -- | - if [ "$TEST_TYPE" = build ]; then - pip install -e .[test] - python setup.py develop - elif [ "$TEST_TYPE" = lint ]; then - pip install flake8 - elif [ "$TEST_TYPE" = mypy ]; then - pip install mypy - fi -script: -- | - if [ "$TEST_TYPE" = lint ]; then - echo "Checking Python code lint." - flake8 graphene - exit - elif [ "$TEST_TYPE" = mypy ]; then - echo "Checking Python types." - mypy graphene - exit - elif [ "$TEST_TYPE" = build ]; then - py.test --cov=graphene graphene examples - fi -after_success: -- | - if [ "$TEST_TYPE" = build ]; then - coveralls - fi -env: - matrix: - - TEST_TYPE=build +python: 3.6 +env: # These should match the tox env list. + - TOXENV=flake8 + - TOXENV=py27 + - TOXENV=py33 + - TOXENV=py34 + - TOXENV=py35 + - TOXENV=py36 + - TOXENV=pypy + - TOXENV=pre-commit global: secure: SQC0eCWCWw8bZxbLE8vQn+UjJOp3Z1m779s9SMK3lCLwJxro/VCLBZ7hj4xsrq1MtcFO2U2Kqf068symw4Hr/0amYI3HFTCFiwXAC3PAKXeURca03eNO2heku+FtnQcOjBanExTsIBQRLDXMOaUkf3MIztpLJ4LHqMfUupKmw9YSB0v40jDbSN8khBnndFykmOnVVHznFp8USoN5F0CiPpnfEvHnJkaX76lNf7Kc9XNShBTTtJsnsHMhuYQeInt0vg9HSjoIYC38Tv2hmMj1myNdzyrHF+LgRjI6ceGi50ApAnGepXC/DNRhXROfECKez+LON/ZSqBGdJhUILqC8A4WmWmIjNcwitVFp3JGBqO7LULS0BI96EtSLe8rD1rkkdTbjivajkbykM1Q0Tnmg1adzGwLxRUbTq9tJQlTTkHBCuXIkpKb1mAtb/TY7A6BqfnPi2xTc/++qEawUG7ePhscdTj0IBrUfZsUNUYZqD8E8XbSWKIuS3SHE+cZ+s/kdAsm4q+FFAlpZKOYGxIkwvgyfu4/Plfol4b7X6iAP9J3r1Kv0DgBVFst5CXEwzZs19/g0CgokQbCXf1N+xeNnUELl6/fImaR3RKP22EaABoil4z8vzl4EqxqVoH1nfhE+WlpryXsuSaF/1R+WklR7aQ1FwoCk8V8HxM2zrj4tI8k= -matrix: - fast_finish: true - include: - - python: '2.7' - env: TEST_TYPE=lint - - python: '3.6' - env: TEST_TYPE=mypy +install: pip install coveralls tox flake8 mypy +script: tox +after_success: coveralls +cache: + directories: + - $HOME/.cache/pip + - $HOME/.cache/pre-commit deploy: provider: pypi user: syrusakbary From 034765aebec33cd26d682cf38d8c428a642018e1 Mon Sep 17 00:00:00 2001 From: Nikordaris Date: Fri, 25 May 2018 09:20:22 -0600 Subject: [PATCH 05/45] Added partial support to Dynamic type (#725) --- graphene/types/dynamic.py | 3 ++- graphene/types/tests/test_dynamic.py | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/graphene/types/dynamic.py b/graphene/types/dynamic.py index 6c4092f0..0efbd081 100644 --- a/graphene/types/dynamic.py +++ b/graphene/types/dynamic.py @@ -1,4 +1,5 @@ import inspect +from functools import partial from .mountedtype import MountedType @@ -11,7 +12,7 @@ class Dynamic(MountedType): def __init__(self, type, with_schema=False, _creation_counter=None): super(Dynamic, self).__init__(_creation_counter=_creation_counter) - assert inspect.isfunction(type) + assert inspect.isfunction(type) or isinstance(type, partial) self.type = type self.with_schema = with_schema diff --git a/graphene/types/tests/test_dynamic.py b/graphene/types/tests/test_dynamic.py index 4e72395f..b31ccf4b 100644 --- a/graphene/types/tests/test_dynamic.py +++ b/graphene/types/tests/test_dynamic.py @@ -1,3 +1,4 @@ +from functools import partial from ..dynamic import Dynamic from ..scalars import String from ..structures import List, NonNull @@ -25,3 +26,11 @@ def test_list_non_null(): dynamic = Dynamic(lambda: List(NonNull(String))) assert dynamic.get_type().of_type.of_type == String assert str(dynamic.get_type()) == '[String!]' + + +def test_partial(): + def __type(_type): + return _type + dynamic = Dynamic(partial(__type, String)) + assert dynamic.get_type() == String + assert str(dynamic.get_type()) == 'String' From ec9526d0cdf7d1d3e5df9ef601849fc982805838 Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Fri, 25 May 2018 17:17:20 +0100 Subject: [PATCH 06/45] Updated version to 2.1.1 --- graphene/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphene/__init__.py b/graphene/__init__.py index 57e6b0ec..ff7f9df7 100644 --- a/graphene/__init__.py +++ b/graphene/__init__.py @@ -35,7 +35,7 @@ from .utils.resolve_only_args import resolve_only_args from .utils.module_loading import lazy_import -VERSION = (2, 1, 0, 'final', 0) +VERSION = (2, 1, 1, 'final', 0) __version__ = get_version(VERSION) From 034b5385a5bcdaaf66c5902e9c634480ab306a41 Mon Sep 17 00:00:00 2001 From: Dan <3498629+dan98765@users.noreply.github.com> Date: Mon, 28 May 2018 11:18:54 -0700 Subject: [PATCH 07/45] Add isort precommit hook & run on all files (#743) * Add isort and seed-isort-config pre-commit hook * Fix erroneous isort moving comment to the top of file --- .editorconfig | 1 - .isort.cfg | 2 ++ .pre-commit-config.yaml | 11 ++++++++++- UPGRADE-v2.0.md | 10 +++++----- docs/conf.py | 2 +- docs/execution/dataloader.rst | 2 +- docs/relay/mutations.rst | 2 +- docs/testing/index.rst | 2 +- examples/starwars/tests/snapshots/snap_test_query.py | 1 - .../tests/snapshots/snap_test_connections.py | 1 - .../tests/snapshots/snap_test_mutation.py | 1 - .../tests/snapshots/snap_test_objectidentification.py | 1 - graphene/pyutils/compat.py | 1 + graphene/pyutils/signature.py | 4 ++-- graphene/relay/tests/test_connection.py | 3 ++- graphene/relay/tests/test_mutation.py | 1 - graphene/tests/issues/test_425.py | 5 +++-- graphene/types/abstracttype.py | 2 +- graphene/types/datetime.py | 2 +- graphene/types/enum.py | 3 +-- graphene/types/generic.py | 3 ++- graphene/types/mutation.py | 3 +-- graphene/types/scalars.py | 1 - graphene/types/schema.py | 2 +- graphene/types/tests/test_abstracttype.py | 6 +++--- graphene/types/tests/test_base.py | 2 +- graphene/types/tests/test_datetime.py | 3 +-- graphene/types/tests/test_dynamic.py | 1 + graphene/types/tests/test_enum.py | 2 +- graphene/types/tests/test_inputobjecttype.py | 4 ++-- graphene/types/tests/test_objecttype.py | 4 ++-- graphene/types/tests/test_query.py | 6 +++--- graphene/types/tests/test_typemap.py | 5 ++--- graphene/types/tests/test_uuid.py | 2 +- graphene/types/union.py | 1 - graphene/utils/annotate.py | 2 +- graphene/utils/resolve_only_args.py | 1 + graphene/utils/subclass_with_meta.py | 3 ++- graphene/utils/tests/test_annotate.py | 1 + graphene/utils/tests/test_deprecated.py | 4 +++- graphene/utils/tests/test_resolve_only_args.py | 2 +- setup.py | 7 ++++--- 42 files changed, 66 insertions(+), 56 deletions(-) create mode 100644 .isort.cfg diff --git a/.editorconfig b/.editorconfig index 5ebeb47b..568b3971 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,4 +11,3 @@ trim_trailing_whitespace = true [*.{py,rst,ini}] indent_style = space indent_size = 4 - diff --git a/.isort.cfg b/.isort.cfg new file mode 100644 index 00000000..d4ed37be --- /dev/null +++ b/.isort.cfg @@ -0,0 +1,2 @@ +[settings] +known_third_party = aniso8601,graphql,graphql_relay,promise,pytest,pytz,pyutils,setuptools,six,snapshottest,sphinx_graphene_theme diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b6bb6ee3..085f7fa9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,5 +1,6 @@ +repos: - repo: git://github.com/pre-commit/pre-commit-hooks - sha: v0.8.0 + rev: v1.2.3 hooks: - id: autopep8-wrapper args: @@ -15,3 +16,11 @@ - id: pretty-format-json args: - --autofix +- repo: https://github.com/asottile/seed-isort-config + rev: v1.0.0 + hooks: + - id: seed-isort-config +- repo: https://github.com/pre-commit/mirrors-isort + rev: v4.3.4 + hooks: + - id: isort diff --git a/UPGRADE-v2.0.md b/UPGRADE-v2.0.md index 96aac143..5dc76154 100644 --- a/UPGRADE-v2.0.md +++ b/UPGRADE-v2.0.md @@ -207,7 +207,7 @@ Before: ```python class SomeMutation(Mutation): ... - + @classmethod def mutate(cls, instance, args, context, info): ... @@ -218,7 +218,7 @@ With 2.0: ```python class SomeMutation(Mutation): ... - + def mutate(self, info, **args): ... ``` @@ -231,7 +231,7 @@ class SomeMutation(Mutation): first_name = String(required=True) last_name = String(required=True) ... - + def mutate(self, info, first_name, last_name): ... ``` @@ -250,7 +250,7 @@ If you are using Middelwares, you need to some adjustments: Before: ```python -class MyGrapheneMiddleware(object): +class MyGrapheneMiddleware(object): def resolve(self, next_mw, root, args, context, info): ## Middleware code @@ -261,7 +261,7 @@ class MyGrapheneMiddleware(object): With 2.0: ```python -class MyGrapheneMiddleware(object): +class MyGrapheneMiddleware(object): def resolve(self, next_mw, root, info, **args): context = info.context diff --git a/docs/conf.py b/docs/conf.py index 9d902f9a..ccb5305d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,4 +1,5 @@ import os +import sphinx_graphene_theme on_rtd = os.environ.get('READTHEDOCS', None) == 'True' @@ -136,7 +137,6 @@ todo_include_todos = True # html_theme = 'alabaster' # if on_rtd: # html_theme = 'sphinx_rtd_theme' -import sphinx_graphene_theme html_theme = "sphinx_graphene_theme" diff --git a/docs/execution/dataloader.rst b/docs/execution/dataloader.rst index 3322acfd..522af161 100644 --- a/docs/execution/dataloader.rst +++ b/docs/execution/dataloader.rst @@ -88,7 +88,7 @@ Naively, if ``me``, ``bestFriend`` and ``friends`` each need to request the back there could be at most 13 database requests! -When using DataLoader, we could define the User type using our previous example with +When using DataLoader, we could define the User type using our previous example with leaner code and at most 4 database requests, and possibly fewer if there are cache hits. diff --git a/docs/relay/mutations.rst b/docs/relay/mutations.rst index d273c137..c6099594 100644 --- a/docs/relay/mutations.rst +++ b/docs/relay/mutations.rst @@ -41,7 +41,7 @@ Mutations can also accept files, that's how it will work with different integrat class Input: pass # nothing needed for uploading file - + # your return fields success = graphene.String() diff --git a/docs/testing/index.rst b/docs/testing/index.rst index 516f0e8d..0263a9aa 100644 --- a/docs/testing/index.rst +++ b/docs/testing/index.rst @@ -101,7 +101,7 @@ Here is a simple example on how our tests will look if we use ``pytest``: If we are using ``unittest``: .. code:: python - + from snapshottest import TestCase class APITestCase(TestCase): diff --git a/examples/starwars/tests/snapshots/snap_test_query.py b/examples/starwars/tests/snapshots/snap_test_query.py index 9314420b..51e7b37f 100644 --- a/examples/starwars/tests/snapshots/snap_test_query.py +++ b/examples/starwars/tests/snapshots/snap_test_query.py @@ -4,7 +4,6 @@ from __future__ import unicode_literals from snapshottest import Snapshot - snapshots = Snapshot() snapshots['test_hero_name_query 1'] = { diff --git a/examples/starwars_relay/tests/snapshots/snap_test_connections.py b/examples/starwars_relay/tests/snapshots/snap_test_connections.py index cbf14d95..d2dff773 100644 --- a/examples/starwars_relay/tests/snapshots/snap_test_connections.py +++ b/examples/starwars_relay/tests/snapshots/snap_test_connections.py @@ -4,7 +4,6 @@ from __future__ import unicode_literals from snapshottest import Snapshot - snapshots = Snapshot() snapshots['test_correct_fetch_first_ship_rebels 1'] = { diff --git a/examples/starwars_relay/tests/snapshots/snap_test_mutation.py b/examples/starwars_relay/tests/snapshots/snap_test_mutation.py index 27c3f9bb..8fff150b 100644 --- a/examples/starwars_relay/tests/snapshots/snap_test_mutation.py +++ b/examples/starwars_relay/tests/snapshots/snap_test_mutation.py @@ -4,7 +4,6 @@ from __future__ import unicode_literals from snapshottest import Snapshot - snapshots = Snapshot() snapshots['test_mutations 1'] = { diff --git a/examples/starwars_relay/tests/snapshots/snap_test_objectidentification.py b/examples/starwars_relay/tests/snapshots/snap_test_objectidentification.py index a15d49d3..1682f2de 100644 --- a/examples/starwars_relay/tests/snapshots/snap_test_objectidentification.py +++ b/examples/starwars_relay/tests/snapshots/snap_test_objectidentification.py @@ -4,7 +4,6 @@ from __future__ import unicode_literals from snapshottest import Snapshot - snapshots = Snapshot() snapshots['test_correctly_fetches_id_name_rebels 1'] = { diff --git a/graphene/pyutils/compat.py b/graphene/pyutils/compat.py index 86452081..ef27f356 100644 --- a/graphene/pyutils/compat.py +++ b/graphene/pyutils/compat.py @@ -1,4 +1,5 @@ from __future__ import absolute_import + import six try: diff --git a/graphene/pyutils/signature.py b/graphene/pyutils/signature.py index 9d94a6ef..5ad6346c 100644 --- a/graphene/pyutils/signature.py +++ b/graphene/pyutils/signature.py @@ -4,11 +4,11 @@ Back port of Python 3.3's function signature tools from the inspect module, modified to be compatible with Python 2.7 and 3.2+. """ from __future__ import absolute_import, division, print_function -import itertools + import functools +import itertools import re import types - from collections import OrderedDict __version__ = "0.4" diff --git a/graphene/relay/tests/test_connection.py b/graphene/relay/tests/test_connection.py index c206f714..28dd929f 100644 --- a/graphene/relay/tests/test_connection.py +++ b/graphene/relay/tests/test_connection.py @@ -1,6 +1,7 @@ import pytest -from ...types import Argument, Field, Int, List, NonNull, ObjectType, String, Schema +from ...types import (Argument, Field, Int, List, NonNull, ObjectType, Schema, + String) from ..connection import Connection, ConnectionField, PageInfo from ..node import Node diff --git a/graphene/relay/tests/test_mutation.py b/graphene/relay/tests/test_mutation.py index aa5ce179..a830ffbe 100644 --- a/graphene/relay/tests/test_mutation.py +++ b/graphene/relay/tests/test_mutation.py @@ -1,5 +1,4 @@ import pytest - from promise import Promise from ...types import (ID, Argument, Field, InputField, InputObjectType, diff --git a/graphene/tests/issues/test_425.py b/graphene/tests/issues/test_425.py index d50edf84..cc77e730 100644 --- a/graphene/tests/issues/test_425.py +++ b/graphene/tests/issues/test_425.py @@ -1,9 +1,10 @@ # https://github.com/graphql-python/graphene/issues/425 # Adapted for Graphene 2.0 -from graphene.types.objecttype import ObjectType, ObjectTypeOptions -from graphene.types.inputobjecttype import InputObjectType, InputObjectTypeOptions from graphene.types.enum import Enum, EnumOptions +from graphene.types.inputobjecttype import (InputObjectType, + InputObjectTypeOptions) +from graphene.types.objecttype import ObjectType, ObjectTypeOptions # ObjectType diff --git a/graphene/types/abstracttype.py b/graphene/types/abstracttype.py index aaa0ff37..9d84d819 100644 --- a/graphene/types/abstracttype.py +++ b/graphene/types/abstracttype.py @@ -1,5 +1,5 @@ -from ..utils.subclass_with_meta import SubclassWithMeta from ..utils.deprecated import warn_deprecation +from ..utils.subclass_with_meta import SubclassWithMeta class AbstractType(SubclassWithMeta): diff --git a/graphene/types/datetime.py b/graphene/types/datetime.py index b750ea01..bdf45f55 100644 --- a/graphene/types/datetime.py +++ b/graphene/types/datetime.py @@ -2,8 +2,8 @@ from __future__ import absolute_import import datetime +from aniso8601 import parse_date, parse_datetime, parse_time from graphql.language import ast -from aniso8601 import parse_datetime, parse_date, parse_time from .scalars import Scalar diff --git a/graphene/types/enum.py b/graphene/types/enum.py index 67a3f6b2..4f571214 100644 --- a/graphene/types/enum.py +++ b/graphene/types/enum.py @@ -4,11 +4,10 @@ import six from graphene.utils.subclass_with_meta import SubclassWithMeta_Meta +from ..pyutils.compat import Enum as PyEnum from .base import BaseOptions, BaseType from .unmountedtype import UnmountedType -from ..pyutils.compat import Enum as PyEnum - def eq_enum(self, other): if isinstance(other, self.__class__): diff --git a/graphene/types/generic.py b/graphene/types/generic.py index 3170e38d..b2b15f00 100644 --- a/graphene/types/generic.py +++ b/graphene/types/generic.py @@ -1,9 +1,10 @@ from __future__ import unicode_literals -from graphene.types.scalars import MAX_INT, MIN_INT from graphql.language.ast import (BooleanValue, FloatValue, IntValue, ListValue, ObjectValue, StringValue) +from graphene.types.scalars import MAX_INT, MIN_INT + from .scalars import Scalar diff --git a/graphene/types/mutation.py b/graphene/types/mutation.py index 6b864e07..fdfd5515 100644 --- a/graphene/types/mutation.py +++ b/graphene/types/mutation.py @@ -1,12 +1,11 @@ from collections import OrderedDict +from ..utils.deprecated import warn_deprecation from ..utils.get_unbound_function import get_unbound_function from ..utils.props import props from .field import Field from .objecttype import ObjectType, ObjectTypeOptions from .utils import yank_fields_from_attrs -from ..utils.deprecated import warn_deprecation - # For static type checking with Mypy MYPY = False diff --git a/graphene/types/scalars.py b/graphene/types/scalars.py index 3b78185d..e34d7a10 100644 --- a/graphene/types/scalars.py +++ b/graphene/types/scalars.py @@ -1,5 +1,4 @@ import six - from graphql.language.ast import (BooleanValue, FloatValue, IntValue, StringValue) diff --git a/graphene/types/schema.py b/graphene/types/schema.py index 7fd513b2..72bae81f 100644 --- a/graphene/types/schema.py +++ b/graphene/types/schema.py @@ -1,6 +1,6 @@ import inspect -from graphql import GraphQLSchema, graphql, is_type, GraphQLObjectType +from graphql import GraphQLObjectType, GraphQLSchema, graphql, is_type from graphql.type.directives import (GraphQLDirective, GraphQLIncludeDirective, GraphQLSkipDirective) from graphql.type.introspection import IntrospectionSchema diff --git a/graphene/types/tests/test_abstracttype.py b/graphene/types/tests/test_abstracttype.py index 6484deb8..73144bec 100644 --- a/graphene/types/tests/test_abstracttype.py +++ b/graphene/types/tests/test_abstracttype.py @@ -1,10 +1,10 @@ import pytest +from .. import abstracttype +from ..abstracttype import AbstractType +from ..field import Field from ..objecttype import ObjectType from ..unmountedtype import UnmountedType -from ..abstracttype import AbstractType -from .. import abstracttype -from ..field import Field class MyType(ObjectType): diff --git a/graphene/types/tests/test_base.py b/graphene/types/tests/test_base.py index 18ba6774..6399f69d 100644 --- a/graphene/types/tests/test_base.py +++ b/graphene/types/tests/test_base.py @@ -1,6 +1,6 @@ import pytest -from ..base import BaseType, BaseOptions +from ..base import BaseOptions, BaseType class CustomOptions(BaseOptions): diff --git a/graphene/types/tests/test_datetime.py b/graphene/types/tests/test_datetime.py index 2d79d9f7..80c1d3c1 100644 --- a/graphene/types/tests/test_datetime.py +++ b/graphene/types/tests/test_datetime.py @@ -1,10 +1,9 @@ import datetime import pytz - from graphql import GraphQLError -from ..datetime import DateTime, Date, Time +from ..datetime import Date, DateTime, Time from ..objecttype import ObjectType from ..schema import Schema diff --git a/graphene/types/tests/test_dynamic.py b/graphene/types/tests/test_dynamic.py index b31ccf4b..5e4dfca8 100644 --- a/graphene/types/tests/test_dynamic.py +++ b/graphene/types/tests/test_dynamic.py @@ -1,4 +1,5 @@ from functools import partial + from ..dynamic import Dynamic from ..scalars import String from ..structures import List, NonNull diff --git a/graphene/types/tests/test_enum.py b/graphene/types/tests/test_enum.py index fdd5f4e4..d35d555f 100644 --- a/graphene/types/tests/test_enum.py +++ b/graphene/types/tests/test_enum.py @@ -1,10 +1,10 @@ import six -from ..schema import Schema, ObjectType from ..argument import Argument from ..enum import Enum, PyEnum from ..field import Field from ..inputfield import InputField +from ..schema import ObjectType, Schema def test_enum_construction(): diff --git a/graphene/types/tests/test_inputobjecttype.py b/graphene/types/tests/test_inputobjecttype.py index 9f90055d..8d6ed904 100644 --- a/graphene/types/tests/test_inputobjecttype.py +++ b/graphene/types/tests/test_inputobjecttype.py @@ -4,9 +4,9 @@ from ..field import Field from ..inputfield import InputField from ..inputobjecttype import InputObjectType from ..objecttype import ObjectType -from ..unmountedtype import UnmountedType -from ..scalars import String, Boolean +from ..scalars import Boolean, String from ..schema import Schema +from ..unmountedtype import UnmountedType class MyType(object): diff --git a/graphene/types/tests/test_objecttype.py b/graphene/types/tests/test_objecttype.py index 73d3823c..766f62fe 100644 --- a/graphene/types/tests/test_objecttype.py +++ b/graphene/types/tests/test_objecttype.py @@ -3,10 +3,10 @@ import pytest from ..field import Field from ..interface import Interface from ..objecttype import ObjectType -from ..unmountedtype import UnmountedType -from ..structures import NonNull from ..scalars import String from ..schema import Schema +from ..structures import NonNull +from ..unmountedtype import UnmountedType class MyType(Interface): diff --git a/graphene/types/tests/test_query.py b/graphene/types/tests/test_query.py index a106af25..c4133970 100644 --- a/graphene/types/tests/test_query.py +++ b/graphene/types/tests/test_query.py @@ -1,19 +1,19 @@ import json from functools import partial -from graphql import GraphQLError, Source, execute, parse, ResolveInfo +from graphql import GraphQLError, ResolveInfo, Source, execute, parse +from ..context import Context from ..dynamic import Dynamic from ..field import Field from ..inputfield import InputField from ..inputobjecttype import InputObjectType from ..interface import Interface from ..objecttype import ObjectType -from ..scalars import Int, String, Boolean +from ..scalars import Boolean, Int, String from ..schema import Schema from ..structures import List, NonNull from ..union import Union -from ..context import Context def test_query(): diff --git a/graphene/types/tests/test_typemap.py b/graphene/types/tests/test_typemap.py index c0626a1a..94af960c 100644 --- a/graphene/types/tests/test_typemap.py +++ b/graphene/types/tests/test_typemap.py @@ -1,11 +1,9 @@ import pytest - from graphql.type import (GraphQLArgument, GraphQLEnumType, GraphQLEnumValue, GraphQLField, GraphQLInputObjectField, GraphQLInputObjectType, GraphQLInterfaceType, GraphQLObjectType, GraphQLString) -from ..structures import List, NonNull from ..dynamic import Dynamic from ..enum import Enum from ..field import Field @@ -13,7 +11,8 @@ from ..inputfield import InputField from ..inputobjecttype import InputObjectType from ..interface import Interface from ..objecttype import ObjectType -from ..scalars import String, Int +from ..scalars import Int, String +from ..structures import List, NonNull from ..typemap import TypeMap, resolve_type diff --git a/graphene/types/tests/test_uuid.py b/graphene/types/tests/test_uuid.py index f1499e35..188ebcb8 100644 --- a/graphene/types/tests/test_uuid.py +++ b/graphene/types/tests/test_uuid.py @@ -1,6 +1,6 @@ -from ..uuid import UUID from ..objecttype import ObjectType from ..schema import Schema +from ..uuid import UUID class Query(ObjectType): diff --git a/graphene/types/union.py b/graphene/types/union.py index c5925e88..45e03b0c 100644 --- a/graphene/types/union.py +++ b/graphene/types/union.py @@ -1,7 +1,6 @@ from .base import BaseOptions, BaseType from .unmountedtype import UnmountedType - # For static type checking with Mypy MYPY = False if MYPY: diff --git a/graphene/utils/annotate.py b/graphene/utils/annotate.py index 51a87a78..9abb8e06 100644 --- a/graphene/utils/annotate.py +++ b/graphene/utils/annotate.py @@ -1,6 +1,6 @@ import six -from ..pyutils.compat import signature, func_name +from ..pyutils.compat import func_name, signature from .deprecated import warn_deprecation diff --git a/graphene/utils/resolve_only_args.py b/graphene/utils/resolve_only_args.py index 897e6223..7862dedd 100644 --- a/graphene/utils/resolve_only_args.py +++ b/graphene/utils/resolve_only_args.py @@ -1,4 +1,5 @@ from functools import wraps + from .deprecated import deprecated diff --git a/graphene/utils/subclass_with_meta.py b/graphene/utils/subclass_with_meta.py index 61205be0..b0c8dee2 100644 --- a/graphene/utils/subclass_with_meta.py +++ b/graphene/utils/subclass_with_meta.py @@ -1,6 +1,7 @@ -import six from inspect import isclass +import six + from ..pyutils.init_subclass import InitSubclassMeta from .props import props diff --git a/graphene/utils/tests/test_annotate.py b/graphene/utils/tests/test_annotate.py index e4930b62..446fbbfe 100644 --- a/graphene/utils/tests/test_annotate.py +++ b/graphene/utils/tests/test_annotate.py @@ -1,4 +1,5 @@ import pytest + from ..annotate import annotate diff --git a/graphene/utils/tests/test_deprecated.py b/graphene/utils/tests/test_deprecated.py index cd0e2dcb..0af06763 100644 --- a/graphene/utils/tests/test_deprecated.py +++ b/graphene/utils/tests/test_deprecated.py @@ -1,6 +1,8 @@ import pytest + from .. import deprecated -from ..deprecated import deprecated as deprecated_decorator, warn_deprecation +from ..deprecated import deprecated as deprecated_decorator +from ..deprecated import warn_deprecation def test_warn_deprecation(mocker): diff --git a/graphene/utils/tests/test_resolve_only_args.py b/graphene/utils/tests/test_resolve_only_args.py index 35554e9b..11a6bbdb 100644 --- a/graphene/utils/tests/test_resolve_only_args.py +++ b/graphene/utils/tests/test_resolve_only_args.py @@ -1,5 +1,5 @@ -from ..resolve_only_args import resolve_only_args from .. import deprecated +from ..resolve_only_args import resolve_only_args def test_resolve_only_args(mocker): diff --git a/setup.py b/setup.py index 102f46c4..f84bfc2d 100644 --- a/setup.py +++ b/setup.py @@ -1,8 +1,9 @@ -from setuptools import find_packages, setup -from setuptools.command.test import test as TestCommand -import sys import ast import re +import sys + +from setuptools import find_packages, setup +from setuptools.command.test import test as TestCommand _version_re = re.compile(r'VERSION\s+=\s+(.*)') From a7168ffc6e3bf2cb01c5abd46440e52a9a8de14f Mon Sep 17 00:00:00 2001 From: Dan <3498629+dan98765@users.noreply.github.com> Date: Mon, 28 May 2018 13:25:15 -0700 Subject: [PATCH 08/45] Fix: Make `tox` stop failing (#741) * Tox stopped working due to recent changes; add in necessary dependencies to tox.ini so it passes again * Run pre-commit on all files * Switch testenv deps to .[test] instead of an explicit list so the list of test deps in setup.py becomes the single source of truth for test deps. --- tox.ini | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/tox.ini b/tox.ini index 849f581c..cf538bb7 100644 --- a/tox.ini +++ b/tox.ini @@ -3,18 +3,7 @@ envlist = flake8,py27,py33,py34,py35,py36,pre-commit,pypy skipsdist = true [testenv] -deps= - pytest>=2.7.2 - graphql-core>=1.1 - promise>=2.0 - graphql-relay>=0.4.5 - six - blinker - singledispatch - mock - pytz - iso8601 - pytest-benchmark +deps = .[test] setenv = PYTHONPATH = .:{envdir} commands= From f13e54b4a4e963b3bf2a6d44d19d27f99b9da8fd Mon Sep 17 00:00:00 2001 From: Dan <3498629+dan98765@users.noreply.github.com> Date: Wed, 30 May 2018 04:53:44 -0700 Subject: [PATCH 09/45] Update contributing docs about using tox and sync tox pytest cmd with travis (#744) * Update pytest command run by tox to match the command used by travis. Updated README contributing section with info about using tox to run tests. * Uppercase 'Graphene' --- README.md | 18 ++++++++++++++++-- docs/conf.py | 1 + tox.ini | 2 +- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2288f341..3d972fdc 100644 --- a/README.md +++ b/README.md @@ -79,18 +79,32 @@ After cloning this repo, ensure dependencies are installed by running: pip install -e ".[test]" ``` -After developing, the full test suite can be evaluated by running: +Well-written tests and maintaining good test coverage is important to this project. While developing, run new and existing tests with: ```sh -py.test graphene --cov=graphene --benchmark-skip # Use -v -s for verbose mode +py.test PATH/TO/MY/DIR/test_test.py # Single file +py.test PATH/TO/MY/DIR/ # All tests in directory ``` +Add the `-s` flag if you have introduced breakpoints into the code for debugging. +Add the `-v` ("verbose") flag to get more detailed test output. For even more detailed output, use `-vv`. +Check out the [pytest documentation](https://docs.pytest.org/en/latest/) for more options and test running controls. + You can also run the benchmarks with: ```sh py.test graphene --benchmark-only ``` +Graphene supports several versions of Python. To make sure that changes do not break compatibility with any of those versions, we use `tox` to create virtualenvs for each python version and run tests with that version. To run against all python versions defined in the `tox.ini` config file, just run: +```sh +tox +``` +If you wish to run against a specific version defined in the `tox.ini` file: +```sh +tox -e py36 +``` +Tox can only use whatever versions of python are installed on your system. When you create a pull request, Travis will also be running the same tests and report the results, so there is no need for potential contributors to try to install every single version of python on their own system ahead of time. We appreciate opening issues and pull requests to make graphene even more stable & useful! ### Documentation diff --git a/docs/conf.py b/docs/conf.py index ccb5305d..b25a36dc 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,4 +1,5 @@ import os + import sphinx_graphene_theme on_rtd = os.environ.get('READTHEDOCS', None) == 'True' diff --git a/tox.ini b/tox.ini index cf538bb7..3c2860c9 100644 --- a/tox.ini +++ b/tox.ini @@ -7,7 +7,7 @@ deps = .[test] setenv = PYTHONPATH = .:{envdir} commands= - py.test + py.test --cov=graphene graphene examples [testenv:pre-commit] basepython=python3.6 From 4e59cf3ea6c3cbf6bab589301b8be8e2600d44ca Mon Sep 17 00:00:00 2001 From: Dan Palmer Date: Wed, 30 May 2018 14:50:22 +0100 Subject: [PATCH 10/45] Fix warning output Warning filtering is the responsibility of the application, not a library, and this current use causes all warnings from an application (at least those after this function is evaluated the first time) to print their contents. This makes the library a better citizen in the Python ecosystem, and more closely matches what developers would expect. (For what it's worth, we also can't start using this library without this patch because the logging is too verbose and may obscure more important warnings. We depend on being able to accurately control warning and logging output) --- graphene/utils/deprecated.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/graphene/utils/deprecated.py b/graphene/utils/deprecated.py index f70b2e7d..d00642f8 100644 --- a/graphene/utils/deprecated.py +++ b/graphene/utils/deprecated.py @@ -6,13 +6,11 @@ string_types = (type(b''), type(u'')) def warn_deprecation(text): - warnings.simplefilter('always', DeprecationWarning) warnings.warn( text, category=DeprecationWarning, stacklevel=2 ) - warnings.simplefilter('default', DeprecationWarning) def deprecated(reason): From aa0c401cb517afc09f6dee7477005ed1badb35c8 Mon Sep 17 00:00:00 2001 From: Kurtis Jantzen Date: Wed, 30 May 2018 16:56:42 -0600 Subject: [PATCH 11/45] Resolve #750 by editing assert message --- graphene/relay/node.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/graphene/relay/node.py b/graphene/relay/node.py index 6596757c..5c787ffb 100644 --- a/graphene/relay/node.py +++ b/graphene/relay/node.py @@ -101,8 +101,8 @@ class Node(AbstractNode): if only_type: assert graphene_type == only_type, ( - 'Must receive an {} id.' - ).format(graphene_type._meta.name) + 'Must receive a {} id.' + ).format(only_type._meta.name) # We make sure the ObjectType implements the "Node" interface if cls not in graphene_type._meta.interfaces: From d6a81ee7ff7a9bb406478cecc3d78ed68da451a1 Mon Sep 17 00:00:00 2001 From: Kurtis Jantzen Date: Wed, 30 May 2018 17:06:43 -0600 Subject: [PATCH 12/45] Update tests to reflect changes --- graphene/relay/tests/test_node.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/graphene/relay/tests/test_node.py b/graphene/relay/tests/test_node.py index 10dc5d94..df44fcb5 100644 --- a/graphene/relay/tests/test_node.py +++ b/graphene/relay/tests/test_node.py @@ -115,7 +115,7 @@ def test_node_field_only_type_wrong(): '{ onlyNode(id:"%s") { __typename, name } } ' % Node.to_global_id("MyOtherNode", 1) ) assert len(executed.errors) == 1 - assert str(executed.errors[0]) == 'Must receive an MyOtherNode id.' + assert str(executed.errors[0]) == 'Must receive a MyNode id.' assert executed.data == {'onlyNode': None} @@ -132,7 +132,7 @@ def test_node_field_only_lazy_type_wrong(): '{ onlyNodeLazy(id:"%s") { __typename, name } } ' % Node.to_global_id("MyOtherNode", 1) ) assert len(executed.errors) == 1 - assert str(executed.errors[0]) == 'Must receive an MyOtherNode id.' + assert str(executed.errors[0]) == 'Must receive a MyNode id.' assert executed.data == {'onlyNodeLazy': None} From 00ccc2056bd6ac3af484459cd9825f38f9006106 Mon Sep 17 00:00:00 2001 From: Jeremiah Lowin Date: Thu, 31 May 2018 21:52:35 -0400 Subject: [PATCH 13/45] Don't overwrite fields on InputObject - closes #720 --- graphene/tests/issues/test_720.py | 44 +++++++++++++++++++++++++++++++ graphene/types/inputobjecttype.py | 5 +++- 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 graphene/tests/issues/test_720.py diff --git a/graphene/tests/issues/test_720.py b/graphene/tests/issues/test_720.py new file mode 100644 index 00000000..8cd99bdd --- /dev/null +++ b/graphene/tests/issues/test_720.py @@ -0,0 +1,44 @@ +# https://github.com/graphql-python/graphene/issues/720 +# InputObjectTypes overwrite the "fields" attribute of the provided +# _meta object, so even if dynamic fields are provided with a standard +# InputObjectTypeOptions, they are ignored. + +import graphene + + +class MyInputClass(graphene.InputObjectType): + + @classmethod + def __init_subclass_with_meta__( + cls, container=None, _meta=None, fields=None, **options): + if _meta is None: + _meta = graphene.types.inputobjecttype.InputObjectTypeOptions(cls) + _meta.fields = fields + super(MyInputClass, cls).__init_subclass_with_meta__( + container=container, _meta=_meta, **options) + + +class MyInput(MyInputClass): + + class Meta: + fields = dict(x=graphene.Field(graphene.Int)) + + +class Query(graphene.ObjectType): + myField = graphene.Field(graphene.String, input=graphene.Argument(MyInput)) + + def resolve_myField(parent, info, input): + return 'ok' + + +def test_issue(): + query_string = ''' + query myQuery { + myField(input: {x: 1}) + } + ''' + + schema = graphene.Schema(query=Query) + result = schema.execute(query_string) + + assert not result.errors diff --git a/graphene/types/inputobjecttype.py b/graphene/types/inputobjecttype.py index dbfccc46..b84fc0fd 100644 --- a/graphene/types/inputobjecttype.py +++ b/graphene/types/inputobjecttype.py @@ -50,7 +50,10 @@ class InputObjectType(UnmountedType, BaseType): yank_fields_from_attrs(base.__dict__, _as=InputField) ) - _meta.fields = fields + if _meta.fields: + _meta.fields.update(fields) + else: + _meta.fields = fields if container is None: container = type(cls.__name__, (InputObjectTypeContainer, cls), {}) _meta.container = container From 2fbd2c1cb6ad4b6ff19896d267b9f8a4af567107 Mon Sep 17 00:00:00 2001 From: Felipe Mesquita Date: Fri, 1 Jun 2018 17:15:34 -0300 Subject: [PATCH 14/45] Fix parameter order for Relay's Root-field --- UPGRADE-v2.0.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/UPGRADE-v2.0.md b/UPGRADE-v2.0.md index 5dc76154..32b28d8b 100644 --- a/UPGRADE-v2.0.md +++ b/UPGRADE-v2.0.md @@ -198,6 +198,32 @@ class MyObject(ObjectType): return ... ``` +## Node.get_node_from_global_id + +The parameters' order of `get_node_from_global_id` method has changed. You may need to adjust your [Node Root Field](http://docs.graphene-python.org/en/latest/relay/nodes/#node-root-field) and maybe other places that uses this method to obtain an object. + +Before: +```python +class RootQuery(object): + ... + node = Field(relay.Node, id=ID(required=True)) + + def resolve_node(self, args, context, info): + node = relay.Node.get_node_from_global_id(args['id'], context, info) + return node +``` + +Now: +```python +class RootQuery(object): + ... + node = Field(relay.Node, id=ID(required=True)) + + def resolve_node(self, info, id): + node = relay.Node.get_node_from_global_id(info, id) + return node +``` + ## Mutation.mutate Now only receives (`self`, `info`, `**args`) and is not a @classmethod From 1b3e7f3b9600f5d2c20a17c9cc0a07f559b76b92 Mon Sep 17 00:00:00 2001 From: Dan <3498629+dan98765@users.noreply.github.com> Date: Tue, 5 Jun 2018 13:47:07 -0700 Subject: [PATCH 15/45] Add flake8 pre-commit hook and manually edit files to pass flake8 validation (#746) Add flake8 pre-commit hook and manually edit files to pass flake8 validation --- .pre-commit-config.yaml | 3 ++- graphene/relay/tests/test_connection_query.py | 7 +++---- graphene/tests/issues/test_313.py | 1 - graphene/tests/issues/test_356.py | 13 ++++++++----- graphene/tests/issues/test_425.py | 3 +-- graphene/types/tests/test_abstracttype.py | 2 -- graphene/types/tests/test_argument.py | 10 ++++++++-- graphene/types/tests/test_base.py | 2 -- graphene/types/tests/test_datetime.py | 6 +++--- graphene/types/tests/test_definition.py | 9 ++++++++- graphene/types/tests/test_enum.py | 4 ++-- graphene/types/tests/test_query.py | 2 -- graphene/types/tests/test_typemap.py | 3 +-- graphene/utils/tests/test_annotate.py | 2 +- graphene/utils/tests/test_deprecated.py | 2 +- graphene/utils/tests/test_resolve_only_args.py | 2 -- 16 files changed, 38 insertions(+), 33 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 085f7fa9..156d038a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: git://github.com/pre-commit/pre-commit-hooks - rev: v1.2.3 + rev: v1.3.0 hooks: - id: autopep8-wrapper args: @@ -16,6 +16,7 @@ repos: - id: pretty-format-json args: - --autofix + - id: flake8 - repo: https://github.com/asottile/seed-isort-config rev: v1.0.0 hooks: diff --git a/graphene/relay/tests/test_connection_query.py b/graphene/relay/tests/test_connection_query.py index b8150e64..0f266a55 100644 --- a/graphene/relay/tests/test_connection_query.py +++ b/graphene/relay/tests/test_connection_query.py @@ -56,8 +56,7 @@ schema = Schema(Query) letters = OrderedDict() for i, letter in enumerate(letter_chars): - l = Letter(id=i, letter=letter) - letters[letter] = l + letters[letter] = Letter(id=i, letter=letter) def edges(selected_letters): @@ -74,8 +73,8 @@ def edges(selected_letters): def cursor_for(ltr): - l = letters[ltr] - return base64('arrayconnection:%s' % l.id) + letter = letters[ltr] + return base64('arrayconnection:%s' % letter.id) def execute(args=''): diff --git a/graphene/tests/issues/test_313.py b/graphene/tests/issues/test_313.py index 9df6c17b..e524a85b 100644 --- a/graphene/tests/issues/test_313.py +++ b/graphene/tests/issues/test_313.py @@ -1,7 +1,6 @@ # https://github.com/graphql-python/graphene/issues/313 import graphene -from graphene import resolve_only_args class Query(graphene.ObjectType): diff --git a/graphene/tests/issues/test_356.py b/graphene/tests/issues/test_356.py index 8eeaed10..9d8fc77b 100644 --- a/graphene/tests/issues/test_356.py +++ b/graphene/tests/issues/test_356.py @@ -21,10 +21,13 @@ class MyUnion(graphene.Union): def test_issue(): + class Query(graphene.ObjectType): + things = relay.ConnectionField(MyUnion) + with pytest.raises(Exception) as exc_info: - class Query(graphene.ObjectType): - things = relay.ConnectionField(MyUnion) + graphene.Schema(query=Query) - schema = graphene.Schema(query=Query) - - assert str(exc_info.value) == 'IterableConnectionField type have to be a subclass of Connection. Received "MyUnion".' + assert str(exc_info.value) == ( + 'IterableConnectionField type have to be a subclass of Connection. ' + 'Received "MyUnion".' + ) diff --git a/graphene/tests/issues/test_425.py b/graphene/tests/issues/test_425.py index cc77e730..525e0b76 100644 --- a/graphene/tests/issues/test_425.py +++ b/graphene/tests/issues/test_425.py @@ -2,8 +2,7 @@ # Adapted for Graphene 2.0 from graphene.types.enum import Enum, EnumOptions -from graphene.types.inputobjecttype import (InputObjectType, - InputObjectTypeOptions) +from graphene.types.inputobjecttype import InputObjectType from graphene.types.objecttype import ObjectType, ObjectTypeOptions diff --git a/graphene/types/tests/test_abstracttype.py b/graphene/types/tests/test_abstracttype.py index 73144bec..6ad35b75 100644 --- a/graphene/types/tests/test_abstracttype.py +++ b/graphene/types/tests/test_abstracttype.py @@ -1,5 +1,3 @@ -import pytest - from .. import abstracttype from ..abstracttype import AbstractType from ..field import Field diff --git a/graphene/types/tests/test_argument.py b/graphene/types/tests/test_argument.py index 744c9e29..bc7b6e1c 100644 --- a/graphene/types/tests/test_argument.py +++ b/graphene/types/tests/test_argument.py @@ -51,7 +51,10 @@ def test_to_arguments_raises_if_field(): with pytest.raises(ValueError) as exc_info: to_arguments(args) - assert str(exc_info.value) == 'Expected arg_string to be Argument, but received Field. Try using Argument(String).' + assert str(exc_info.value) == ( + 'Expected arg_string to be Argument, but received Field. Try using ' + 'Argument(String).' + ) def test_to_arguments_raises_if_inputfield(): @@ -62,7 +65,10 @@ def test_to_arguments_raises_if_inputfield(): with pytest.raises(ValueError) as exc_info: to_arguments(args) - assert str(exc_info.value) == 'Expected arg_string to be Argument, but received InputField. Try using Argument(String).' + assert str(exc_info.value) == ( + 'Expected arg_string to be Argument, but received InputField. Try ' + 'using Argument(String).' + ) def test_argument_with_lazy_type(): diff --git a/graphene/types/tests/test_base.py b/graphene/types/tests/test_base.py index 6399f69d..cd555ad5 100644 --- a/graphene/types/tests/test_base.py +++ b/graphene/types/tests/test_base.py @@ -1,5 +1,3 @@ -import pytest - from ..base import BaseOptions, BaseType diff --git a/graphene/types/tests/test_datetime.py b/graphene/types/tests/test_datetime.py index 80c1d3c1..35e8c785 100644 --- a/graphene/types/tests/test_datetime.py +++ b/graphene/types/tests/test_datetime.py @@ -62,7 +62,7 @@ def test_bad_datetime_query(): assert len(result.errors) == 1 assert isinstance(result.errors[0], GraphQLError) - assert result.data == None + assert result.data is None def test_bad_date_query(): @@ -72,7 +72,7 @@ def test_bad_date_query(): assert len(result.errors) == 1 assert isinstance(result.errors[0], GraphQLError) - assert result.data == None + assert result.data is None def test_bad_time_query(): @@ -82,7 +82,7 @@ def test_bad_time_query(): assert len(result.errors) == 1 assert isinstance(result.errors[0], GraphQLError) - assert result.data == None + assert result.data is None def test_datetime_query_variable(): diff --git a/graphene/types/tests/test_definition.py b/graphene/types/tests/test_definition.py index af9168c9..d3cd2c38 100644 --- a/graphene/types/tests/test_definition.py +++ b/graphene/types/tests/test_definition.py @@ -288,7 +288,14 @@ def test_stringifies_simple_types(): # ] # for x in bad_union_types: # with raises(Exception) as excinfo: -# GraphQLSchema(GraphQLObjectType('Root', fields={'union': GraphQLField(GraphQLUnionType('BadUnion', [x]))})) +# GraphQLSchema( +# GraphQLObjectType( +# 'Root', +# fields={ +# 'union': GraphQLField(GraphQLUnionType('BadUnion', [x])) +# } +# ) +# ) # assert 'BadUnion may only contain Object types, it cannot contain: ' + str(x) + '.' \ # == str(excinfo.value) diff --git a/graphene/types/tests/test_enum.py b/graphene/types/tests/test_enum.py index d35d555f..231abba6 100644 --- a/graphene/types/tests/test_enum.py +++ b/graphene/types/tests/test_enum.py @@ -96,8 +96,8 @@ def test_enum_from_builtin_enum_accepts_lambda_description(): assert GraphQLPyEpisode[2].name == 'JEDI' and GraphQLPyEpisode[2].description == 'Other' assert GraphQLPyEpisode[0].name == 'NEWHOPE' and GraphQLPyEpisode[0].deprecation_reason == 'meh' - assert GraphQLPyEpisode[1].name == 'EMPIRE' and GraphQLPyEpisode[1].deprecation_reason == None - assert GraphQLPyEpisode[2].name == 'JEDI' and GraphQLPyEpisode[2].deprecation_reason == None + assert GraphQLPyEpisode[1].name == 'EMPIRE' and GraphQLPyEpisode[1].deprecation_reason is None + assert GraphQLPyEpisode[2].name == 'JEDI' and GraphQLPyEpisode[2].deprecation_reason is None def test_enum_from_python3_enum_uses_enum_doc(): diff --git a/graphene/types/tests/test_query.py b/graphene/types/tests/test_query.py index c4133970..7bdde001 100644 --- a/graphene/types/tests/test_query.py +++ b/graphene/types/tests/test_query.py @@ -442,8 +442,6 @@ def test_big_list_of_containers_multiple_fields_custom_resolvers_query_benchmark def test_query_annotated_resolvers(): - import json - context = Context(key="context") class Query(ObjectType): diff --git a/graphene/types/tests/test_typemap.py b/graphene/types/tests/test_typemap.py index 94af960c..7d441bfb 100644 --- a/graphene/types/tests/test_typemap.py +++ b/graphene/types/tests/test_typemap.py @@ -67,8 +67,7 @@ def test_objecttype(): foo_field = fields['foo'] assert isinstance(foo_field, GraphQLField) assert foo_field.description == 'Field description' - f = MyObjectType.resolve_foo - # assert foo_field.resolver == getattr(f, '__func__', f) + assert foo_field.args == { 'bar': GraphQLArgument(GraphQLString, description='Argument description', default_value='x', out_name='bar') } diff --git a/graphene/utils/tests/test_annotate.py b/graphene/utils/tests/test_annotate.py index 446fbbfe..259df3cb 100644 --- a/graphene/utils/tests/test_annotate.py +++ b/graphene/utils/tests/test_annotate.py @@ -34,6 +34,6 @@ def test_annotate_with_params(): def test_annotate_with_wront_params(): with pytest.raises(Exception) as exc_info: - annotated_func = annotate(p=int, _trigger_warning=False)(func) + annotate(p=int, _trigger_warning=False)(func) assert str(exc_info.value) == 'The key p is not a function parameter in the function "func".' diff --git a/graphene/utils/tests/test_deprecated.py b/graphene/utils/tests/test_deprecated.py index 0af06763..16fca03b 100644 --- a/graphene/utils/tests/test_deprecated.py +++ b/graphene/utils/tests/test_deprecated.py @@ -63,5 +63,5 @@ def test_deprecated_class_text(mocker): def test_deprecated_other_object(mocker): mocker.patch.object(deprecated, 'warn_deprecation') - with pytest.raises(TypeError) as exc_info: + with pytest.raises(TypeError): deprecated_decorator({}) diff --git a/graphene/utils/tests/test_resolve_only_args.py b/graphene/utils/tests/test_resolve_only_args.py index 11a6bbdb..1dfd4789 100644 --- a/graphene/utils/tests/test_resolve_only_args.py +++ b/graphene/utils/tests/test_resolve_only_args.py @@ -8,8 +8,6 @@ def test_resolve_only_args(mocker): def resolver(root, **args): return root, args - my_data = {'one': 1, 'two': 2} - wrapped_resolver = resolve_only_args(resolver) assert deprecated.warn_deprecation.called result = wrapped_resolver(1, 2, a=3) From dbb72ba06b53a8a840204cc085310d5a1c3da639 Mon Sep 17 00:00:00 2001 From: Daniel Gallagher Date: Fri, 8 Jun 2018 21:54:24 -0700 Subject: [PATCH 16/45] Update to match graphql-core --- .travis.yml | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/.travis.yml b/.travis.yml index b24ba5c4..e6e01192 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,23 +1,24 @@ language: python -python: 3.6 -env: # These should match the tox env list. - - TOXENV=flake8 - - TOXENV=py27 - - TOXENV=py33 - - TOXENV=py34 - - TOXENV=py35 - - TOXENV=py36 - - TOXENV=pypy - - TOXENV=pre-commit - global: - secure: SQC0eCWCWw8bZxbLE8vQn+UjJOp3Z1m779s9SMK3lCLwJxro/VCLBZ7hj4xsrq1MtcFO2U2Kqf068symw4Hr/0amYI3HFTCFiwXAC3PAKXeURca03eNO2heku+FtnQcOjBanExTsIBQRLDXMOaUkf3MIztpLJ4LHqMfUupKmw9YSB0v40jDbSN8khBnndFykmOnVVHznFp8USoN5F0CiPpnfEvHnJkaX76lNf7Kc9XNShBTTtJsnsHMhuYQeInt0vg9HSjoIYC38Tv2hmMj1myNdzyrHF+LgRjI6ceGi50ApAnGepXC/DNRhXROfECKez+LON/ZSqBGdJhUILqC8A4WmWmIjNcwitVFp3JGBqO7LULS0BI96EtSLe8rD1rkkdTbjivajkbykM1Q0Tnmg1adzGwLxRUbTq9tJQlTTkHBCuXIkpKb1mAtb/TY7A6BqfnPi2xTc/++qEawUG7ePhscdTj0IBrUfZsUNUYZqD8E8XbSWKIuS3SHE+cZ+s/kdAsm4q+FFAlpZKOYGxIkwvgyfu4/Plfol4b7X6iAP9J3r1Kv0DgBVFst5CXEwzZs19/g0CgokQbCXf1N+xeNnUELl6/fImaR3RKP22EaABoil4z8vzl4EqxqVoH1nfhE+WlpryXsuSaF/1R+WklR7aQ1FwoCk8V8HxM2zrj4tI8k= -install: pip install coveralls tox flake8 mypy +matrix: + include: + - env: TOXENV=py27 + - env: TOXENV=py34 + python: 3.4 + - env: TOXENV=py35 + python: 3.5 + - env: TOXENV=py36 + python: 3.6 + - env: TOXENV=pypy + python: pypy-5.7.1 + - env: TOXENV=pre-commit + python: 3.6 +install: pip install coveralls tox mypy script: tox after_success: coveralls cache: - directories: - - $HOME/.cache/pip - - $HOME/.cache/pre-commit + directories: + - $HOME/.cache/pip + - $HOME/.cache/pre-commit deploy: provider: pypi user: syrusakbary From 1d49df033cd02133fd9d0783ba5501aea91b6b19 Mon Sep 17 00:00:00 2001 From: Daniel Gallagher Date: Fri, 8 Jun 2018 21:56:08 -0700 Subject: [PATCH 17/45] Explicitly run on py27 --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index e6e01192..519cdb7c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,7 @@ language: python matrix: include: - env: TOXENV=py27 + python: 2.7 - env: TOXENV=py34 python: 3.4 - env: TOXENV=py35 From 87cf3d4b80a4ac134343a21cbf23f5402e1aabc6 Mon Sep 17 00:00:00 2001 From: Daniel Gallagher Date: Fri, 8 Jun 2018 22:00:01 -0700 Subject: [PATCH 18/45] Try installing mypy only when python version is 3.6 --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 519cdb7c..3fd433b6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,9 @@ matrix: python: pypy-5.7.1 - env: TOXENV=pre-commit python: 3.6 -install: pip install coveralls tox mypy +install: + - pip install coveralls tox mypy + - if [[ $TRAVIS_PYTHON_VERSION == '3.6' ]]; then pip install mypy; fi script: tox after_success: coveralls cache: From 0f3d786402c04719d3c14f864c5084cbc40c0776 Mon Sep 17 00:00:00 2001 From: Daniel Gallagher Date: Fri, 8 Jun 2018 22:08:58 -0700 Subject: [PATCH 19/45] Run pre-commit on all files --- .travis.yml | 2 +- docs/conf.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3fd433b6..d0eb834b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,7 @@ matrix: - env: TOXENV=pre-commit python: 3.6 install: - - pip install coveralls tox mypy + - pip install coveralls tox - if [[ $TRAVIS_PYTHON_VERSION == '3.6' ]]; then pip install mypy; fi script: tox after_success: coveralls diff --git a/docs/conf.py b/docs/conf.py index ccb5305d..b25a36dc 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,4 +1,5 @@ import os + import sphinx_graphene_theme on_rtd = os.environ.get('READTHEDOCS', None) == 'True' From b5542d4426e3cf8132e4bf61e9591a19e061a561 Mon Sep 17 00:00:00 2001 From: Daniel Gallagher Date: Fri, 8 Jun 2018 22:13:45 -0700 Subject: [PATCH 20/45] Run pre-commit autoupdate --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 085f7fa9..195d9a0d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: git://github.com/pre-commit/pre-commit-hooks - rev: v1.2.3 + rev: v1.3.0 hooks: - id: autopep8-wrapper args: @@ -17,7 +17,7 @@ repos: args: - --autofix - repo: https://github.com/asottile/seed-isort-config - rev: v1.0.0 + rev: v1.0.1 hooks: - id: seed-isort-config - repo: https://github.com/pre-commit/mirrors-isort From c8fba61a05b5309f432fcd3b2582419c8ea3004b Mon Sep 17 00:00:00 2001 From: Daniel Gallagher Date: Fri, 8 Jun 2018 22:19:26 -0700 Subject: [PATCH 21/45] Exclude README.md from trailing-whitespace hook --- .pre-commit-config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 195d9a0d..0cbcc645 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,6 +13,7 @@ repos: - id: end-of-file-fixer exclude: ^docs/.*$ - id: trailing-whitespace + exclude: README.md - id: pretty-format-json args: - --autofix From 12ee52a13acb11595858f699f2f133d64840ac99 Mon Sep 17 00:00:00 2001 From: Dan <3498629+dan98765@users.noreply.github.com> Date: Sat, 9 Jun 2018 06:01:29 -0700 Subject: [PATCH 22/45] Add pyupgrade pre-commit hook and run on all files (#736) --- .pre-commit-config.yaml | 4 ++++ graphene/pyutils/enum.py | 8 +++---- graphene/pyutils/signature.py | 40 +++++++++++++++++------------------ graphene/types/base.py | 2 +- 4 files changed, 29 insertions(+), 25 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 156d038a..0eeb4cac 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,6 +17,10 @@ repos: args: - --autofix - id: flake8 +- repo: https://github.com/asottile/pyupgrade + rev: v1.2.0 + hooks: + - id: pyupgrade - repo: https://github.com/asottile/seed-isort-config rev: v1.0.0 hooks: diff --git a/graphene/pyutils/enum.py b/graphene/pyutils/enum.py index 076b6a9d..f3421d9f 100644 --- a/graphene/pyutils/enum.py +++ b/graphene/pyutils/enum.py @@ -170,7 +170,7 @@ class EnumMeta(type): first_enum) # save enum items into separate mapping so they don't get baked into # the new class - members = dict((k, classdict[k]) for k in classdict._member_names) + members = {k: classdict[k] for k in classdict._member_names} for name in classdict._member_names: del classdict[name] @@ -192,14 +192,14 @@ class EnumMeta(type): _order_ += aliases # check for illegal enum names (any others?) - invalid_names = set(members) & set(['mro']) + invalid_names = set(members) & {'mro'} if invalid_names: raise ValueError('Invalid enum member name(s): %s' % ( ', '.join(invalid_names), )) # save attributes from super classes so we know if we can take # the shortcut of storing members in the class dict - base_attributes = set([a for b in bases for a in b.__dict__]) + base_attributes = {a for b in bases for a in b.__dict__} # create our new Enum type enum_class = super(EnumMeta, metacls).__new__(metacls, cls, bases, classdict) enum_class._member_names_ = [] # names in random order @@ -831,7 +831,7 @@ def _convert(cls, name, module, filter, source=None): source = vars(source) else: source = module_globals - members = dict((name, value) for name, value in source.items() if filter(name)) + members = {name: value for name, value in source.items() if filter(name)} cls = cls(name, members, module=module) cls.__reduce_ex__ = _reduce_ex_by_name module_globals.update(cls.__members__) diff --git a/graphene/pyutils/signature.py b/graphene/pyutils/signature.py index 5ad6346c..c15fd14b 100644 --- a/graphene/pyutils/signature.py +++ b/graphene/pyutils/signature.py @@ -52,7 +52,7 @@ def signature(obj): '''Get a signature object for the passed callable.''' if not callable(obj): - raise TypeError('{0!r} is not a callable object'.format(obj)) + raise TypeError('{!r} is not a callable object'.format(obj)) if isinstance(obj, types.MethodType): sig = signature(obj.__func__) @@ -99,7 +99,7 @@ def signature(obj): try: ba = sig.bind_partial(*partial_args, **partial_keywords) except TypeError as ex: - msg = 'partial object {0!r} has incorrect arguments'.format(obj) + msg = 'partial object {!r} has incorrect arguments'.format(obj) raise ValueError(msg) for arg_name, arg_value in ba.arguments.items(): @@ -166,10 +166,10 @@ def signature(obj): if isinstance(obj, types.BuiltinFunctionType): # Raise a nicer error message for builtins - msg = 'no signature found for builtin function {0!r}'.format(obj) + msg = 'no signature found for builtin function {!r}'.format(obj) raise ValueError(msg) - raise ValueError('callable {0!r} is not supported by signature'.format(obj)) + raise ValueError('callable {!r} is not supported by signature'.format(obj)) class _void(object): @@ -190,7 +190,7 @@ class _ParameterKind(int): return self._name def __repr__(self): - return '<_ParameterKind: {0!r}>'.format(self._name) + return '<_ParameterKind: {!r}>'.format(self._name) _POSITIONAL_ONLY = _ParameterKind(0, name='POSITIONAL_ONLY') @@ -238,7 +238,7 @@ class Parameter(object): if default is not _empty: if kind in (_VAR_POSITIONAL, _VAR_KEYWORD): - msg = '{0} parameters cannot have default values'.format(kind) + msg = '{} parameters cannot have default values'.format(kind) raise ValueError(msg) self._default = default self._annotation = annotation @@ -251,7 +251,7 @@ class Parameter(object): else: name = str(name) if kind != _POSITIONAL_ONLY and not re.match(r'[a-z_]\w*$', name, re.I): - msg = '{0!r} is not a valid parameter name'.format(name) + msg = '{!r} is not a valid parameter name'.format(name) raise ValueError(msg) self._name = name @@ -302,15 +302,15 @@ class Parameter(object): if kind == _POSITIONAL_ONLY: if formatted is None: formatted = '' - formatted = '<{0}>'.format(formatted) + formatted = '<{}>'.format(formatted) # Add annotation and default value if self._annotation is not _empty: - formatted = '{0}:{1}'.format(formatted, + formatted = '{}:{}'.format(formatted, formatannotation(self._annotation)) if self._default is not _empty: - formatted = '{0}={1}'.format(formatted, repr(self._default)) + formatted = '{}={}'.format(formatted, repr(self._default)) if kind == _VAR_POSITIONAL: formatted = '*' + formatted @@ -320,11 +320,11 @@ class Parameter(object): return formatted def __repr__(self): - return '<{0} at {1:#x} {2!r}>'.format(self.__class__.__name__, + return '<{} at {:#x} {!r}>'.format(self.__class__.__name__, id(self), self.name) def __hash__(self): - msg = "unhashable type: '{0}'".format(self.__class__.__name__) + msg = "unhashable type: '{}'".format(self.__class__.__name__) raise TypeError(msg) def __eq__(self, other): @@ -421,7 +421,7 @@ class BoundArguments(object): return kwargs def __hash__(self): - msg = "unhashable type: '{0}'".format(self.__class__.__name__) + msg = "unhashable type: '{}'".format(self.__class__.__name__) raise TypeError(msg) def __eq__(self, other): @@ -489,7 +489,7 @@ class Signature(object): param = param.replace(name=name) if name in params: - msg = 'duplicate parameter name: {0!r}'.format(name) + msg = 'duplicate parameter name: {!r}'.format(name) raise ValueError(msg) params[name] = param else: @@ -504,7 +504,7 @@ class Signature(object): '''Constructs Signature for the given python function''' if not isinstance(func, types.FunctionType): - raise TypeError('{0!r} is not a Python function'.format(func)) + raise TypeError('{!r} is not a Python function'.format(func)) Parameter = cls._parameter_cls @@ -599,7 +599,7 @@ class Signature(object): return_annotation=return_annotation) def __hash__(self): - msg = "unhashable type: '{0}'".format(self.__class__.__name__) + msg = "unhashable type: '{}'".format(self.__class__.__name__) raise TypeError(msg) def __eq__(self, other): @@ -608,8 +608,8 @@ class Signature(object): len(self.parameters) != len(other.parameters)): return False - other_positions = dict((param, idx) - for idx, param in enumerate(other.parameters.keys())) + other_positions = {param: idx + for idx, param in enumerate(other.parameters.keys())} for idx, (param_name, param) in enumerate(self.parameters.items()): if param.kind == _KEYWORD_ONLY: @@ -799,10 +799,10 @@ class Signature(object): result.append(formatted) - rendered = '({0})'.format(', '.join(result)) + rendered = '({})'.format(', '.join(result)) if self.return_annotation is not _empty: anno = formatannotation(self.return_annotation) - rendered += ' -> {0}'.format(anno) + rendered += ' -> {}'.format(anno) return rendered diff --git a/graphene/types/base.py b/graphene/types/base.py index 50242674..3bbd42d1 100644 --- a/graphene/types/base.py +++ b/graphene/types/base.py @@ -18,7 +18,7 @@ class BaseOptions(object): if not self._frozen: super(BaseOptions, self).__setattr__(name, value) else: - raise Exception("Can't modify frozen Options {0}".format(self)) + raise Exception("Can't modify frozen Options {}".format(self)) def __repr__(self): return "<{} name={}>".format(self.__class__.__name__, repr(self.name)) From 400a98de921cf1c8f43f66dd1b8387a9f74f9b4a Mon Sep 17 00:00:00 2001 From: Daniel Gallagher Date: Mon, 11 Jun 2018 09:12:27 -0700 Subject: [PATCH 23/45] Add tox env for running mypy and add that to .travis.yml --- .travis.yml | 3 ++- tox.ini | 9 ++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index d0eb834b..399ce134 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,9 +13,10 @@ matrix: python: pypy-5.7.1 - env: TOXENV=pre-commit python: 3.6 + - env: TOXENV=mypy + python: 3.6 install: - pip install coveralls tox - - if [[ $TRAVIS_PYTHON_VERSION == '3.6' ]]; then pip install mypy; fi script: tox after_success: coveralls cache: diff --git a/tox.ini b/tox.ini index cf538bb7..8166a5b6 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = flake8,py27,py33,py34,py35,py36,pre-commit,pypy +envlist = flake8,py27,py33,py34,py35,py36,pre-commit,pypy,mypy skipsdist = true [testenv] @@ -18,6 +18,13 @@ setenv = commands = pre-commit {posargs:run --all-files} +[testenv:mypy] +basepython=python3.6 +deps = + mypy +commands = + mypy graphene + [testenv:flake8] deps = flake8 commands = From b72dfa87a483317533c7f46bc4d25b782cc7b97a Mon Sep 17 00:00:00 2001 From: Dan <3498629+dan98765@users.noreply.github.com> Date: Tue, 12 Jun 2018 13:38:07 -0700 Subject: [PATCH 24/45] Update README Contributing section to encourage use of virtualenv (#765) --- README.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 3d972fdc..1ffb4aea 100644 --- a/README.md +++ b/README.md @@ -73,9 +73,11 @@ If you want to learn even more, you can also check the following [examples](exam ## Contributing -After cloning this repo, ensure dependencies are installed by running: +After cloning this repo, create a [virtualenv](https://virtualenv.pypa.io/en/stable/) and ensure dependencies are installed by running: ```sh +virtualenv venv +source venv/bin/activate pip install -e ".[test]" ``` @@ -87,7 +89,7 @@ py.test PATH/TO/MY/DIR/ # All tests in directory ``` Add the `-s` flag if you have introduced breakpoints into the code for debugging. -Add the `-v` ("verbose") flag to get more detailed test output. For even more detailed output, use `-vv`. +Add the `-v` ("verbose") flag to get more detailed test output. For even more detailed output, use `-vv`. Check out the [pytest documentation](https://docs.pytest.org/en/latest/) for more options and test running controls. You can also run the benchmarks with: @@ -96,15 +98,15 @@ You can also run the benchmarks with: py.test graphene --benchmark-only ``` -Graphene supports several versions of Python. To make sure that changes do not break compatibility with any of those versions, we use `tox` to create virtualenvs for each python version and run tests with that version. To run against all python versions defined in the `tox.ini` config file, just run: +Graphene supports several versions of Python. To make sure that changes do not break compatibility with any of those versions, we use `tox` to create virtualenvs for each python version and run tests with that version. To run against all python versions defined in the `tox.ini` config file, just run: ```sh tox ``` -If you wish to run against a specific version defined in the `tox.ini` file: +If you wish to run against a specific version defined in the `tox.ini` file: ```sh tox -e py36 ``` -Tox can only use whatever versions of python are installed on your system. When you create a pull request, Travis will also be running the same tests and report the results, so there is no need for potential contributors to try to install every single version of python on their own system ahead of time. We appreciate opening issues and pull requests to make graphene even more stable & useful! +Tox can only use whatever versions of python are installed on your system. When you create a pull request, Travis will also be running the same tests and report the results, so there is no need for potential contributors to try to install every single version of python on their own system ahead of time. We appreciate opening issues and pull requests to make graphene even more stable & useful! ### Documentation From 33f2b303de76495e123d40e90298a2c68e545766 Mon Sep 17 00:00:00 2001 From: Dan <3498629+dan98765@users.noreply.github.com> Date: Tue, 12 Jun 2018 13:38:16 -0700 Subject: [PATCH 25/45] Add python3.6 classifier to setup.py (#763) --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index f84bfc2d..46a9f427 100644 --- a/setup.py +++ b/setup.py @@ -79,6 +79,7 @@ setup( 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: Implementation :: PyPy', ], From 81419de5bfb343f048d42ed94f10af6deab47031 Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Tue, 12 Jun 2018 21:48:52 +0100 Subject: [PATCH 26/45] Update to v2.1.2 --- graphene/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphene/__init__.py b/graphene/__init__.py index ff7f9df7..30f89a46 100644 --- a/graphene/__init__.py +++ b/graphene/__init__.py @@ -35,7 +35,7 @@ from .utils.resolve_only_args import resolve_only_args from .utils.module_loading import lazy_import -VERSION = (2, 1, 1, 'final', 0) +VERSION = (2, 1, 2, 'final', 0) __version__ = get_version(VERSION) From 5c4736e1023897c0450a8dbbac63fe1ba28c6041 Mon Sep 17 00:00:00 2001 From: Raphael Boidol Date: Fri, 20 Apr 2018 14:21:59 +0200 Subject: [PATCH 27/45] Update documentation * resolver function arguments changed in `objecttypes.rst` * small typo in `mutations.rst` --- docs/types/mutations.rst | 2 +- docs/types/objecttypes.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/types/mutations.rst b/docs/types/mutations.rst index ffa5a3e2..70c80d0a 100644 --- a/docs/types/mutations.rst +++ b/docs/types/mutations.rst @@ -24,7 +24,7 @@ This example defines a Mutation: ok = True return CreatePerson(person=person, ok=ok) -**person** and **ok** are the output fields of the Mutation when is +**person** and **ok** are the output fields of the Mutation when it is resolved. **Input** attributes are the arguments that the Mutation diff --git a/docs/types/objecttypes.rst b/docs/types/objecttypes.rst index 091617ce..69c8c08a 100644 --- a/docs/types/objecttypes.rst +++ b/docs/types/objecttypes.rst @@ -50,7 +50,7 @@ A resolver is a method that resolves certain fields within a ``ObjectType``. If not specififed otherwise, the resolver of a field is the ``resolve_{field_name}`` method on the ``ObjectType``. -By default resolvers take the arguments ``args``, ``context`` and ``info``. +By default resolvers take the arguments ``info`` and ``*args``. NOTE: The resolvers on a ``ObjectType`` are always treated as ``staticmethod``\ s, so the first argument to the resolver method ``self`` (or ``root``) need From 43e87768d2a4b9a069681ede6ca97a14e67bd1be Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Sat, 16 Jun 2018 15:10:32 +0100 Subject: [PATCH 28/45] Update interface documentation --- docs/types/interfaces.rst | 140 ++++++++++++++++++++++++++++++-------- 1 file changed, 111 insertions(+), 29 deletions(-) diff --git a/docs/types/interfaces.rst b/docs/types/interfaces.rst index 8c049a24..e8bcf1d1 100644 --- a/docs/types/interfaces.rst +++ b/docs/types/interfaces.rst @@ -1,60 +1,142 @@ Interfaces ========== -An Interface contains the essential fields that will be implemented by -multiple ObjectTypes. +An *Interface* is an abstract type that defines a certain set of fields that a +type must include to implement the interface. -The basics: - -- Each Interface is a Python class that inherits from ``graphene.Interface``. -- Each attribute of the Interface represents a GraphQL field. - -Quick example -------------- - -This example model defines a ``Character`` interface with a name. ``Human`` -and ``Droid`` are two implementations of that interface. +For example, you can define an Interface ``Character`` that represents any +character in the Star Wars trilogy: .. code:: python import graphene class Character(graphene.Interface): - name = graphene.String() + id = graphene.ID(required=True) + name = graphene.String(required=True) + friends = graphene.List(lambda: Character) + appears_in = graphene.List(Episode, required=True) + + +Any ObjectType that implements ``Character`` will have these exact fields, with +these arguments and return types. + +For example, here are some types that might implement ``Character``: + +.. code:: python - # Human is a Character implementation class Human(graphene.ObjectType): class Meta: interfaces = (Character, ) - born_in = graphene.String() + starships = graphene.List(Starship) + home_planet = graphene.String() - # Droid is a Character implementation class Droid(graphene.ObjectType): class Meta: interfaces = (Character, ) - function = graphene.String() + primary_function = graphene.String() -``name`` is a field on the ``Character`` interface that will also exist on both -the ``Human`` and ``Droid`` ObjectTypes (as those implement the ``Character`` -interface). Each ObjectType may define additional fields. +Both of these types have all of the fields from the ``Character`` interface, +but also bring in extra fields, ``home_planet``, ``starships`` and +``primary_function``, that are specific to that particular type of character. -The above types have the following representation in a schema: +The full GraphQL schema defition will look like this: .. code:: interface Character { - name: String - } - - type Droid implements Character { - name: String - function: String + id: ID! + name: String! + friends: [Character] + appearsIn: [Episode]! } type Human implements Character { - name: String - bornIn: String + id: ID! + name: String! + friends: [Character] + appearsIn: [Episode]! + starships: [Starship] + homePlanet: String + } + + type Droid implements Character { + id: ID! + name: String! + friends: [Character] + appearsIn: [Episode]! + primaryFunction: String + } + +Interfaces are useful when you want to return an object or set of objects, +which might be of several different types. + +For example, you can define a field ``hero`` that resolves to any +``Character``, depending on the episode, like this: + +.. code:: python + + class Query(graphene.ObjectType): + hero = graphene.Field( + Character, + required=True, + episode=graphene.Field(Episode, required=True) + ) + + def resolve_hero(_, info, episode): + # Luke is the hero of Episode V + if episode == 5: + return get_human(name='Luke Skywalker') + return get_droid(name='R2-D2') + +This allows you to directly query for fields that exist on the Character interface +as well as selecting specific fields on any type that implments the interface +using `inline fragments `_. + +For example, the following query: + +.. code:: + + query HeroForEpisode($episode: Episode!) { + hero(episode: $episode) { + __typename + name + ... on Droid { + primaryFunction + } + ... on Human { + homePlanet + } + } + } + +Will return the following data with variables ``{ "episode": 4 }``: + +.. code:: json + + { + "data": { + "hero": { + "__typename": "Droid", + "name": "R2-D2", + "primaryFunction": "Astromech" + } + } + } + +And different data with the variables ``{ "episode": 5 }``: + +.. code:: json + + { + "data": { + "hero": { + "__typename": "Human", + "name": "Luke Skywalker", + "homePlanet": "Tatooine" + } + } } From 3f6c3a7a9959bc3e4be3a0eb6422678347479793 Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Sun, 17 Jun 2018 11:23:08 +0100 Subject: [PATCH 29/45] Clean up doc and add resolve_type documentation --- docs/types/interfaces.rst | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/docs/types/interfaces.rst b/docs/types/interfaces.rst index e8bcf1d1..113edee5 100644 --- a/docs/types/interfaces.rst +++ b/docs/types/interfaces.rst @@ -83,7 +83,7 @@ For example, you can define a field ``hero`` that resolves to any hero = graphene.Field( Character, required=True, - episode=graphene.Field(Episode, required=True) + episode=graphene.Int(required=True) ) def resolve_hero(_, info, episode): @@ -92,6 +92,8 @@ For example, you can define a field ``hero`` that resolves to any return get_human(name='Luke Skywalker') return get_droid(name='R2-D2') + schema = graphene.Schema(query=Query, types=[Human, Droid]) + This allows you to directly query for fields that exist on the Character interface as well as selecting specific fields on any type that implments the interface using `inline fragments `_. @@ -100,7 +102,7 @@ For example, the following query: .. code:: - query HeroForEpisode($episode: Episode!) { + query HeroForEpisode($episode: Int!) { hero(episode: $episode) { __typename name @@ -140,3 +142,32 @@ And different data with the variables ``{ "episode": 5 }``: } } } + +Resolving data objects to types +------------------------------- + +As you build out your schema in Graphene it is common for your resolvers to +return objects that represent the data backing your GraphQL types rather than +instances of the Graphene types (e.g. Django or SQLAlchemy models). However +when you start using Interfaces you might come across this error: + +.. code:: + + "Abstract type Character must resolve to an Object type at runtime for field Query.hero ..." + +This happens because Graphene doesn't have enough information to convert the +data object into a Graphene type needed to resolve the ``Interface``. To solve +this you can define a ``resolve_type`` class method on the ``Interface`` which +maps a data object to a Graphene type: + +.. code:: python + + class Character(graphene.Interface): + id = graphene.ID(required=True) + name = graphene.String(required=True) + + @classmethod + def resolve_type(cls, instance, info): + if instance.type == 'DROID': + return Droid + return Human From a2db7c5dae36ac3c9b2f1d261a27d1efb0bacbb7 Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Sun, 17 Jun 2018 11:24:59 +0100 Subject: [PATCH 30/45] Remove an unnecessary field --- docs/types/interfaces.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/types/interfaces.rst b/docs/types/interfaces.rst index 113edee5..a8d06b9a 100644 --- a/docs/types/interfaces.rst +++ b/docs/types/interfaces.rst @@ -15,7 +15,6 @@ character in the Star Wars trilogy: id = graphene.ID(required=True) name = graphene.String(required=True) friends = graphene.List(lambda: Character) - appears_in = graphene.List(Episode, required=True) Any ObjectType that implements ``Character`` will have these exact fields, with @@ -51,14 +50,12 @@ The full GraphQL schema defition will look like this: id: ID! name: String! friends: [Character] - appearsIn: [Episode]! } type Human implements Character { id: ID! name: String! friends: [Character] - appearsIn: [Episode]! starships: [Starship] homePlanet: String } @@ -67,7 +64,6 @@ The full GraphQL schema defition will look like this: id: ID! name: String! friends: [Character] - appearsIn: [Episode]! primaryFunction: String } From e7ebb86e5aa163294ce051883889b15d247d092f Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Sun, 17 Jun 2018 11:25:32 +0100 Subject: [PATCH 31/45] Re-order type list --- docs/types/index.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/types/index.rst b/docs/types/index.rst index a49c23e7..acbdb8e8 100644 --- a/docs/types/index.rst +++ b/docs/types/index.rst @@ -8,9 +8,9 @@ Types Reference enums scalars list-and-nonnull - interfaces - abstracttypes - unions objecttypes + interfaces + unions schema mutations + abstracttypes From cc54c76a3e673922e2436d335dae17d0ddbbce33 Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Sun, 17 Jun 2018 12:05:34 +0100 Subject: [PATCH 32/45] Improve wording --- docs/types/interfaces.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/types/interfaces.rst b/docs/types/interfaces.rst index a8d06b9a..21cf2173 100644 --- a/docs/types/interfaces.rst +++ b/docs/types/interfaces.rst @@ -142,10 +142,11 @@ And different data with the variables ``{ "episode": 5 }``: Resolving data objects to types ------------------------------- -As you build out your schema in Graphene it is common for your resolvers to +As you build out your schema in Graphene it's common for your resolvers to return objects that represent the data backing your GraphQL types rather than -instances of the Graphene types (e.g. Django or SQLAlchemy models). However -when you start using Interfaces you might come across this error: +instances of the Graphene types (e.g. Django or SQLAlchemy models). This works +well with ``ObjectType`` and ``Scalar`` fields, however when you start using +Interfaces you might come across this error: .. code:: From 708278e6dca72f39e769eec559b2eb01b6915986 Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Tue, 26 Jun 2018 07:14:46 -0400 Subject: [PATCH 33/45] docs: mutation 'Output' example (closes #543) --- docs/types/mutations.rst | 42 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/docs/types/mutations.rst b/docs/types/mutations.rst index 70c80d0a..6949008f 100644 --- a/docs/types/mutations.rst +++ b/docs/types/mutations.rst @@ -76,7 +76,7 @@ We should receive: { "createPerson": { "person" : { - name: "Peter" + "name": "Peter" }, "ok": true } @@ -116,7 +116,7 @@ Note that **name** and **age** are part of **person_data** now Using the above mutation your new query would look like this: -.. code:: json +.. code:: mutation myFirstMutation { createPerson(personData: {name:"Peter", age: 24}) { @@ -143,3 +143,41 @@ as complex of input data as you need name = graphene.String() latlng = graphene.InputField(LatLngInput) +Output type example +------------------- +To return an existing ObjectType instead of a mutation-specific type, set the **Output** attribute to the desired ObjectType: + +.. code:: python + + import graphene + + class CreatePerson(graphene.Mutation): + class Arguments: + name = graphene.String() + + Output = Person + + def mutate(self, info, name): + return Person(name=name) + +Then, if we query (``schema.execute(query_str)``) the following: + +.. code:: + + mutation myFirstMutation { + createPerson(name:"Peter") { + name + __typename + } + } + +We should receive: + +.. code:: json + + { + "createPerson": { + "name": "Peter", + "__typename": "Person" + } + } From cbcaac66d0dec374082f619b8b060e87f8fd18a0 Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Sun, 1 Jul 2018 11:29:45 +0100 Subject: [PATCH 34/45] Add deduplicator utility --- graphene/utils/deduplicator.py | 51 +++++ graphene/utils/tests/test_deduplicator.py | 257 ++++++++++++++++++++++ 2 files changed, 308 insertions(+) create mode 100644 graphene/utils/deduplicator.py create mode 100644 graphene/utils/tests/test_deduplicator.py diff --git a/graphene/utils/deduplicator.py b/graphene/utils/deduplicator.py new file mode 100644 index 00000000..e381c0dd --- /dev/null +++ b/graphene/utils/deduplicator.py @@ -0,0 +1,51 @@ +from collections import defaultdict, Mapping, OrderedDict + + +def nested_dict(): + return defaultdict(nested_dict) + + +def deflate(node, index=None, path=None): + if index is None: + index = {} + if path is None: + path = [] + + if node and 'id' in node and '__typename' in node: + route = ','.join(path) + + if ( + route in index and + node['__typename'] in index[route] and + index[route][node['__typename']].get(node['id']) + ): + return { + '__typename': node['__typename'], + 'id': node['id'], + } + else: + if route not in index: + index[route] = {} + + if node['__typename'] not in index[route]: + index[route][node['__typename']] = {} + + index[route][node['__typename']][node['id']] = True + + field_names = node.keys() + result = OrderedDict() + + for field_name in field_names: + value = node[field_name] + + new_path = path + [field_name] + if isinstance(value, (list, tuple)): + result[field_name] = [ + deflate(child, index, new_path) for child in value + ] + elif isinstance(value, Mapping): + result[field_name] = deflate(value, index, new_path) + else: + result[field_name] = value + + return result diff --git a/graphene/utils/tests/test_deduplicator.py b/graphene/utils/tests/test_deduplicator.py new file mode 100644 index 00000000..dd3b54a2 --- /dev/null +++ b/graphene/utils/tests/test_deduplicator.py @@ -0,0 +1,257 @@ +import datetime +import graphene +from graphene import relay +from graphene.types.resolver import dict_resolver + +from ..deduplicator import deflate + + +def test_does_not_modify_object_without_typename_and_id(): + response = { + 'foo': 'bar', + } + + deflated_response = deflate(response) + assert deflated_response == { + 'foo': 'bar', + } + + +def test_does_not_modify_first_instance_of_an_object(): + response = { + 'data': [ + { + '__typename': 'foo', + 'id': 1, + 'name': 'foo' + }, + { + '__typename': 'foo', + 'id': 1, + 'name': 'foo' + } + ] + } + + deflated_response = deflate(response) + + assert deflated_response == { + 'data': [ + { + '__typename': 'foo', + 'id': 1, + 'name': 'foo' + }, + { + '__typename': 'foo', + 'id': 1 + } + ] + } + + +def test_does_not_modify_first_instance_of_an_object_nested(): + response = { + 'data': [ + { + '__typename': 'foo', + 'bar1': { + '__typename': 'bar', + 'id': 1, + 'name': 'bar' + }, + 'bar2': { + '__typename': 'bar', + 'id': 1, + 'name': 'bar' + }, + 'id': 1 + }, + { + '__typename': 'foo', + 'bar1': { + '__typename': 'bar', + 'id': 1, + 'name': 'bar' + }, + 'bar2': { + '__typename': 'bar', + 'id': 1, + 'name': 'bar' + }, + 'id': 2 + } + ] + } + + deflated_response = deflate(response) + + assert deflated_response == { + 'data': [ + { + '__typename': 'foo', + 'bar1': { + '__typename': 'bar', + 'id': 1, + 'name': 'bar' + }, + 'bar2': { + '__typename': 'bar', + 'id': 1, + 'name': 'bar' + }, + 'id': 1 + }, + { + '__typename': 'foo', + 'bar1': { + '__typename': 'bar', + 'id': 1 + }, + 'bar2': { + '__typename': 'bar', + 'id': 1 + }, + 'id': 2 + } + ] + } + + +def test_does_not_modify_input(): + response = { + 'data': [ + { + '__typename': 'foo', + 'id': 1, + 'name': 'foo' + }, + { + '__typename': 'foo', + 'id': 1, + 'name': 'foo' + } + ] + } + + deflate(response) + + assert response == { + 'data': [ + { + '__typename': 'foo', + 'id': 1, + 'name': 'foo' + }, + { + '__typename': 'foo', + 'id': 1, + 'name': 'foo' + } + ] + } + + +TEST_DATA = { + 'events': [ + { + 'id': '568', + 'date': datetime.date(2017, 5, 19), + 'movie': '1198359', + }, + { + 'id': '234', + 'date': datetime.date(2017, 5, 20), + 'movie': '1198359', + }, + ], + 'movies': { + '1198359': { + 'name': 'King Arthur: Legend of the Sword', + 'synopsis': ( + "When the child Arthur’s father is murdered, Vortigern, " + "Arthur’s uncle, seizes the crown. Robbed of his birthright and " + "with no idea who he truly is..." + ), + }, + }, +} + + +def test_example_end_to_end(): + class Movie(graphene.ObjectType): + class Meta: + interfaces = (relay.Node,) + default_resolver = dict_resolver + + name = graphene.String(required=True) + synopsis = graphene.String(required=True) + + class Event(graphene.ObjectType): + class Meta: + interfaces = (relay.Node,) + default_resolver = dict_resolver + + movie = graphene.Field(Movie, required=True) + date = graphene.types.datetime.Date(required=True) + + def resolve_movie(event, info): + return TEST_DATA['movies'][event['movie']] + + class Query(graphene.ObjectType): + events = graphene.List( + graphene.NonNull(Event), + required=True + ) + + def resolve_events(_, info): + return TEST_DATA['events'] + + schema = graphene.Schema(query=Query) + query = """\ + { + events { + __typename + id + date + movie { + __typename + id + name + synopsis + } + } + } + """ + result = schema.execute(query) + assert not result.errors + + result.data = deflate(result.data) + assert result.data == { + 'events': [ + { + '__typename': 'Event', + 'id': 'RXZlbnQ6NTY4', + 'date': '2017-05-19', + 'movie': { + '__typename': 'Movie', + 'id': 'TW92aWU6Tm9uZQ==', + 'name': 'King Arthur: Legend of the Sword', + 'synopsis': ( + "When the child Arthur’s father is murdered, Vortigern, " + "Arthur’s uncle, seizes the crown. Robbed of his birthright and " + "with no idea who he truly is..." + ), + }, + }, + { + '__typename': 'Event', + 'id': 'RXZlbnQ6MjM0', + 'date': '2017-05-20', + 'movie': { + '__typename': 'Movie', + 'id': 'TW92aWU6Tm9uZQ==', + }, + }, + ], + } From 56000394c4746246efd1a2846310f993c53eda8a Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Sun, 1 Jul 2018 11:32:16 +0100 Subject: [PATCH 35/45] Simplify code --- graphene/utils/deduplicator.py | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/graphene/utils/deduplicator.py b/graphene/utils/deduplicator.py index e381c0dd..fd5682b1 100644 --- a/graphene/utils/deduplicator.py +++ b/graphene/utils/deduplicator.py @@ -1,8 +1,4 @@ -from collections import defaultdict, Mapping, OrderedDict - - -def nested_dict(): - return defaultdict(nested_dict) +from collections import Mapping, OrderedDict def deflate(node, index=None, path=None): @@ -13,24 +9,15 @@ def deflate(node, index=None, path=None): if node and 'id' in node and '__typename' in node: route = ','.join(path) + cache_key = ':'.join([route, str(node['__typename']), str(node['id'])]) - if ( - route in index and - node['__typename'] in index[route] and - index[route][node['__typename']].get(node['id']) - ): + if index.get(cache_key) is True: return { '__typename': node['__typename'], 'id': node['id'], } else: - if route not in index: - index[route] = {} - - if node['__typename'] not in index[route]: - index[route][node['__typename']] = {} - - index[route][node['__typename']][node['id']] = True + index[cache_key] = True field_names = node.keys() result = OrderedDict() From 1f541e4467701431687dc1053028712ad74d0c21 Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Sun, 1 Jul 2018 21:09:12 +0100 Subject: [PATCH 36/45] Add crunch utility --- graphene/utils/crunch.py | 37 ++++++++++++++++++++++++++ graphene/utils/tests/test_crunch.py | 40 +++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 graphene/utils/crunch.py create mode 100644 graphene/utils/tests/test_crunch.py diff --git a/graphene/utils/crunch.py b/graphene/utils/crunch.py new file mode 100644 index 00000000..16902e2b --- /dev/null +++ b/graphene/utils/crunch.py @@ -0,0 +1,37 @@ +import json +from collections import Mapping + + +def to_key(value): + return json.dumps(value) + + +def insert(value, index, values): + key = to_key(value) + + if key not in index: + index[key] = len(values) + values.append(value) + return len(values) - 1 + + return index.get(key) + + +def flatten(data, index, values): + if isinstance(data, (list, tuple)): + flattened = [flatten(child, index, values) for child in data] + elif isinstance(data, Mapping): + flattened = { + key: flatten(child, index, values) for key, child in data.items() + } + else: + flattened = data + return insert(flattened, index, values) + + +def crunch(data): + index = {} + values = [] + + flatten(data, index, values) + return values diff --git a/graphene/utils/tests/test_crunch.py b/graphene/utils/tests/test_crunch.py new file mode 100644 index 00000000..086d0d0f --- /dev/null +++ b/graphene/utils/tests/test_crunch.py @@ -0,0 +1,40 @@ +import pytest + +from ..crunch import crunch + + +@pytest.mark.parametrize("description,uncrunched,crunched", [ + ['number primitive', 0, [0]], + ['boolean primitive', True, [True]], + ['string primitive', "string", ["string"]], + ['empty array', [], [[]]], + ['single-item array', [None], [None, [0]]], + ['multi-primitive all distinct array', [None, 0, True, "string"], [None, 0, True, "string", [0, 1, 2, 3]]], + ['multi-primitive repeated array', [True, True, True, True], [True, [0, 0, 0, 0]]], + ['one-level nested array', [[1, 2, 3]], [1, 2, 3, [0, 1, 2], [3]]], + ['two-level nested array', [[[1, 2, 3]]], [1, 2, 3, [0, 1, 2], [3], [4]]], + ['empty object', {}, [{}]], + ['single-item object', {'a': None}, [None, {'a': 0}]], + [ + 'multi-item all distinct object', + {'a': None, 'b': 0, 'c': True, 'd': "string"}, + [None, 0, True, "string", {'a': 0, 'b': 1, 'c': 2, 'd': 3}] + ], + [ + 'multi-item repeated object', + {'a': True, 'b': True, 'c': True, 'd': True}, + [True, {'a': 0, 'b': 0, 'c': 0, 'd': 0}] + ], + [ + 'complex array', + [{'a': True, 'b': [1, 2, 3]}, [1, 2, 3]], + [True, 1, 2, 3, [1, 2, 3], {'a': 0, 'b': 4}, [5, 4]] + ], + [ + 'complex object', + {'a': True, 'b': [1, 2, 3], 'c': {'a': True, 'b': [1, 2, 3]}}, + [True, 1, 2, 3, [1, 2, 3], {'a': 0, 'b': 4}, {'a': 0, 'b': 4, 'c': 5}] + ], +]) +def test_crunch(description, uncrunched, crunched): + assert crunch(uncrunched) == crunched From 9ce78e32a5db92022dfe4505a201d3d1c462e445 Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Sun, 1 Jul 2018 20:52:08 +0100 Subject: [PATCH 37/45] Remove utf-8 characters --- graphene/utils/tests/test_deduplicator.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/graphene/utils/tests/test_deduplicator.py b/graphene/utils/tests/test_deduplicator.py index dd3b54a2..d73fbfbe 100644 --- a/graphene/utils/tests/test_deduplicator.py +++ b/graphene/utils/tests/test_deduplicator.py @@ -169,8 +169,8 @@ TEST_DATA = { '1198359': { 'name': 'King Arthur: Legend of the Sword', 'synopsis': ( - "When the child Arthur’s father is murdered, Vortigern, " - "Arthur’s uncle, seizes the crown. Robbed of his birthright and " + "When the child Arthur's father is murdered, Vortigern, " + "Arthur's uncle, seizes the crown. Robbed of his birthright and " "with no idea who he truly is..." ), }, @@ -238,8 +238,8 @@ def test_example_end_to_end(): 'id': 'TW92aWU6Tm9uZQ==', 'name': 'King Arthur: Legend of the Sword', 'synopsis': ( - "When the child Arthur’s father is murdered, Vortigern, " - "Arthur’s uncle, seizes the crown. Robbed of his birthright and " + "When the child Arthur's father is murdered, Vortigern, " + "Arthur's uncle, seizes the crown. Robbed of his birthright and " "with no idea who he truly is..." ), }, From 1e40eceab3b88bb283e6ce7a5a67c0f836f669eb Mon Sep 17 00:00:00 2001 From: Jonathan Kim Date: Sun, 1 Jul 2018 21:19:19 +0100 Subject: [PATCH 38/45] Convert inputs to OrderedDicts --- graphene/utils/tests/test_crunch.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/graphene/utils/tests/test_crunch.py b/graphene/utils/tests/test_crunch.py index 086d0d0f..6dd396c6 100644 --- a/graphene/utils/tests/test_crunch.py +++ b/graphene/utils/tests/test_crunch.py @@ -1,4 +1,5 @@ import pytest +from collections import OrderedDict from ..crunch import crunch @@ -17,22 +18,29 @@ from ..crunch import crunch ['single-item object', {'a': None}, [None, {'a': 0}]], [ 'multi-item all distinct object', - {'a': None, 'b': 0, 'c': True, 'd': "string"}, + OrderedDict([('a', None), ('b', 0), ('c', True), ('d', 'string')]), [None, 0, True, "string", {'a': 0, 'b': 1, 'c': 2, 'd': 3}] ], [ 'multi-item repeated object', - {'a': True, 'b': True, 'c': True, 'd': True}, + OrderedDict([('a', True), ('b', True), ('c', True), ('d', True)]), [True, {'a': 0, 'b': 0, 'c': 0, 'd': 0}] ], [ 'complex array', - [{'a': True, 'b': [1, 2, 3]}, [1, 2, 3]], + [ + OrderedDict([('a', True), ('b', [1, 2, 3])]), + [1, 2, 3] + ], [True, 1, 2, 3, [1, 2, 3], {'a': 0, 'b': 4}, [5, 4]] ], [ 'complex object', - {'a': True, 'b': [1, 2, 3], 'c': {'a': True, 'b': [1, 2, 3]}}, + OrderedDict([ + ('a', True), + ('b', [1, 2, 3]), + ('c', OrderedDict([('a', True), ('b', [1, 2, 3])])) + ]), [True, 1, 2, 3, [1, 2, 3], {'a': 0, 'b': 4}, {'a': 0, 'b': 4, 'c': 5}] ], ]) From 9f366e93c60e1e01e635a50b8c424b93093e5ec2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Diemer?= Date: Mon, 2 Jul 2018 09:34:34 +0200 Subject: [PATCH 39/45] __wip__ add failed test Just to ease review. TODO: merge with next commit. --- graphene/types/tests/test_mutation.py | 44 +++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/graphene/types/tests/test_mutation.py b/graphene/types/tests/test_mutation.py index df17477d..6ef5a072 100644 --- a/graphene/types/tests/test_mutation.py +++ b/graphene/types/tests/test_mutation.py @@ -158,3 +158,47 @@ def test_mutation_allow_to_have_custom_args(): assert field.description == 'Create a user' assert field.deprecation_reason == 'Is deprecated' assert field.type == NonNull(CreateUser) + + +def test_mutation_as_subclass(): + class BaseCreateUser(Mutation): + + class Arguments: + name = String() + + name = String() + + def mutate(self, info, **args): + return args + + class CreateUserWithPlanet(BaseCreateUser): + + class Arguments(BaseCreateUser.Arguments): + planet = String() + + planet = String() + + def mutate(self, info, **args): + return CreateUserWithPlanet(**args) + + class MyMutation(ObjectType): + create_user_with_planet = CreateUserWithPlanet.Field() + + class Query(ObjectType): + a = String() + + schema = Schema(query=Query, mutation=MyMutation) + result = schema.execute(''' mutation mymutation { + createUserWithPlanet(name:"Peter", planet: "earth") { + name + planet + } + } + ''') + assert not result.errors + assert result.data == { + 'createUserWithPlanet': { + 'name': 'Peter', + 'planet': 'earth', + } + } From 181e75c952a3a357c4386749e09a46c547c02b74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Diemer?= Date: Fri, 29 Jun 2018 16:49:33 +0200 Subject: [PATCH 40/45] Fetch fields from parent classes in mutations The goal of this commit is to be able to subclass mutations like this: ``` class BaseMutation(graphene.Mutation): class Arguments: name = graphene.String() def mutate(self, info, **kwargs): # do something class ChildMutation(BaseMutation): class Arguments(BaseMutation.Arguments): other_arg = graphene.String() def mutate(self, info, **kwargs): # do other things ``` Note: vars(x).get(key, gettattr(x, key)) is used instead of the simpler gettatrr(x, key) for python2.7 compat. Indeed python2 and python3 lead to different results for class Foo(object): def bar(self): pass getattr(Foo, 'bar') # python 2.7 : > unbound method bar # python 3.x : > function Foo.bar --- graphene/utils/props.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphene/utils/props.py b/graphene/utils/props.py index 5162720e..5ef3ba0a 100644 --- a/graphene/utils/props.py +++ b/graphene/utils/props.py @@ -11,5 +11,5 @@ _all_vars = set(dir(_OldClass) + dir(_NewClass)) def props(x): return { - key: value for key, value in vars(x).items() if key not in _all_vars + key: vars(x).get(key, getattr(x, key)) for key in dir(x) if key not in _all_vars } From 04782a28188068a3f0e4a5cef3cf595c5e92cb81 Mon Sep 17 00:00:00 2001 From: Daniel Gallagher Date: Fri, 6 Jul 2018 11:10:41 -0700 Subject: [PATCH 41/45] Add black formatter pre-commit hook and remove isort (since black also sorts imports) --- .pre-commit-config.yaml | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index dce35cd0..37777846 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -22,11 +22,8 @@ repos: rev: v1.2.0 hooks: - id: pyupgrade -- repo: https://github.com/asottile/seed-isort-config - rev: v1.0.1 +- repo: https://github.com/ambv/black + rev: stable hooks: - - id: seed-isort-config -- repo: https://github.com/pre-commit/mirrors-isort - rev: v4.3.4 - hooks: - - id: isort + - id: black + language_version: python3.6 From bf0d23b5848d89c06b76dfd9dc840492e267b761 Mon Sep 17 00:00:00 2001 From: Daniel Gallagher Date: Fri, 6 Jul 2018 11:18:24 -0700 Subject: [PATCH 42/45] Add pyproject.toml to configure black formatter --- pyproject.toml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 pyproject.toml diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..5d75a651 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,9 @@ +# Example configuration for Black. + +# NOTE: you have to use single-quoted strings in TOML for regular expressions. +# It's the equivalent of r-strings in Python. Multiline strings are treated as +# verbose regular expressions by Black. Use [ ] to denote a significant space +# character. + +[tool.black] +skip-string-normalization = true From 71bcbb8566d39d32c0c1605c3fe15667943f9248 Mon Sep 17 00:00:00 2001 From: Daniel Gallagher Date: Fri, 6 Jul 2018 12:06:16 -0700 Subject: [PATCH 43/45] Go with base black formatter for now --- pyproject.toml | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 pyproject.toml diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index 5d75a651..00000000 --- a/pyproject.toml +++ /dev/null @@ -1,9 +0,0 @@ -# Example configuration for Black. - -# NOTE: you have to use single-quoted strings in TOML for regular expressions. -# It's the equivalent of r-strings in Python. Multiline strings are treated as -# verbose regular expressions by Black. Use [ ] to denote a significant space -# character. - -[tool.black] -skip-string-normalization = true From 086f9dda99ff0f5bf6e0ee8d7773c4c7db970f07 Mon Sep 17 00:00:00 2001 From: Daniel Gallagher Date: Fri, 6 Jul 2018 12:09:23 -0700 Subject: [PATCH 44/45] Run black formatter via pre-commit on all files --- .pre-commit-config.yaml | 5 - docs/conf.py | 105 +++--- examples/complex_example.py | 24 +- examples/context_example.py | 21 +- examples/simple_example.py | 18 +- examples/starwars/data.py | 72 ++-- examples/starwars/schema.py | 18 +- .../tests/snapshots/snap_test_query.py | 235 ++++--------- examples/starwars/tests/test_query.py | 64 ++-- examples/starwars_relay/data.py | 94 ++---- examples/starwars_relay/schema.py | 20 +- .../tests/snapshots/snap_test_connections.py | 33 +- .../tests/snapshots/snap_test_mutation.py | 65 +--- .../snap_test_objectidentification.py | 51 +-- .../starwars_relay/tests/test_connections.py | 4 +- .../starwars_relay/tests/test_mutation.py | 4 +- .../tests/test_objectidentification.py | 20 +- graphene/__init__.py | 94 +++--- graphene/pyutils/compat.py | 4 + graphene/pyutils/enum.py | 290 +++++++++------- graphene/pyutils/init_subclass.py | 12 +- graphene/pyutils/signature.py | 318 ++++++++++-------- graphene/pyutils/tests/test_enum.py | 26 +- graphene/pyutils/version.py | 33 +- graphene/relay/__init__.py | 14 +- graphene/relay/connection.py | 79 ++--- graphene/relay/mutation.py | 41 ++- graphene/relay/node.py | 33 +- graphene/relay/tests/test_connection.py | 88 +++-- graphene/relay/tests/test_connection_query.py | 162 ++++----- graphene/relay/tests/test_global_id.py | 9 +- graphene/relay/tests/test_mutation.py | 104 +++--- graphene/relay/tests/test_node.py | 63 ++-- graphene/relay/tests/test_node_custom.py | 163 ++++----- graphene/test/__init__.py | 11 +- graphene/tests/issues/test_313.py | 9 +- graphene/tests/issues/test_356.py | 3 +- graphene/tests/issues/test_425.py | 47 ++- graphene/tests/issues/test_490.py | 6 +- graphene/tests/issues/test_720.py | 12 +- graphene/types/__init__.py | 55 ++- graphene/types/argument.py | 35 +- graphene/types/base.py | 2 +- graphene/types/context.py | 1 + graphene/types/datetime.py | 30 +- graphene/types/definitions.py | 17 +- graphene/types/dynamic.py | 4 +- graphene/types/enum.py | 24 +- graphene/types/field.py | 28 +- graphene/types/generic.py | 15 +- graphene/types/inputfield.py | 14 +- graphene/types/inputobjecttype.py | 16 +- graphene/types/interface.py | 10 +- graphene/types/json.py | 2 +- graphene/types/mountedtype.py | 10 +- graphene/types/mutation.py | 45 +-- graphene/types/objecttype.py | 33 +- graphene/types/resolver.py | 2 +- graphene/types/scalars.py | 34 +- graphene/types/schema.py | 53 +-- graphene/types/structures.py | 45 ++- graphene/types/tests/test_abstracttype.py | 5 +- graphene/types/tests/test_argument.py | 37 +- graphene/types/tests/test_base.py | 18 +- graphene/types/tests/test_datetime.py | 51 +-- graphene/types/tests/test_definition.py | 94 +++--- graphene/types/tests/test_dynamic.py | 12 +- graphene/types/tests/test_enum.py | 111 +++--- graphene/types/tests/test_field.py | 64 ++-- graphene/types/tests/test_generic.py | 69 ++-- graphene/types/tests/test_inputobjecttype.py | 61 ++-- graphene/types/tests/test_interface.py | 30 +- graphene/types/tests/test_json.py | 14 +- graphene/types/tests/test_mountedtype.py | 6 +- graphene/types/tests/test_mutation.py | 66 ++-- graphene/types/tests/test_objecttype.py | 104 +++--- graphene/types/tests/test_query.py | 202 ++++++----- graphene/types/tests/test_resolver.py | 30 +- graphene/types/tests/test_scalar.py | 3 +- .../types/tests/test_scalars_serialization.py | 24 +- graphene/types/tests/test_schema.py | 7 +- graphene/types/tests/test_structures.py | 19 +- graphene/types/tests/test_typemap.py | 232 +++++++------ graphene/types/tests/test_union.py | 13 +- graphene/types/tests/test_uuid.py | 18 +- graphene/types/typemap.py | 124 ++++--- graphene/types/union.py | 15 +- graphene/types/unmountedtype.py | 35 +- graphene/types/utils.py | 8 +- graphene/types/uuid.py | 6 +- graphene/utils/annotate.py | 9 +- graphene/utils/crunch.py | 4 +- graphene/utils/deduplicator.py | 15 +- graphene/utils/deprecated.py | 16 +- graphene/utils/get_unbound_function.py | 2 +- graphene/utils/module_loading.py | 16 +- graphene/utils/props.py | 4 +- graphene/utils/resolve_only_args.py | 3 +- graphene/utils/str_converters.py | 10 +- graphene/utils/subclass_with_meta.py | 11 +- graphene/utils/tests/test_annotate.py | 12 +- graphene/utils/tests/test_crunch.py | 82 +++-- graphene/utils/tests/test_deduplicator.py | 200 ++++------- graphene/utils/tests/test_deprecated.py | 28 +- graphene/utils/tests/test_module_loading.py | 46 ++- .../utils/tests/test_resolve_only_args.py | 4 +- graphene/utils/tests/test_str_converters.py | 24 +- graphene/utils/tests/test_trim_docstring.py | 9 +- setup.py | 103 +++--- 109 files changed, 2517 insertions(+), 2508 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 37777846..153980eb 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,11 +2,6 @@ repos: - repo: git://github.com/pre-commit/pre-commit-hooks rev: v1.3.0 hooks: - - id: autopep8-wrapper - args: - - -i - - --ignore=E128,E309,E501 - exclude: ^docs/.*$ - id: check-json - id: check-yaml - id: debug-statements diff --git a/docs/conf.py b/docs/conf.py index b25a36dc..c7927ec2 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -2,7 +2,7 @@ import os import sphinx_graphene_theme -on_rtd = os.environ.get('READTHEDOCS', None) == 'True' +on_rtd = os.environ.get("READTHEDOCS", None) == "True" # -*- coding: utf-8 -*- # @@ -36,46 +36,44 @@ on_rtd = os.environ.get('READTHEDOCS', None) == 'True' # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.intersphinx', - 'sphinx.ext.todo', - 'sphinx.ext.coverage', - 'sphinx.ext.viewcode', + "sphinx.ext.autodoc", + "sphinx.ext.intersphinx", + "sphinx.ext.todo", + "sphinx.ext.coverage", + "sphinx.ext.viewcode", ] if not on_rtd: - extensions += [ - 'sphinx.ext.githubpages', - ] + extensions += ["sphinx.ext.githubpages"] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] -source_suffix = '.rst' +source_suffix = ".rst" # The encoding of source files. # # source_encoding = 'utf-8-sig' # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = u'Graphene' -copyright = u'Graphene 2016' -author = u'Syrus Akbary' +project = u"Graphene" +copyright = u"Graphene 2016" +author = u"Syrus Akbary" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = u'1.0' +version = u"1.0" # The full version, including alpha/beta/rc tags. -release = u'1.0' +release = u"1.0" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -96,7 +94,7 @@ language = None # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This patterns also effect to html_static_path and html_extra_path -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] # The reST default role (used for this markup: `text`) to use for all # documents. @@ -118,7 +116,7 @@ exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] # show_authors = False # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # A list of ignored prefixes for module index sorting. # modindex_common_prefix = [] @@ -175,7 +173,7 @@ html_theme_path = [sphinx_graphene_theme.get_html_theme_path()] # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied @@ -255,34 +253,30 @@ html_static_path = ['_static'] # html_search_scorer = 'scorer.js' # Output file base name for HTML help builder. -htmlhelp_basename = 'Graphenedoc' +htmlhelp_basename = "Graphenedoc" # -- Options for LaTeX output --------------------------------------------- latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # - # 'preamble': '', - - # Latex figure (float) alignment - # - # 'figure_align': 'htbp', + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'Graphene.tex', u'Graphene Documentation', - u'Syrus Akbary', 'manual'), + (master_doc, "Graphene.tex", u"Graphene Documentation", u"Syrus Akbary", "manual") ] # The name of an image file (relative to this directory) to place at the top of @@ -322,10 +316,7 @@ latex_documents = [ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'graphene', u'Graphene Documentation', - [author], 1) -] +man_pages = [(master_doc, "graphene", u"Graphene Documentation", [author], 1)] # If true, show URL addresses after external links. # @@ -338,9 +329,15 @@ man_pages = [ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'Graphene', u'Graphene Documentation', - author, 'Graphene', 'One line description of project.', - 'Miscellaneous'), + ( + master_doc, + "Graphene", + u"Graphene Documentation", + author, + "Graphene", + "One line description of project.", + "Miscellaneous", + ) ] # Documents to append as an appendix to all manuals. @@ -414,7 +411,7 @@ epub_copyright = copyright # epub_post_files = [] # A list of files that should not be packed into the epub file. -epub_exclude_files = ['search.html'] +epub_exclude_files = ["search.html"] # The depth of the table of contents in toc.ncx. # @@ -447,9 +444,15 @@ epub_exclude_files = ['search.html'] # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = { - 'https://docs.python.org/': None, - 'python': ('https://docs.python.org/', None), - 'graphene_django': ('http://docs.graphene-python.org/projects/django/en/latest/', None), - 'graphene_sqlalchemy': ('http://docs.graphene-python.org/projects/sqlalchemy/en/latest/', None), - 'graphene_gae': ('http://docs.graphene-python.org/projects/gae/en/latest/', None), + "https://docs.python.org/": None, + "python": ("https://docs.python.org/", None), + "graphene_django": ( + "http://docs.graphene-python.org/projects/django/en/latest/", + None, + ), + "graphene_sqlalchemy": ( + "http://docs.graphene-python.org/projects/sqlalchemy/en/latest/", + None, + ), + "graphene_gae": ("http://docs.graphene-python.org/projects/gae/en/latest/", None), } diff --git a/examples/complex_example.py b/examples/complex_example.py index c9a4bb75..18ad89b9 100644 --- a/examples/complex_example.py +++ b/examples/complex_example.py @@ -37,42 +37,34 @@ class Mutation(graphene.ObjectType): schema = graphene.Schema(query=Query, mutation=Mutation) -query = ''' +query = """ query something{ address(geo: {lat:32.2, lng:12}) { latlng } } -''' -mutation = ''' +""" +mutation = """ mutation addAddress{ createAddress(geo: {lat:32.2, lng:12}) { latlng } } -''' +""" def test_query(): result = schema.execute(query) assert not result.errors - assert result.data == { - 'address': { - 'latlng': "(32.2,12.0)", - } - } + assert result.data == {"address": {"latlng": "(32.2,12.0)"}} def test_mutation(): result = schema.execute(mutation) assert not result.errors - assert result.data == { - 'createAddress': { - 'latlng': "(32.2,12.0)", - } - } + assert result.data == {"createAddress": {"latlng": "(32.2,12.0)"}} -if __name__ == '__main__': +if __name__ == "__main__": result = schema.execute(query) - print(result.data['address']['latlng']) + print(result.data["address"]["latlng"]) diff --git a/examples/context_example.py b/examples/context_example.py index dfcf3548..5fd7647d 100644 --- a/examples/context_example.py +++ b/examples/context_example.py @@ -10,31 +10,26 @@ class Query(graphene.ObjectType): me = graphene.Field(User) def resolve_me(self, info): - return info.context['user'] + return info.context["user"] schema = graphene.Schema(query=Query) -query = ''' +query = """ query something{ me { id name } } -''' +""" def test_query(): - result = schema.execute(query, context_value={'user': User(id='1', name='Syrus')}) + result = schema.execute(query, context_value={"user": User(id="1", name="Syrus")}) assert not result.errors - assert result.data == { - 'me': { - 'id': '1', - 'name': 'Syrus', - } - } + assert result.data == {"me": {"id": "1", "name": "Syrus"}} -if __name__ == '__main__': - result = schema.execute(query, context_value={'user': User(id='X', name='Console')}) - print(result.data['me']) +if __name__ == "__main__": + result = schema.execute(query, context_value={"user": User(id="X", name="Console")}) + print(result.data["me"]) diff --git a/examples/simple_example.py b/examples/simple_example.py index 927e0962..9bff3070 100644 --- a/examples/simple_example.py +++ b/examples/simple_example.py @@ -12,11 +12,11 @@ class Query(graphene.ObjectType): patron = graphene.Field(Patron) def resolve_patron(self, info): - return Patron(id=1, name='Syrus', age=27) + return Patron(id=1, name="Syrus", age=27) schema = graphene.Schema(query=Query) -query = ''' +query = """ query something{ patron { id @@ -24,21 +24,15 @@ query = ''' age } } -''' +""" def test_query(): result = schema.execute(query) assert not result.errors - assert result.data == { - 'patron': { - 'id': '1', - 'name': 'Syrus', - 'age': 27, - } - } + assert result.data == {"patron": {"id": "1", "name": "Syrus", "age": 27}} -if __name__ == '__main__': +if __name__ == "__main__": result = schema.execute(query) - print(result.data['patron']) + print(result.data["patron"]) diff --git a/examples/starwars/data.py b/examples/starwars/data.py index 90a96331..6c68b85c 100644 --- a/examples/starwars/data.py +++ b/examples/starwars/data.py @@ -4,75 +4,73 @@ droid_data = {} def setup(): from .schema import Human, Droid + global human_data, droid_data luke = Human( - id='1000', - name='Luke Skywalker', - friends=['1002', '1003', '2000', '2001'], + id="1000", + name="Luke Skywalker", + friends=["1002", "1003", "2000", "2001"], appears_in=[4, 5, 6], - home_planet='Tatooine', + home_planet="Tatooine", ) vader = Human( - id='1001', - name='Darth Vader', - friends=['1004'], + id="1001", + name="Darth Vader", + friends=["1004"], appears_in=[4, 5, 6], - home_planet='Tatooine', + home_planet="Tatooine", ) han = Human( - id='1002', - name='Han Solo', - friends=['1000', '1003', '2001'], + id="1002", + name="Han Solo", + friends=["1000", "1003", "2001"], appears_in=[4, 5, 6], home_planet=None, ) leia = Human( - id='1003', - name='Leia Organa', - friends=['1000', '1002', '2000', '2001'], + id="1003", + name="Leia Organa", + friends=["1000", "1002", "2000", "2001"], appears_in=[4, 5, 6], - home_planet='Alderaan', + home_planet="Alderaan", ) tarkin = Human( - id='1004', - name='Wilhuff Tarkin', - friends=['1001'], + id="1004", + name="Wilhuff Tarkin", + friends=["1001"], appears_in=[4], home_planet=None, ) human_data = { - '1000': luke, - '1001': vader, - '1002': han, - '1003': leia, - '1004': tarkin, + "1000": luke, + "1001": vader, + "1002": han, + "1003": leia, + "1004": tarkin, } c3po = Droid( - id='2000', - name='C-3PO', - friends=['1000', '1002', '1003', '2001'], + id="2000", + name="C-3PO", + friends=["1000", "1002", "1003", "2001"], appears_in=[4, 5, 6], - primary_function='Protocol', + primary_function="Protocol", ) r2d2 = Droid( - id='2001', - name='R2-D2', - friends=['1000', '1002', '1003'], + id="2001", + name="R2-D2", + friends=["1000", "1002", "1003"], appears_in=[4, 5, 6], - primary_function='Astromech', + primary_function="Astromech", ) - droid_data = { - '2000': c3po, - '2001': r2d2, - } + droid_data = {"2000": c3po, "2001": r2d2} def get_character(id): @@ -85,8 +83,8 @@ def get_friends(character): def get_hero(episode): if episode == 5: - return human_data['1000'] - return droid_data['2001'] + return human_data["1000"] + return droid_data["2001"] def get_human(id): diff --git a/examples/starwars/schema.py b/examples/starwars/schema.py index a19a7b31..b4182949 100644 --- a/examples/starwars/schema.py +++ b/examples/starwars/schema.py @@ -23,27 +23,23 @@ class Character(graphene.Interface): class Human(graphene.ObjectType): class Meta: - interfaces = (Character, ) + interfaces = (Character,) + home_planet = graphene.String() class Droid(graphene.ObjectType): class Meta: - interfaces = (Character, ) + interfaces = (Character,) + primary_function = graphene.String() class Query(graphene.ObjectType): - hero = graphene.Field(Character, - episode=Episode() - ) - human = graphene.Field(Human, - id=graphene.String() - ) - droid = graphene.Field(Droid, - id=graphene.String() - ) + hero = graphene.Field(Character, episode=Episode()) + human = graphene.Field(Human, id=graphene.String()) + droid = graphene.Field(Droid, id=graphene.String()) def resolve_hero(self, info, episode=None): return get_hero(episode) diff --git a/examples/starwars/tests/snapshots/snap_test_query.py b/examples/starwars/tests/snapshots/snap_test_query.py index 51e7b37f..b4f05bdb 100644 --- a/examples/starwars/tests/snapshots/snap_test_query.py +++ b/examples/starwars/tests/snapshots/snap_test_query.py @@ -6,196 +6,95 @@ from snapshottest import Snapshot snapshots = Snapshot() -snapshots['test_hero_name_query 1'] = { - 'data': { - 'hero': { - 'name': 'R2-D2' +snapshots["test_hero_name_query 1"] = {"data": {"hero": {"name": "R2-D2"}}} + +snapshots["test_hero_name_and_friends_query 1"] = { + "data": { + "hero": { + "id": "2001", + "name": "R2-D2", + "friends": [ + {"name": "Luke Skywalker"}, + {"name": "Han Solo"}, + {"name": "Leia Organa"}, + ], } } } -snapshots['test_hero_name_and_friends_query 1'] = { - 'data': { - 'hero': { - 'id': '2001', - 'name': 'R2-D2', - 'friends': [ +snapshots["test_nested_query 1"] = { + "data": { + "hero": { + "name": "R2-D2", + "friends": [ { - 'name': 'Luke Skywalker' - }, - { - 'name': 'Han Solo' - }, - { - 'name': 'Leia Organa' - } - ] - } - } -} - -snapshots['test_nested_query 1'] = { - 'data': { - 'hero': { - 'name': 'R2-D2', - 'friends': [ - { - 'name': 'Luke Skywalker', - 'appearsIn': [ - 'NEWHOPE', - 'EMPIRE', - 'JEDI' + "name": "Luke Skywalker", + "appearsIn": ["NEWHOPE", "EMPIRE", "JEDI"], + "friends": [ + {"name": "Han Solo"}, + {"name": "Leia Organa"}, + {"name": "C-3PO"}, + {"name": "R2-D2"}, ], - 'friends': [ - { - 'name': 'Han Solo' - }, - { - 'name': 'Leia Organa' - }, - { - 'name': 'C-3PO' - }, - { - 'name': 'R2-D2' - } - ] }, { - 'name': 'Han Solo', - 'appearsIn': [ - 'NEWHOPE', - 'EMPIRE', - 'JEDI' + "name": "Han Solo", + "appearsIn": ["NEWHOPE", "EMPIRE", "JEDI"], + "friends": [ + {"name": "Luke Skywalker"}, + {"name": "Leia Organa"}, + {"name": "R2-D2"}, ], - 'friends': [ - { - 'name': 'Luke Skywalker' - }, - { - 'name': 'Leia Organa' - }, - { - 'name': 'R2-D2' - } - ] }, { - 'name': 'Leia Organa', - 'appearsIn': [ - 'NEWHOPE', - 'EMPIRE', - 'JEDI' + "name": "Leia Organa", + "appearsIn": ["NEWHOPE", "EMPIRE", "JEDI"], + "friends": [ + {"name": "Luke Skywalker"}, + {"name": "Han Solo"}, + {"name": "C-3PO"}, + {"name": "R2-D2"}, ], - 'friends': [ - { - 'name': 'Luke Skywalker' - }, - { - 'name': 'Han Solo' - }, - { - 'name': 'C-3PO' - }, - { - 'name': 'R2-D2' - } - ] - } - ] + }, + ], } } } -snapshots['test_fetch_luke_query 1'] = { - 'data': { - 'human': { - 'name': 'Luke Skywalker' - } +snapshots["test_fetch_luke_query 1"] = {"data": {"human": {"name": "Luke Skywalker"}}} + +snapshots["test_fetch_some_id_query 1"] = { + "data": {"human": {"name": "Luke Skywalker"}} +} + +snapshots["test_fetch_some_id_query2 1"] = {"data": {"human": {"name": "Han Solo"}}} + +snapshots["test_invalid_id_query 1"] = {"data": {"human": None}} + +snapshots["test_fetch_luke_aliased 1"] = {"data": {"luke": {"name": "Luke Skywalker"}}} + +snapshots["test_fetch_luke_and_leia_aliased 1"] = { + "data": {"luke": {"name": "Luke Skywalker"}, "leia": {"name": "Leia Organa"}} +} + +snapshots["test_duplicate_fields 1"] = { + "data": { + "luke": {"name": "Luke Skywalker", "homePlanet": "Tatooine"}, + "leia": {"name": "Leia Organa", "homePlanet": "Alderaan"}, } } -snapshots['test_fetch_some_id_query 1'] = { - 'data': { - 'human': { - 'name': 'Luke Skywalker' - } +snapshots["test_use_fragment 1"] = { + "data": { + "luke": {"name": "Luke Skywalker", "homePlanet": "Tatooine"}, + "leia": {"name": "Leia Organa", "homePlanet": "Alderaan"}, } } -snapshots['test_fetch_some_id_query2 1'] = { - 'data': { - 'human': { - 'name': 'Han Solo' - } - } +snapshots["test_check_type_of_r2 1"] = { + "data": {"hero": {"__typename": "Droid", "name": "R2-D2"}} } -snapshots['test_invalid_id_query 1'] = { - 'data': { - 'human': None - } -} - -snapshots['test_fetch_luke_aliased 1'] = { - 'data': { - 'luke': { - 'name': 'Luke Skywalker' - } - } -} - -snapshots['test_fetch_luke_and_leia_aliased 1'] = { - 'data': { - 'luke': { - 'name': 'Luke Skywalker' - }, - 'leia': { - 'name': 'Leia Organa' - } - } -} - -snapshots['test_duplicate_fields 1'] = { - 'data': { - 'luke': { - 'name': 'Luke Skywalker', - 'homePlanet': 'Tatooine' - }, - 'leia': { - 'name': 'Leia Organa', - 'homePlanet': 'Alderaan' - } - } -} - -snapshots['test_use_fragment 1'] = { - 'data': { - 'luke': { - 'name': 'Luke Skywalker', - 'homePlanet': 'Tatooine' - }, - 'leia': { - 'name': 'Leia Organa', - 'homePlanet': 'Alderaan' - } - } -} - -snapshots['test_check_type_of_r2 1'] = { - 'data': { - 'hero': { - '__typename': 'Droid', - 'name': 'R2-D2' - } - } -} - -snapshots['test_check_type_of_luke 1'] = { - 'data': { - 'hero': { - '__typename': 'Human', - 'name': 'Luke Skywalker' - } - } +snapshots["test_check_type_of_luke 1"] = { + "data": {"hero": {"__typename": "Human", "name": "Luke Skywalker"}} } diff --git a/examples/starwars/tests/test_query.py b/examples/starwars/tests/test_query.py index d88076a5..b26374b6 100644 --- a/examples/starwars/tests/test_query.py +++ b/examples/starwars/tests/test_query.py @@ -9,18 +9,18 @@ client = Client(schema) def test_hero_name_query(snapshot): - query = ''' + query = """ query HeroNameQuery { hero { name } } - ''' + """ snapshot.assert_match(client.execute(query)) def test_hero_name_and_friends_query(snapshot): - query = ''' + query = """ query HeroNameAndFriendsQuery { hero { id @@ -30,12 +30,12 @@ def test_hero_name_and_friends_query(snapshot): } } } - ''' + """ snapshot.assert_match(client.execute(query)) def test_nested_query(snapshot): - query = ''' + query = """ query NestedQuery { hero { name @@ -48,76 +48,70 @@ def test_nested_query(snapshot): } } } - ''' + """ snapshot.assert_match(client.execute(query)) def test_fetch_luke_query(snapshot): - query = ''' + query = """ query FetchLukeQuery { human(id: "1000") { name } } - ''' + """ snapshot.assert_match(client.execute(query)) def test_fetch_some_id_query(snapshot): - query = ''' + query = """ query FetchSomeIDQuery($someId: String!) { human(id: $someId) { name } } - ''' - params = { - 'someId': '1000', - } + """ + params = {"someId": "1000"} snapshot.assert_match(client.execute(query, variable_values=params)) def test_fetch_some_id_query2(snapshot): - query = ''' + query = """ query FetchSomeIDQuery($someId: String!) { human(id: $someId) { name } } - ''' - params = { - 'someId': '1002', - } + """ + params = {"someId": "1002"} snapshot.assert_match(client.execute(query, variable_values=params)) def test_invalid_id_query(snapshot): - query = ''' + query = """ query humanQuery($id: String!) { human(id: $id) { name } } - ''' - params = { - 'id': 'not a valid id', - } + """ + params = {"id": "not a valid id"} snapshot.assert_match(client.execute(query, variable_values=params)) def test_fetch_luke_aliased(snapshot): - query = ''' + query = """ query FetchLukeAliased { luke: human(id: "1000") { name } } - ''' + """ snapshot.assert_match(client.execute(query)) def test_fetch_luke_and_leia_aliased(snapshot): - query = ''' + query = """ query FetchLukeAndLeiaAliased { luke: human(id: "1000") { name @@ -126,12 +120,12 @@ def test_fetch_luke_and_leia_aliased(snapshot): name } } - ''' + """ snapshot.assert_match(client.execute(query)) def test_duplicate_fields(snapshot): - query = ''' + query = """ query DuplicateFields { luke: human(id: "1000") { name @@ -142,12 +136,12 @@ def test_duplicate_fields(snapshot): homePlanet } } - ''' + """ snapshot.assert_match(client.execute(query)) def test_use_fragment(snapshot): - query = ''' + query = """ query UseFragment { luke: human(id: "1000") { ...HumanFragment @@ -160,29 +154,29 @@ def test_use_fragment(snapshot): name homePlanet } - ''' + """ snapshot.assert_match(client.execute(query)) def test_check_type_of_r2(snapshot): - query = ''' + query = """ query CheckTypeOfR2 { hero { __typename name } } - ''' + """ snapshot.assert_match(client.execute(query)) def test_check_type_of_luke(snapshot): - query = ''' + query = """ query CheckTypeOfLuke { hero(episode: EMPIRE) { __typename name } } - ''' + """ snapshot.assert_match(client.execute(query)) diff --git a/examples/starwars_relay/data.py b/examples/starwars_relay/data.py index cb451deb..01231b7f 100644 --- a/examples/starwars_relay/data.py +++ b/examples/starwars_relay/data.py @@ -5,101 +5,67 @@ def setup(): global data from .schema import Ship, Faction - xwing = Ship( - id='1', - name='X-Wing', - ) - ywing = Ship( - id='2', - name='Y-Wing', - ) + xwing = Ship(id="1", name="X-Wing") - awing = Ship( - id='3', - name='A-Wing', - ) + ywing = Ship(id="2", name="Y-Wing") + + awing = Ship(id="3", name="A-Wing") # Yeah, technically it's Corellian. But it flew in the service of the rebels, # so for the purposes of this demo it's a rebel ship. - falcon = Ship( - id='4', - name='Millenium Falcon', - ) + falcon = Ship(id="4", name="Millenium Falcon") - homeOne = Ship( - id='5', - name='Home One', - ) + homeOne = Ship(id="5", name="Home One") - tieFighter = Ship( - id='6', - name='TIE Fighter', - ) + tieFighter = Ship(id="6", name="TIE Fighter") - tieInterceptor = Ship( - id='7', - name='TIE Interceptor', - ) + tieInterceptor = Ship(id="7", name="TIE Interceptor") - executor = Ship( - id='8', - name='Executor', - ) + executor = Ship(id="8", name="Executor") rebels = Faction( - id='1', - name='Alliance to Restore the Republic', - ships=['1', '2', '3', '4', '5'] + id="1", name="Alliance to Restore the Republic", ships=["1", "2", "3", "4", "5"] ) - empire = Faction( - id='2', - name='Galactic Empire', - ships=['6', '7', '8'] - ) + empire = Faction(id="2", name="Galactic Empire", ships=["6", "7", "8"]) data = { - 'Faction': { - '1': rebels, - '2': empire + "Faction": {"1": rebels, "2": empire}, + "Ship": { + "1": xwing, + "2": ywing, + "3": awing, + "4": falcon, + "5": homeOne, + "6": tieFighter, + "7": tieInterceptor, + "8": executor, }, - 'Ship': { - '1': xwing, - '2': ywing, - '3': awing, - '4': falcon, - '5': homeOne, - '6': tieFighter, - '7': tieInterceptor, - '8': executor - } } def create_ship(ship_name, faction_id): from .schema import Ship - next_ship = len(data['Ship'].keys()) + 1 - new_ship = Ship( - id=str(next_ship), - name=ship_name - ) - data['Ship'][new_ship.id] = new_ship - data['Faction'][faction_id].ships.append(new_ship.id) + + next_ship = len(data["Ship"].keys()) + 1 + new_ship = Ship(id=str(next_ship), name=ship_name) + data["Ship"][new_ship.id] = new_ship + data["Faction"][faction_id].ships.append(new_ship.id) return new_ship def get_ship(_id): - return data['Ship'][_id] + return data["Ship"][_id] def get_faction(_id): - return data['Faction'][_id] + return data["Faction"][_id] def get_rebels(): - return get_faction('1') + return get_faction("1") def get_empire(): - return get_faction('2') + return get_faction("2") diff --git a/examples/starwars_relay/schema.py b/examples/starwars_relay/schema.py index beb291c3..f3ebb09d 100644 --- a/examples/starwars_relay/schema.py +++ b/examples/starwars_relay/schema.py @@ -5,12 +5,12 @@ from .data import create_ship, get_empire, get_faction, get_rebels, get_ship class Ship(graphene.ObjectType): - '''A ship in the Star Wars saga''' + """A ship in the Star Wars saga""" class Meta: - interfaces = (relay.Node, ) + interfaces = (relay.Node,) - name = graphene.String(description='The name of the ship.') + name = graphene.String(description="The name of the ship.") @classmethod def get_node(cls, info, id): @@ -24,13 +24,15 @@ class ShipConnection(relay.Connection): class Faction(graphene.ObjectType): - '''A faction in the Star Wars saga''' + """A faction in the Star Wars saga""" class Meta: - interfaces = (relay.Node, ) + interfaces = (relay.Node,) - name = graphene.String(description='The name of the faction.') - ships = relay.ConnectionField(ShipConnection, description='The ships used by the faction.') + name = graphene.String(description="The name of the faction.") + ships = relay.ConnectionField( + ShipConnection, description="The ships used by the faction." + ) def resolve_ships(self, info, **args): # Transform the instance ship_ids into real instances @@ -51,7 +53,9 @@ class IntroduceShip(relay.ClientIDMutation): faction = graphene.Field(Faction) @classmethod - def mutate_and_get_payload(cls, root, info, ship_name, faction_id, client_mutation_id=None): + def mutate_and_get_payload( + cls, root, info, ship_name, faction_id, client_mutation_id=None + ): ship = create_ship(ship_name, faction_id) faction = get_faction(faction_id) return IntroduceShip(ship=ship, faction=faction) diff --git a/examples/starwars_relay/tests/snapshots/snap_test_connections.py b/examples/starwars_relay/tests/snapshots/snap_test_connections.py index d2dff773..57a7b7ea 100644 --- a/examples/starwars_relay/tests/snapshots/snap_test_connections.py +++ b/examples/starwars_relay/tests/snapshots/snap_test_connections.py @@ -6,26 +6,21 @@ from snapshottest import Snapshot snapshots = Snapshot() -snapshots['test_correct_fetch_first_ship_rebels 1'] = { - 'data': { - 'rebels': { - 'name': 'Alliance to Restore the Republic', - 'ships': { - 'pageInfo': { - 'startCursor': 'YXJyYXljb25uZWN0aW9uOjA=', - 'endCursor': 'YXJyYXljb25uZWN0aW9uOjA=', - 'hasNextPage': True, - 'hasPreviousPage': False +snapshots["test_correct_fetch_first_ship_rebels 1"] = { + "data": { + "rebels": { + "name": "Alliance to Restore the Republic", + "ships": { + "pageInfo": { + "startCursor": "YXJyYXljb25uZWN0aW9uOjA=", + "endCursor": "YXJyYXljb25uZWN0aW9uOjA=", + "hasNextPage": True, + "hasPreviousPage": False, }, - 'edges': [ - { - 'cursor': 'YXJyYXljb25uZWN0aW9uOjA=', - 'node': { - 'name': 'X-Wing' - } - } - ] - } + "edges": [ + {"cursor": "YXJyYXljb25uZWN0aW9uOjA=", "node": {"name": "X-Wing"}} + ], + }, } } } diff --git a/examples/starwars_relay/tests/snapshots/snap_test_mutation.py b/examples/starwars_relay/tests/snapshots/snap_test_mutation.py index 8fff150b..4608bdaf 100644 --- a/examples/starwars_relay/tests/snapshots/snap_test_mutation.py +++ b/examples/starwars_relay/tests/snapshots/snap_test_mutation.py @@ -6,56 +6,23 @@ from snapshottest import Snapshot snapshots = Snapshot() -snapshots['test_mutations 1'] = { - 'data': { - 'introduceShip': { - 'ship': { - 'id': 'U2hpcDo5', - 'name': 'Peter' - }, - 'faction': { - 'name': 'Alliance to Restore the Republic', - 'ships': { - 'edges': [ - { - 'node': { - 'id': 'U2hpcDox', - 'name': 'X-Wing' - } - }, - { - 'node': { - 'id': 'U2hpcDoy', - 'name': 'Y-Wing' - } - }, - { - 'node': { - 'id': 'U2hpcDoz', - 'name': 'A-Wing' - } - }, - { - 'node': { - 'id': 'U2hpcDo0', - 'name': 'Millenium Falcon' - } - }, - { - 'node': { - 'id': 'U2hpcDo1', - 'name': 'Home One' - } - }, - { - 'node': { - 'id': 'U2hpcDo5', - 'name': 'Peter' - } - } +snapshots["test_mutations 1"] = { + "data": { + "introduceShip": { + "ship": {"id": "U2hpcDo5", "name": "Peter"}, + "faction": { + "name": "Alliance to Restore the Republic", + "ships": { + "edges": [ + {"node": {"id": "U2hpcDox", "name": "X-Wing"}}, + {"node": {"id": "U2hpcDoy", "name": "Y-Wing"}}, + {"node": {"id": "U2hpcDoz", "name": "A-Wing"}}, + {"node": {"id": "U2hpcDo0", "name": "Millenium Falcon"}}, + {"node": {"id": "U2hpcDo1", "name": "Home One"}}, + {"node": {"id": "U2hpcDo5", "name": "Peter"}}, ] - } - } + }, + }, } } } diff --git a/examples/starwars_relay/tests/snapshots/snap_test_objectidentification.py b/examples/starwars_relay/tests/snapshots/snap_test_objectidentification.py index 1682f2de..2d13cba3 100644 --- a/examples/starwars_relay/tests/snapshots/snap_test_objectidentification.py +++ b/examples/starwars_relay/tests/snapshots/snap_test_objectidentification.py @@ -6,52 +6,31 @@ from snapshottest import Snapshot snapshots = Snapshot() -snapshots['test_correctly_fetches_id_name_rebels 1'] = { - 'data': { - 'rebels': { - 'id': 'RmFjdGlvbjox', - 'name': 'Alliance to Restore the Republic' - } +snapshots["test_correctly_fetches_id_name_rebels 1"] = { + "data": { + "rebels": {"id": "RmFjdGlvbjox", "name": "Alliance to Restore the Republic"} } } -snapshots['test_correctly_refetches_rebels 1'] = { - 'data': { - 'node': { - 'id': 'RmFjdGlvbjox', - 'name': 'Alliance to Restore the Republic' - } - } +snapshots["test_correctly_refetches_rebels 1"] = { + "data": {"node": {"id": "RmFjdGlvbjox", "name": "Alliance to Restore the Republic"}} } -snapshots['test_correctly_fetches_id_name_empire 1'] = { - 'data': { - 'empire': { - 'id': 'RmFjdGlvbjoy', - 'name': 'Galactic Empire' - } - } +snapshots["test_correctly_fetches_id_name_empire 1"] = { + "data": {"empire": {"id": "RmFjdGlvbjoy", "name": "Galactic Empire"}} } -snapshots['test_correctly_refetches_empire 1'] = { - 'data': { - 'node': { - 'id': 'RmFjdGlvbjoy', - 'name': 'Galactic Empire' - } - } +snapshots["test_correctly_refetches_empire 1"] = { + "data": {"node": {"id": "RmFjdGlvbjoy", "name": "Galactic Empire"}} } -snapshots['test_correctly_refetches_xwing 1'] = { - 'data': { - 'node': { - 'id': 'U2hpcDox', - 'name': 'X-Wing' - } - } +snapshots["test_correctly_refetches_xwing 1"] = { + "data": {"node": {"id": "U2hpcDox", "name": "X-Wing"}} } -snapshots['test_str_schema 1'] = '''schema { +snapshots[ + "test_str_schema 1" +] = """schema { query: Query mutation: Mutation } @@ -109,4 +88,4 @@ type ShipEdge { node: Ship cursor: String! } -''' +""" diff --git a/examples/starwars_relay/tests/test_connections.py b/examples/starwars_relay/tests/test_connections.py index bf26c0ec..697796d1 100644 --- a/examples/starwars_relay/tests/test_connections.py +++ b/examples/starwars_relay/tests/test_connections.py @@ -9,7 +9,7 @@ client = Client(schema) def test_correct_fetch_first_ship_rebels(snapshot): - query = ''' + query = """ query RebelsShipsQuery { rebels { name, @@ -29,5 +29,5 @@ def test_correct_fetch_first_ship_rebels(snapshot): } } } - ''' + """ snapshot.assert_match(client.execute(query)) diff --git a/examples/starwars_relay/tests/test_mutation.py b/examples/starwars_relay/tests/test_mutation.py index fb4ab7ad..e3ba7fe6 100644 --- a/examples/starwars_relay/tests/test_mutation.py +++ b/examples/starwars_relay/tests/test_mutation.py @@ -9,7 +9,7 @@ client = Client(schema) def test_mutations(snapshot): - query = ''' + query = """ mutation MyMutation { introduceShip(input:{clientMutationId:"abc", shipName: "Peter", factionId: "1"}) { ship { @@ -29,5 +29,5 @@ def test_mutations(snapshot): } } } - ''' + """ snapshot.assert_match(client.execute(query)) diff --git a/examples/starwars_relay/tests/test_objectidentification.py b/examples/starwars_relay/tests/test_objectidentification.py index 28a5decb..f280df04 100644 --- a/examples/starwars_relay/tests/test_objectidentification.py +++ b/examples/starwars_relay/tests/test_objectidentification.py @@ -13,19 +13,19 @@ def test_str_schema(snapshot): def test_correctly_fetches_id_name_rebels(snapshot): - query = ''' + query = """ query RebelsQuery { rebels { id name } } - ''' + """ snapshot.assert_match(client.execute(query)) def test_correctly_refetches_rebels(snapshot): - query = ''' + query = """ query RebelsRefetchQuery { node(id: "RmFjdGlvbjox") { id @@ -34,24 +34,24 @@ def test_correctly_refetches_rebels(snapshot): } } } - ''' + """ snapshot.assert_match(client.execute(query)) def test_correctly_fetches_id_name_empire(snapshot): - query = ''' + query = """ query EmpireQuery { empire { id name } } - ''' + """ snapshot.assert_match(client.execute(query)) def test_correctly_refetches_empire(snapshot): - query = ''' + query = """ query EmpireRefetchQuery { node(id: "RmFjdGlvbjoy") { id @@ -60,12 +60,12 @@ def test_correctly_refetches_empire(snapshot): } } } - ''' + """ snapshot.assert_match(client.execute(query)) def test_correctly_refetches_xwing(snapshot): - query = ''' + query = """ query XWingRefetchQuery { node(id: "U2hpcDox") { id @@ -74,5 +74,5 @@ def test_correctly_refetches_xwing(snapshot): } } } - ''' + """ snapshot.assert_match(client.execute(query)) diff --git a/graphene/__init__.py b/graphene/__init__.py index 30f89a46..9437e3de 100644 --- a/graphene/__init__.py +++ b/graphene/__init__.py @@ -10,17 +10,24 @@ from .types import ( InputField, Schema, Scalar, - String, ID, Int, Float, Boolean, - Date, DateTime, Time, + String, + ID, + Int, + Float, + Boolean, + Date, + DateTime, + Time, JSONString, UUID, - List, NonNull, + List, + NonNull, Enum, Argument, Dynamic, Union, Context, - ResolveInfo + ResolveInfo, ) from .relay import ( Node, @@ -29,54 +36,53 @@ from .relay import ( ClientIDMutation, Connection, ConnectionField, - PageInfo + PageInfo, ) from .utils.resolve_only_args import resolve_only_args from .utils.module_loading import lazy_import -VERSION = (2, 1, 2, 'final', 0) +VERSION = (2, 1, 2, "final", 0) __version__ = get_version(VERSION) __all__ = [ - '__version__', - 'ObjectType', - 'InputObjectType', - 'Interface', - 'Mutation', - 'Field', - 'InputField', - 'Schema', - 'Scalar', - 'String', - 'ID', - 'Int', - 'Float', - 'Enum', - 'Boolean', - 'Date', - 'DateTime', - 'Time', - 'JSONString', - 'UUID', - 'List', - 'NonNull', - 'Argument', - 'Dynamic', - 'Union', - 'resolve_only_args', - 'Node', - 'is_node', - 'GlobalID', - 'ClientIDMutation', - 'Connection', - 'ConnectionField', - 'PageInfo', - 'lazy_import', - 'Context', - 'ResolveInfo', - + "__version__", + "ObjectType", + "InputObjectType", + "Interface", + "Mutation", + "Field", + "InputField", + "Schema", + "Scalar", + "String", + "ID", + "Int", + "Float", + "Enum", + "Boolean", + "Date", + "DateTime", + "Time", + "JSONString", + "UUID", + "List", + "NonNull", + "Argument", + "Dynamic", + "Union", + "resolve_only_args", + "Node", + "is_node", + "GlobalID", + "ClientIDMutation", + "Connection", + "ConnectionField", + "PageInfo", + "lazy_import", + "Context", + "ResolveInfo", # Deprecated - 'AbstractType', + "AbstractType", ] diff --git a/graphene/pyutils/compat.py b/graphene/pyutils/compat.py index ef27f356..661d4543 100644 --- a/graphene/pyutils/compat.py +++ b/graphene/pyutils/compat.py @@ -13,8 +13,12 @@ except ImportError: from .signature import signature if six.PY2: + def func_name(func): return func.func_name + + else: + def func_name(func): return func.__name__ diff --git a/graphene/pyutils/enum.py b/graphene/pyutils/enum.py index f3421d9f..6ce91b23 100644 --- a/graphene/pyutils/enum.py +++ b/graphene/pyutils/enum.py @@ -2,21 +2,23 @@ import sys as _sys -__all__ = ['Enum', 'IntEnum', 'unique'] +__all__ = ["Enum", "IntEnum", "unique"] version = 1, 1, 6 -pyver = float('%s.%s' % _sys.version_info[:2]) +pyver = float("%s.%s" % _sys.version_info[:2]) try: any except NameError: + def any(iterable): for element in iterable: if element: return True return False + try: from collections import OrderedDict except ImportError: @@ -64,34 +66,38 @@ class _RouteClassAttributeToGetattr(object): def _is_descriptor(obj): """Returns True if obj is a descriptor, False otherwise.""" return ( - hasattr(obj, '__get__') or - hasattr(obj, '__set__') or - hasattr(obj, '__delete__')) + hasattr(obj, "__get__") or hasattr(obj, "__set__") or hasattr(obj, "__delete__") + ) def _is_dunder(name): """Returns True if a __dunder__ name, False otherwise.""" - return (len(name) > 4 and - name[:2] == name[-2:] == '__' and - name[2:3] != '_' and - name[-3:-2] != '_') + return ( + len(name) > 4 + and name[:2] == name[-2:] == "__" + and name[2:3] != "_" + and name[-3:-2] != "_" + ) def _is_sunder(name): """Returns True if a _sunder_ name, False otherwise.""" - return (len(name) > 2 and - name[0] == name[-1] == '_' and - name[1:2] != '_' and - name[-2:-1] != '_') + return ( + len(name) > 2 + and name[0] == name[-1] == "_" + and name[1:2] != "_" + and name[-2:-1] != "_" + ) def _make_class_unpicklable(cls): """Make the given class un-picklable.""" def _break_on_call_reduce(self, protocol=None): - raise TypeError('%r cannot be pickled' % self) + raise TypeError("%r cannot be pickled" % self) + cls.__reduce_ex__ = _break_on_call_reduce - cls.__module__ = '' + cls.__module__ = "" class _EnumDict(OrderedDict): @@ -122,22 +128,22 @@ class _EnumDict(OrderedDict): leftover from 2.x """ - if pyver >= 3.0 and key in ('_order_', '__order__'): + if pyver >= 3.0 and key in ("_order_", "__order__"): return - elif key == '__order__': - key = '_order_' + elif key == "__order__": + key = "_order_" if _is_sunder(key): - if key != '_order_': - raise ValueError('_names_ are reserved for future Enum use') + if key != "_order_": + raise ValueError("_names_ are reserved for future Enum use") elif _is_dunder(key): pass elif key in self._member_names: # descriptor overwriting an enum? - raise TypeError('Attempted to reuse key: %r' % key) + raise TypeError("Attempted to reuse key: %r" % key) elif not _is_descriptor(value): if key in self: # enum overwriting a descriptor? - raise TypeError('Key already defined as: %r' % self[key]) + raise TypeError("Key already defined as: %r" % self[key]) self._member_names.append(key) super(_EnumDict, self).__setitem__(key, value) @@ -150,6 +156,7 @@ Enum = None class EnumMeta(type): """Metaclass for Enum""" + @classmethod def __prepare__(metacls, cls, bases): return _EnumDict() @@ -166,8 +173,9 @@ class EnumMeta(type): classdict[k] = v member_type, first_enum = metacls._get_mixins_(bases) - __new__, save_new, use_args = metacls._find_new_(classdict, member_type, - first_enum) + __new__, save_new, use_args = metacls._find_new_( + classdict, member_type, first_enum + ) # save enum items into separate mapping so they don't get baked into # the new class members = {k: classdict[k] for k in classdict._member_names} @@ -175,38 +183,44 @@ class EnumMeta(type): del classdict[name] # py2 support for definition order - _order_ = classdict.get('_order_') + _order_ = classdict.get("_order_") if _order_ is None: if pyver < 3.0: try: - _order_ = [name for (name, value) in sorted(members.items(), key=lambda item: item[1])] + _order_ = [ + name + for (name, value) in sorted( + members.items(), key=lambda item: item[1] + ) + ] except TypeError: _order_ = [name for name in sorted(members.keys())] else: _order_ = classdict._member_names else: - del classdict['_order_'] + del classdict["_order_"] if pyver < 3.0: - _order_ = _order_.replace(',', ' ').split() + _order_ = _order_.replace(",", " ").split() aliases = [name for name in members if name not in _order_] _order_ += aliases # check for illegal enum names (any others?) - invalid_names = set(members) & {'mro'} + invalid_names = set(members) & {"mro"} if invalid_names: - raise ValueError('Invalid enum member name(s): %s' % ( - ', '.join(invalid_names), )) + raise ValueError( + "Invalid enum member name(s): %s" % (", ".join(invalid_names),) + ) # save attributes from super classes so we know if we can take # the shortcut of storing members in the class dict base_attributes = {a for b in bases for a in b.__dict__} # create our new Enum type enum_class = super(EnumMeta, metacls).__new__(metacls, cls, bases, classdict) - enum_class._member_names_ = [] # names in random order + enum_class._member_names_ = [] # names in random order if OrderedDict is not None: enum_class._member_map_ = OrderedDict() else: - enum_class._member_map_ = {} # name->value map + enum_class._member_map_ = {} # name->value map enum_class._member_type_ = member_type # Reverse value->name map for hashable values. @@ -221,18 +235,18 @@ class EnumMeta(type): for member_name in _order_: value = members[member_name] if not isinstance(value, tuple): - args = (value, ) + args = (value,) else: args = value - if member_type is tuple: # special case for tuple enums - args = (args, ) # wrap it one more time + if member_type is tuple: # special case for tuple enums + args = (args,) # wrap it one more time if not use_args or not args: enum_member = __new__(enum_class) - if not hasattr(enum_member, '_value_'): + if not hasattr(enum_member, "_value_"): enum_member._value_ = value else: enum_member = __new__(enum_class, *args) - if not hasattr(enum_member, '_value_'): + if not hasattr(enum_member, "_value_"): enum_member._value_ = member_type(*args) value = enum_member._value_ enum_member._name_ = member_name @@ -272,22 +286,26 @@ class EnumMeta(type): # __reduce_ex__ instead of any of the others as it is preferred by # pickle over __reduce__, and it handles all pickle protocols. unpicklable = False - if '__reduce_ex__' not in classdict: + if "__reduce_ex__" not in classdict: if member_type is not object: - methods = ('__getnewargs_ex__', '__getnewargs__', - '__reduce_ex__', '__reduce__') + methods = ( + "__getnewargs_ex__", + "__getnewargs__", + "__reduce_ex__", + "__reduce__", + ) if not any(m in member_type.__dict__ for m in methods): _make_class_unpicklable(enum_class) unpicklable = True # double check that repr and friends are not the mixin's or various # things break (such as pickle) - for name in ('__repr__', '__str__', '__format__', '__reduce_ex__'): + for name in ("__repr__", "__str__", "__format__", "__reduce_ex__"): class_method = getattr(enum_class, name) getattr(member_type, name, None) enum_method = getattr(first_enum, name, None) if name not in classdict and class_method is not enum_method: - if name == '__reduce_ex__' and unpicklable: + if name == "__reduce_ex__" and unpicklable: continue setattr(enum_class, name, enum_method) @@ -297,19 +315,19 @@ class EnumMeta(type): if pyver < 2.6: if issubclass(enum_class, int): - setattr(enum_class, '__cmp__', getattr(int, '__cmp__')) + setattr(enum_class, "__cmp__", getattr(int, "__cmp__")) elif pyver < 3.0: if issubclass(enum_class, int): for method in ( - '__le__', - '__lt__', - '__gt__', - '__ge__', - '__eq__', - '__ne__', - '__hash__', + "__le__", + "__lt__", + "__gt__", + "__ge__", + "__eq__", + "__ne__", + "__hash__", ): setattr(enum_class, method, getattr(int, method)) @@ -319,8 +337,8 @@ class EnumMeta(type): # if the user defined their own __new__, save it before it gets # clobbered in case they subclass later if save_new: - setattr(enum_class, '__member_new__', enum_class.__dict__['__new__']) - setattr(enum_class, '__new__', Enum.__dict__['__new__']) + setattr(enum_class, "__member_new__", enum_class.__dict__["__new__"]) + setattr(enum_class, "__new__", Enum.__dict__["__new__"]) return enum_class def __bool__(cls): @@ -357,13 +375,16 @@ class EnumMeta(type): # nicer error message when someone tries to delete an attribute # (see issue19025). if attr in cls._member_map_: - raise AttributeError( - "%s: cannot delete Enum member." % cls.__name__) + raise AttributeError("%s: cannot delete Enum member." % cls.__name__) super(EnumMeta, cls).__delattr__(attr) def __dir__(self): - return (['__class__', '__doc__', '__members__', '__module__'] + - self._member_names_) + return [ + "__class__", + "__doc__", + "__members__", + "__module__", + ] + self._member_names_ @property def __members__(cls): @@ -416,9 +437,9 @@ class EnumMeta(type): resulting in an inconsistent Enumeration. """ - member_map = cls.__dict__.get('_member_map_', {}) + member_map = cls.__dict__.get("_member_map_", {}) if name in member_map: - raise AttributeError('Cannot reassign members.') + raise AttributeError("Cannot reassign members.") super(EnumMeta, cls).__setattr__(name, value) def _create_(cls, class_name, names=None, module=None, type=None, start=1): @@ -437,12 +458,12 @@ class EnumMeta(type): # if class_name is unicode, attempt a conversion to ASCII if isinstance(class_name, unicode): try: - class_name = class_name.encode('ascii') + class_name = class_name.encode("ascii") except UnicodeEncodeError: - raise TypeError('%r is not representable in ASCII' % class_name) + raise TypeError("%r is not representable in ASCII" % class_name) metacls = cls.__class__ if type is None: - bases = (cls, ) + bases = (cls,) else: bases = (type, cls) classdict = metacls.__prepare__(class_name, bases) @@ -450,7 +471,7 @@ class EnumMeta(type): # special processing needed for names? if isinstance(names, basestring): - names = names.replace(',', ' ').split() + names = names.replace(",", " ").split() if isinstance(names, (tuple, list)) and isinstance(names[0], basestring): names = [(e, i + start) for (i, e) in enumerate(names)] @@ -465,14 +486,14 @@ class EnumMeta(type): _order_.append(member_name) # only set _order_ in classdict if name/value was not from a mapping if not isinstance(item, basestring): - classdict['_order_'] = ' '.join(_order_) + classdict["_order_"] = " ".join(_order_) enum_class = metacls.__new__(metacls, class_name, bases, classdict) # TODO: replace the frame hack if a blessed way to know the calling # module is ever developed if module is None: try: - module = _sys._getframe(2).f_globals['__name__'] + module = _sys._getframe(2).f_globals["__name__"] except (AttributeError, ValueError): pass if module is None: @@ -498,19 +519,19 @@ class EnumMeta(type): # type has been mixed in so we can use the correct __new__ member_type = first_enum = None for base in bases: - if (base is not Enum and - issubclass(base, Enum) and - base._member_names_): + if base is not Enum and issubclass(base, Enum) and base._member_names_: raise TypeError("Cannot extend enumerations") # base is now the last base in bases if not issubclass(base, Enum): - raise TypeError("new enumerations must be created as " - "`ClassName([mixin_type,] enum_type)`") + raise TypeError( + "new enumerations must be created as " + "`ClassName([mixin_type,] enum_type)`" + ) # get correct mix-in type (either mix-in type of Enum subclass, or # first base if last base is Enum) if not issubclass(bases[0], Enum): - member_type = bases[0] # first data type + member_type = bases[0] # first data type first_enum = bases[-1] # enum type else: for base in bases[0].__mro__: @@ -528,6 +549,7 @@ class EnumMeta(type): return member_type, first_enum if pyver < 3.0: + @staticmethod def _find_new_(classdict, member_type, first_enum): """Returns the __new__ to be used for creating the enum members. @@ -540,32 +562,27 @@ class EnumMeta(type): # now find the correct __new__, checking to see of one was defined # by the user; also check earlier enum classes in case a __new__ was # saved as __member_new__ - __new__ = classdict.get('__new__', None) + __new__ = classdict.get("__new__", None) if __new__: - return None, True, True # __new__, save_new, use_args + return None, True, True # __new__, save_new, use_args - N__new__ = getattr(None, '__new__') - O__new__ = getattr(object, '__new__') + N__new__ = getattr(None, "__new__") + O__new__ = getattr(object, "__new__") if Enum is None: E__new__ = N__new__ else: - E__new__ = Enum.__dict__['__new__'] + E__new__ = Enum.__dict__["__new__"] # check all possibles for __member_new__ before falling back to # __new__ - for method in ('__member_new__', '__new__'): + for method in ("__member_new__", "__new__"): for possible in (member_type, first_enum): try: target = possible.__dict__[method] except (AttributeError, KeyError): target = getattr(possible, method, None) - if target not in [ - None, - N__new__, - O__new__, - E__new__, - ]: - if method == '__member_new__': - classdict['__new__'] = target + if target not in [None, N__new__, O__new__, E__new__]: + if method == "__member_new__": + classdict["__new__"] = target return None, False, True if isinstance(target, staticmethod): target = target.__get__(member_type) @@ -585,7 +602,9 @@ class EnumMeta(type): use_args = True return __new__, False, use_args + else: + @staticmethod def _find_new_(classdict, member_type, first_enum): """Returns the __new__ to be used for creating the enum members. @@ -598,7 +617,7 @@ class EnumMeta(type): # now find the correct __new__, checking to see of one was defined # by the user; also check earlier enum classes in case a __new__ was # saved as __member_new__ - __new__ = classdict.get('__new__', None) + __new__ = classdict.get("__new__", None) # should __new__ be saved as __member_new__ later? save_new = __new__ is not None @@ -606,14 +625,14 @@ class EnumMeta(type): if __new__ is None: # check all possibles for __member_new__ before falling back to # __new__ - for method in ('__member_new__', '__new__'): + for method in ("__member_new__", "__new__"): for possible in (member_type, first_enum): target = getattr(possible, method, None) if target not in ( - None, - None.__new__, - object.__new__, - Enum.__new__, + None, + None.__new__, + object.__new__, + Enum.__new__, ): __new__ = target break @@ -640,7 +659,9 @@ class EnumMeta(type): # create the class. ######################################################## temp_enum_dict = {} -temp_enum_dict['__doc__'] = "Generic enumeration.\n\n Derive from this class to define new enumerations.\n\n" +temp_enum_dict[ + "__doc__" +] = "Generic enumeration.\n\n Derive from this class to define new enumerations.\n\n" def __new__(cls, value): @@ -664,16 +685,15 @@ def __new__(cls, value): raise ValueError("%s is not a valid %s" % (value, cls.__name__)) -temp_enum_dict['__new__'] = __new__ +temp_enum_dict["__new__"] = __new__ del __new__ def __repr__(self): - return "<%s.%s: %r>" % ( - self.__class__.__name__, self._name_, self._value_) + return "<%s.%s: %r>" % (self.__class__.__name__, self._name_, self._value_) -temp_enum_dict['__repr__'] = __repr__ +temp_enum_dict["__repr__"] = __repr__ del __repr__ @@ -681,19 +701,21 @@ def __str__(self): return "%s.%s" % (self.__class__.__name__, self._name_) -temp_enum_dict['__str__'] = __str__ +temp_enum_dict["__str__"] = __str__ del __str__ if pyver >= 3.0: + def __dir__(self): added_behavior = [ m for cls in self.__class__.mro() for m in cls.__dict__ - if m[0] != '_' and m not in self._member_map_ + if m[0] != "_" and m not in self._member_map_ ] - return (['__class__', '__doc__', '__module__', ] + added_behavior) - temp_enum_dict['__dir__'] = __dir__ + return ["__class__", "__doc__", "__module__"] + added_behavior + + temp_enum_dict["__dir__"] = __dir__ del __dir__ @@ -713,7 +735,7 @@ def __format__(self, format_spec): return cls.__format__(val, format_spec) -temp_enum_dict['__format__'] = __format__ +temp_enum_dict["__format__"] = __format__ del __format__ @@ -728,30 +750,50 @@ if pyver < 2.6: return 0 return -1 return NotImplemented - raise TypeError("unorderable types: %s() and %s()" % (self.__class__.__name__, other.__class__.__name__)) - temp_enum_dict['__cmp__'] = __cmp__ + raise TypeError( + "unorderable types: %s() and %s()" + % (self.__class__.__name__, other.__class__.__name__) + ) + + temp_enum_dict["__cmp__"] = __cmp__ del __cmp__ else: def __le__(self, other): - raise TypeError("unorderable types: %s() <= %s()" % (self.__class__.__name__, other.__class__.__name__)) - temp_enum_dict['__le__'] = __le__ + raise TypeError( + "unorderable types: %s() <= %s()" + % (self.__class__.__name__, other.__class__.__name__) + ) + + temp_enum_dict["__le__"] = __le__ del __le__ def __lt__(self, other): - raise TypeError("unorderable types: %s() < %s()" % (self.__class__.__name__, other.__class__.__name__)) - temp_enum_dict['__lt__'] = __lt__ + raise TypeError( + "unorderable types: %s() < %s()" + % (self.__class__.__name__, other.__class__.__name__) + ) + + temp_enum_dict["__lt__"] = __lt__ del __lt__ def __ge__(self, other): - raise TypeError("unorderable types: %s() >= %s()" % (self.__class__.__name__, other.__class__.__name__)) - temp_enum_dict['__ge__'] = __ge__ + raise TypeError( + "unorderable types: %s() >= %s()" + % (self.__class__.__name__, other.__class__.__name__) + ) + + temp_enum_dict["__ge__"] = __ge__ del __ge__ def __gt__(self, other): - raise TypeError("unorderable types: %s() > %s()" % (self.__class__.__name__, other.__class__.__name__)) - temp_enum_dict['__gt__'] = __gt__ + raise TypeError( + "unorderable types: %s() > %s()" + % (self.__class__.__name__, other.__class__.__name__) + ) + + temp_enum_dict["__gt__"] = __gt__ del __gt__ @@ -761,7 +803,7 @@ def __eq__(self, other): return NotImplemented -temp_enum_dict['__eq__'] = __eq__ +temp_enum_dict["__eq__"] = __eq__ del __eq__ @@ -771,7 +813,7 @@ def __ne__(self, other): return NotImplemented -temp_enum_dict['__ne__'] = __ne__ +temp_enum_dict["__ne__"] = __ne__ del __ne__ @@ -779,15 +821,15 @@ def __hash__(self): return hash(self._name_) -temp_enum_dict['__hash__'] = __hash__ +temp_enum_dict["__hash__"] = __hash__ del __hash__ def __reduce_ex__(self, proto): - return self.__class__, (self._value_, ) + return self.__class__, (self._value_,) -temp_enum_dict['__reduce_ex__'] = __reduce_ex__ +temp_enum_dict["__reduce_ex__"] = __reduce_ex__ del __reduce_ex__ # _RouteClassAttributeToGetattr is used to provide access to the `name` @@ -803,7 +845,7 @@ def name(self): return self._name_ -temp_enum_dict['name'] = name +temp_enum_dict["name"] = name del name @@ -812,7 +854,7 @@ def value(self): return self._value_ -temp_enum_dict['value'] = value +temp_enum_dict["value"] = value del value @@ -839,10 +881,10 @@ def _convert(cls, name, module, filter, source=None): return cls -temp_enum_dict['_convert'] = _convert +temp_enum_dict["_convert"] = _convert del _convert -Enum = EnumMeta('Enum', (object, ), temp_enum_dict) +Enum = EnumMeta("Enum", (object,), temp_enum_dict) del temp_enum_dict # Enum has now been created @@ -864,10 +906,10 @@ def unique(enumeration): if name != member.name: duplicates.append((name, member.name)) if duplicates: - duplicate_names = ', '.join( + duplicate_names = ", ".join( ["%s -> %s" % (alias, name) for (alias, name) in duplicates] ) - raise ValueError('duplicate names found in %r: %s' % - (enumeration, duplicate_names) - ) + raise ValueError( + "duplicate names found in %r: %s" % (enumeration, duplicate_names) + ) return enumeration diff --git a/graphene/pyutils/init_subclass.py b/graphene/pyutils/init_subclass.py index 78e4ff19..81198c9c 100644 --- a/graphene/pyutils/init_subclass.py +++ b/graphene/pyutils/init_subclass.py @@ -1,19 +1,23 @@ -is_init_subclass_available = hasattr(object, '__init_subclass__') +is_init_subclass_available = hasattr(object, "__init_subclass__") if not is_init_subclass_available: + class InitSubclassMeta(type): """Metaclass that implements PEP 487 protocol""" + def __new__(cls, name, bases, ns, **kwargs): - __init_subclass__ = ns.pop('__init_subclass__', None) + __init_subclass__ = ns.pop("__init_subclass__", None) if __init_subclass__: __init_subclass__ = classmethod(__init_subclass__) - ns['__init_subclass__'] = __init_subclass__ + ns["__init_subclass__"] = __init_subclass__ return super(InitSubclassMeta, cls).__new__(cls, name, bases, ns, **kwargs) def __init__(cls, name, bases, ns, **kwargs): super(InitSubclassMeta, cls).__init__(name, bases, ns) super_class = super(cls, cls) - if hasattr(super_class, '__init_subclass__'): + if hasattr(super_class, "__init_subclass__"): super_class.__init_subclass__.__func__(cls, **kwargs) + + else: InitSubclassMeta = type # type: ignore diff --git a/graphene/pyutils/signature.py b/graphene/pyutils/signature.py index c15fd14b..43633f56 100644 --- a/graphene/pyutils/signature.py +++ b/graphene/pyutils/signature.py @@ -13,22 +13,24 @@ from collections import OrderedDict __version__ = "0.4" -__all__ = ['BoundArguments', 'Parameter', 'Signature', 'signature'] +__all__ = ["BoundArguments", "Parameter", "Signature", "signature"] _WrapperDescriptor = type(type.__call__) _MethodWrapper = type(all.__call__) -_NonUserDefinedCallables = (_WrapperDescriptor, - _MethodWrapper, - types.BuiltinFunctionType) +_NonUserDefinedCallables = ( + _WrapperDescriptor, + _MethodWrapper, + types.BuiltinFunctionType, +) def formatannotation(annotation, base_module=None): if isinstance(annotation, type): - if annotation.__module__ in ('builtins', '__builtin__', base_module): + if annotation.__module__ in ("builtins", "__builtin__", base_module): return annotation.__name__ - return annotation.__module__ + '.' + annotation.__name__ + return annotation.__module__ + "." + annotation.__name__ return repr(annotation) @@ -49,20 +51,20 @@ def _get_user_defined_method(cls, method_name, *nested): def signature(obj): - '''Get a signature object for the passed callable.''' + """Get a signature object for the passed callable.""" if not callable(obj): - raise TypeError('{!r} is not a callable object'.format(obj)) + raise TypeError("{!r} is not a callable object".format(obj)) if isinstance(obj, types.MethodType): sig = signature(obj.__func__) if obj.__self__ is None: # Unbound method: the first parameter becomes positional-only if sig.parameters: - first = sig.parameters.values()[0].replace( - kind=_POSITIONAL_ONLY) + first = sig.parameters.values()[0].replace(kind=_POSITIONAL_ONLY) return sig.replace( - parameters=(first,) + tuple(sig.parameters.values())[1:]) + parameters=(first,) + tuple(sig.parameters.values())[1:] + ) else: return sig else: @@ -99,7 +101,7 @@ def signature(obj): try: ba = sig.bind_partial(*partial_args, **partial_keywords) except TypeError as ex: - msg = 'partial object {!r} has incorrect arguments'.format(obj) + msg = "partial object {!r} has incorrect arguments".format(obj) raise ValueError(msg) for arg_name, arg_value in ba.arguments.items(): @@ -122,11 +124,14 @@ def signature(obj): # flag. Later, in '_bind', the 'default' value of this # parameter will be added to 'kwargs', to simulate # the 'functools.partial' real call. - new_params[arg_name] = param.replace(default=arg_value, - _partial_kwarg=True) + new_params[arg_name] = param.replace( + default=arg_value, _partial_kwarg=True + ) - elif (param.kind not in (_VAR_KEYWORD, _VAR_POSITIONAL) and - not param._partial_kwarg): + elif ( + param.kind not in (_VAR_KEYWORD, _VAR_POSITIONAL) + and not param._partial_kwarg + ): new_params.pop(arg_name) return sig.replace(parameters=new_params.values()) @@ -137,17 +142,17 @@ def signature(obj): # First, let's see if it has an overloaded __call__ defined # in its metaclass - call = _get_user_defined_method(type(obj), '__call__') + call = _get_user_defined_method(type(obj), "__call__") if call is not None: sig = signature(call) else: # Now we check if the 'obj' class has a '__new__' method - new = _get_user_defined_method(obj, '__new__') + new = _get_user_defined_method(obj, "__new__") if new is not None: sig = signature(new) else: # Finally, we should have at least __init__ implemented - init = _get_user_defined_method(obj, '__init__') + init = _get_user_defined_method(obj, "__init__") if init is not None: sig = signature(init) elif not isinstance(obj, _NonUserDefinedCallables): @@ -155,7 +160,7 @@ def signature(obj): # We also check that the 'obj' is not an instance of # _WrapperDescriptor or _MethodWrapper to avoid # infinite recursion (and even potential segfault) - call = _get_user_defined_method(type(obj), '__call__', 'im_func') + call = _get_user_defined_method(type(obj), "__call__", "im_func") if call is not None: sig = signature(call) @@ -166,14 +171,14 @@ def signature(obj): if isinstance(obj, types.BuiltinFunctionType): # Raise a nicer error message for builtins - msg = 'no signature found for builtin function {!r}'.format(obj) + msg = "no signature found for builtin function {!r}".format(obj) raise ValueError(msg) - raise ValueError('callable {!r} is not supported by signature'.format(obj)) + raise ValueError("callable {!r} is not supported by signature".format(obj)) class _void(object): - '''A private marker - used in Parameter & Signature''' + """A private marker - used in Parameter & Signature""" class _empty(object): @@ -181,27 +186,28 @@ class _empty(object): class _ParameterKind(int): + def __new__(self, *args, **kwargs): obj = int.__new__(self, *args) - obj._name = kwargs['name'] + obj._name = kwargs["name"] return obj def __str__(self): return self._name def __repr__(self): - return '<_ParameterKind: {!r}>'.format(self._name) + return "<_ParameterKind: {!r}>".format(self._name) -_POSITIONAL_ONLY = _ParameterKind(0, name='POSITIONAL_ONLY') -_POSITIONAL_OR_KEYWORD = _ParameterKind(1, name='POSITIONAL_OR_KEYWORD') -_VAR_POSITIONAL = _ParameterKind(2, name='VAR_POSITIONAL') -_KEYWORD_ONLY = _ParameterKind(3, name='KEYWORD_ONLY') -_VAR_KEYWORD = _ParameterKind(4, name='VAR_KEYWORD') +_POSITIONAL_ONLY = _ParameterKind(0, name="POSITIONAL_ONLY") +_POSITIONAL_OR_KEYWORD = _ParameterKind(1, name="POSITIONAL_OR_KEYWORD") +_VAR_POSITIONAL = _ParameterKind(2, name="VAR_POSITIONAL") +_KEYWORD_ONLY = _ParameterKind(3, name="KEYWORD_ONLY") +_VAR_KEYWORD = _ParameterKind(4, name="VAR_KEYWORD") class Parameter(object): - '''Represents a parameter in a function signature. + """Represents a parameter in a function signature. Has the following public attributes: * name : str The name of the parameter as a string. @@ -216,9 +222,9 @@ class Parameter(object): Possible values: `Parameter.POSITIONAL_ONLY`, `Parameter.POSITIONAL_OR_KEYWORD`, `Parameter.VAR_POSITIONAL`, `Parameter.KEYWORD_ONLY`, `Parameter.VAR_KEYWORD`. - ''' + """ - __slots__ = ('_name', '_kind', '_default', '_annotation', '_partial_kwarg') + __slots__ = ("_name", "_kind", "_default", "_annotation", "_partial_kwarg") POSITIONAL_ONLY = _POSITIONAL_ONLY POSITIONAL_OR_KEYWORD = _POSITIONAL_OR_KEYWORD @@ -228,30 +234,37 @@ class Parameter(object): empty = _empty - def __init__(self, name, kind, default=_empty, annotation=_empty, - _partial_kwarg=False): + def __init__( + self, name, kind, default=_empty, annotation=_empty, _partial_kwarg=False + ): - if kind not in (_POSITIONAL_ONLY, _POSITIONAL_OR_KEYWORD, - _VAR_POSITIONAL, _KEYWORD_ONLY, _VAR_KEYWORD): + if kind not in ( + _POSITIONAL_ONLY, + _POSITIONAL_OR_KEYWORD, + _VAR_POSITIONAL, + _KEYWORD_ONLY, + _VAR_KEYWORD, + ): raise ValueError("invalid value for 'Parameter.kind' attribute") self._kind = kind if default is not _empty: if kind in (_VAR_POSITIONAL, _VAR_KEYWORD): - msg = '{} parameters cannot have default values'.format(kind) + msg = "{} parameters cannot have default values".format(kind) raise ValueError(msg) self._default = default self._annotation = annotation if name is None: if kind != _POSITIONAL_ONLY: - raise ValueError("None is not a valid name for a " - "non-positional-only parameter") + raise ValueError( + "None is not a valid name for a " "non-positional-only parameter" + ) self._name = name else: name = str(name) - if kind != _POSITIONAL_ONLY and not re.match(r'[a-z_]\w*$', name, re.I): - msg = '{!r} is not a valid parameter name'.format(name) + if kind != _POSITIONAL_ONLY and not re.match(r"[a-z_]\w*$", name, re.I): + msg = "{!r} is not a valid parameter name".format(name) raise ValueError(msg) self._name = name @@ -273,9 +286,15 @@ class Parameter(object): def kind(self): return self._kind - def replace(self, name=_void, kind=_void, annotation=_void, - default=_void, _partial_kwarg=_void): - '''Creates a customized copy of the Parameter.''' + def replace( + self, + name=_void, + kind=_void, + annotation=_void, + default=_void, + _partial_kwarg=_void, + ): + """Creates a customized copy of the Parameter.""" if name is _void: name = self._name @@ -292,8 +311,13 @@ class Parameter(object): if _partial_kwarg is _void: _partial_kwarg = self._partial_kwarg - return type(self)(name, kind, default=default, annotation=annotation, - _partial_kwarg=_partial_kwarg) + return type(self)( + name, + kind, + default=default, + annotation=annotation, + _partial_kwarg=_partial_kwarg, + ) def __str__(self): kind = self.kind @@ -301,45 +325,45 @@ class Parameter(object): formatted = self._name if kind == _POSITIONAL_ONLY: if formatted is None: - formatted = '' - formatted = '<{}>'.format(formatted) + formatted = "" + formatted = "<{}>".format(formatted) # Add annotation and default value if self._annotation is not _empty: - formatted = '{}:{}'.format(formatted, - formatannotation(self._annotation)) + formatted = "{}:{}".format(formatted, formatannotation(self._annotation)) if self._default is not _empty: - formatted = '{}={}'.format(formatted, repr(self._default)) + formatted = "{}={}".format(formatted, repr(self._default)) if kind == _VAR_POSITIONAL: - formatted = '*' + formatted + formatted = "*" + formatted elif kind == _VAR_KEYWORD: - formatted = '**' + formatted + formatted = "**" + formatted return formatted def __repr__(self): - return '<{} at {:#x} {!r}>'.format(self.__class__.__name__, - id(self), self.name) + return "<{} at {:#x} {!r}>".format(self.__class__.__name__, id(self), self.name) def __hash__(self): msg = "unhashable type: '{}'".format(self.__class__.__name__) raise TypeError(msg) def __eq__(self, other): - return (issubclass(other.__class__, Parameter) and - self._name == other._name and - self._kind == other._kind and - self._default == other._default and - self._annotation == other._annotation) + return ( + issubclass(other.__class__, Parameter) + and self._name == other._name + and self._kind == other._kind + and self._default == other._default + and self._annotation == other._annotation + ) def __ne__(self, other): return not self.__eq__(other) class BoundArguments(object): - '''Result of `Signature.bind` call. Holds the mapping of arguments + """Result of `Signature.bind` call. Holds the mapping of arguments to the function's parameters. Has the following public attributes: * arguments : OrderedDict @@ -351,7 +375,7 @@ class BoundArguments(object): Tuple of positional arguments values. * kwargs : dict Dict of keyword arguments values. - ''' + """ def __init__(self, signature, arguments): self.arguments = arguments @@ -365,8 +389,7 @@ class BoundArguments(object): def args(self): args = [] for param_name, param in self._signature.parameters.items(): - if (param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY) or - param._partial_kwarg): + if param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY) or param._partial_kwarg: # Keyword arguments mapped by 'functools.partial' # (Parameter._partial_kwarg is True) are mapped # in 'BoundArguments.kwargs', along with VAR_KEYWORD & @@ -395,8 +418,7 @@ class BoundArguments(object): kwargs_started = False for param_name, param in self._signature.parameters.items(): if not kwargs_started: - if (param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY) or - param._partial_kwarg): + if param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY) or param._partial_kwarg: kwargs_started = True else: if param_name not in self.arguments: @@ -425,16 +447,18 @@ class BoundArguments(object): raise TypeError(msg) def __eq__(self, other): - return (issubclass(other.__class__, BoundArguments) and - self.signature == other.signature and - self.arguments == other.arguments) + return ( + issubclass(other.__class__, BoundArguments) + and self.signature == other.signature + and self.arguments == other.arguments + ) def __ne__(self, other): return not self.__eq__(other) class Signature(object): - '''A Signature object represents the overall signature of a function. + """A Signature object represents the overall signature of a function. It stores a Parameter object for each parameter accepted by the function, as well as information specific to the function itself. A Signature object has the following public attributes and methods: @@ -452,20 +476,21 @@ class Signature(object): * bind_partial(*args, **kwargs) -> BoundArguments Creates a partial mapping from positional and keyword arguments to parameters (simulating 'functools.partial' behavior.) - ''' + """ - __slots__ = ('_return_annotation', '_parameters') + __slots__ = ("_return_annotation", "_parameters") _parameter_cls = Parameter _bound_arguments_cls = BoundArguments empty = _empty - def __init__(self, parameters=None, return_annotation=_empty, - __validate_parameters__=True): - '''Constructs Signature from the given list of Parameter + def __init__( + self, parameters=None, return_annotation=_empty, __validate_parameters__=True + ): + """Constructs Signature from the given list of Parameter objects and 'return_annotation'. All arguments are optional. - ''' + """ if parameters is None: params = OrderedDict() @@ -477,7 +502,7 @@ class Signature(object): for idx, param in enumerate(parameters): kind = param.kind if kind < top_kind: - msg = 'wrong parameter order: {0} before {1}' + msg = "wrong parameter order: {0} before {1}" msg = msg.format(top_kind, param.kind) raise ValueError(msg) else: @@ -489,22 +514,21 @@ class Signature(object): param = param.replace(name=name) if name in params: - msg = 'duplicate parameter name: {!r}'.format(name) + msg = "duplicate parameter name: {!r}".format(name) raise ValueError(msg) params[name] = param else: - params = OrderedDict(((param.name, param) - for param in parameters)) + params = OrderedDict(((param.name, param) for param in parameters)) self._parameters = params self._return_annotation = return_annotation @classmethod def from_function(cls, func): - '''Constructs Signature for the given python function''' + """Constructs Signature for the given python function""" if not isinstance(func, types.FunctionType): - raise TypeError('{!r} is not a Python function'.format(func)) + raise TypeError("{!r} is not a Python function".format(func)) Parameter = cls._parameter_cls @@ -513,11 +537,11 @@ class Signature(object): pos_count = func_code.co_argcount arg_names = func_code.co_varnames positional = tuple(arg_names[:pos_count]) - keyword_only_count = getattr(func_code, 'co_kwonlyargcount', 0) - keyword_only = arg_names[pos_count:(pos_count + keyword_only_count)] - annotations = getattr(func, '__annotations__', {}) + keyword_only_count = getattr(func_code, "co_kwonlyargcount", 0) + keyword_only = arg_names[pos_count : (pos_count + keyword_only_count)] + annotations = getattr(func, "__annotations__", {}) defaults = func.__defaults__ - kwdefaults = getattr(func, '__kwdefaults__', None) + kwdefaults = getattr(func, "__kwdefaults__", None) if defaults: pos_default_count = len(defaults) @@ -530,22 +554,29 @@ class Signature(object): non_default_count = pos_count - pos_default_count for name in positional[:non_default_count]: annotation = annotations.get(name, _empty) - parameters.append(Parameter(name, annotation=annotation, - kind=_POSITIONAL_OR_KEYWORD)) + parameters.append( + Parameter(name, annotation=annotation, kind=_POSITIONAL_OR_KEYWORD) + ) # ... w/ defaults. for offset, name in enumerate(positional[non_default_count:]): annotation = annotations.get(name, _empty) - parameters.append(Parameter(name, annotation=annotation, - kind=_POSITIONAL_OR_KEYWORD, - default=defaults[offset])) + parameters.append( + Parameter( + name, + annotation=annotation, + kind=_POSITIONAL_OR_KEYWORD, + default=defaults[offset], + ) + ) # *args if func_code.co_flags & 0x04: name = arg_names[pos_count + keyword_only_count] annotation = annotations.get(name, _empty) - parameters.append(Parameter(name, annotation=annotation, - kind=_VAR_POSITIONAL)) + parameters.append( + Parameter(name, annotation=annotation, kind=_VAR_POSITIONAL) + ) # Keyword-only parameters. for name in keyword_only: @@ -554,9 +585,11 @@ class Signature(object): default = kwdefaults.get(name, _empty) annotation = annotations.get(name, _empty) - parameters.append(Parameter(name, annotation=annotation, - kind=_KEYWORD_ONLY, - default=default)) + parameters.append( + Parameter( + name, annotation=annotation, kind=_KEYWORD_ONLY, default=default + ) + ) # **kwargs if func_code.co_flags & 0x08: index = pos_count + keyword_only_count @@ -565,12 +598,13 @@ class Signature(object): name = arg_names[index] annotation = annotations.get(name, _empty) - parameters.append(Parameter(name, annotation=annotation, - kind=_VAR_KEYWORD)) + parameters.append(Parameter(name, annotation=annotation, kind=_VAR_KEYWORD)) - return cls(parameters, - return_annotation=annotations.get('return', _empty), - __validate_parameters__=False) + return cls( + parameters, + return_annotation=annotations.get("return", _empty), + __validate_parameters__=False, + ) @property def parameters(self): @@ -584,10 +618,10 @@ class Signature(object): return self._return_annotation def replace(self, parameters=_void, return_annotation=_void): - '''Creates a customized copy of the Signature. + """Creates a customized copy of the Signature. Pass 'parameters' and/or 'return_annotation' arguments to override them in the new copy. - ''' + """ if parameters is _void: parameters = self.parameters.values() @@ -595,21 +629,23 @@ class Signature(object): if return_annotation is _void: return_annotation = self._return_annotation - return type(self)(parameters, - return_annotation=return_annotation) + return type(self)(parameters, return_annotation=return_annotation) def __hash__(self): msg = "unhashable type: '{}'".format(self.__class__.__name__) raise TypeError(msg) def __eq__(self, other): - if (not issubclass(type(other), Signature) or - self.return_annotation != other.return_annotation or - len(self.parameters) != len(other.parameters)): + if ( + not issubclass(type(other), Signature) + or self.return_annotation != other.return_annotation + or len(self.parameters) != len(other.parameters) + ): return False - other_positions = {param: idx - for idx, param in enumerate(other.parameters.keys())} + other_positions = { + param: idx for idx, param in enumerate(other.parameters.keys()) + } for idx, (param_name, param) in enumerate(self.parameters.items()): if param.kind == _KEYWORD_ONLY: @@ -626,8 +662,7 @@ class Signature(object): except KeyError: return False else: - if (idx != other_idx or - param != other.parameters[param_name]): + if idx != other_idx or param != other.parameters[param_name]: return False return True @@ -636,7 +671,7 @@ class Signature(object): return not self.__eq__(other) def _bind(self, args, kwargs, partial=False): - '''Private method. Don't use directly.''' + """Private method. Don't use directly.""" arguments = OrderedDict() @@ -649,7 +684,7 @@ class Signature(object): # See 'functools.partial' case in 'signature()' implementation # for details. for param_name, param in self.parameters.items(): - if (param._partial_kwarg and param_name not in kwargs): + if param._partial_kwarg and param_name not in kwargs: # Simulating 'functools.partial' behavior kwargs[param_name] = param.default @@ -673,14 +708,12 @@ class Signature(object): break elif param.name in kwargs: if param.kind == _POSITIONAL_ONLY: - msg = '{arg!r} parameter is positional only, ' \ - 'but was passed as a keyword' + msg = "{arg!r} parameter is positional only, " "but was passed as a keyword" msg = msg.format(arg=param.name) raise TypeError(msg) parameters_ex = (param,) break - elif (param.kind == _VAR_KEYWORD or - param.default is not _empty): + elif param.kind == _VAR_KEYWORD or param.default is not _empty: # That's fine too - we have a default value for this # parameter. So, lets start parsing `kwargs`, starting # with the current parameter @@ -691,7 +724,7 @@ class Signature(object): parameters_ex = (param,) break else: - msg = '{arg!r} parameter lacking default value' + msg = "{arg!r} parameter lacking default value" msg = msg.format(arg=param.name) raise TypeError(msg) else: @@ -699,12 +732,12 @@ class Signature(object): try: param = next(parameters) except StopIteration: - raise TypeError('too many positional arguments') + raise TypeError("too many positional arguments") else: if param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY): # Looks like we have no parameter for this positional # argument - raise TypeError('too many positional arguments') + raise TypeError("too many positional arguments") if param.kind == _VAR_POSITIONAL: # We have an '*args'-like argument, let's fill it with @@ -716,8 +749,10 @@ class Signature(object): break if param.name in kwargs: - raise TypeError('multiple values for argument ' - '{arg!r}'.format(arg=param.name)) + raise TypeError( + "multiple values for argument " + "{arg!r}".format(arg=param.name) + ) arguments[param.name] = arg_val @@ -729,9 +764,10 @@ class Signature(object): # This should never happen in case of a properly built # Signature object (but let's have this check here # to ensure correct behaviour just in case) - raise TypeError('{arg!r} parameter is positional only, ' - 'but was passed as a keyword'. - format(arg=param.name)) + raise TypeError( + "{arg!r} parameter is positional only, " + "but was passed as a keyword".format(arg=param.name) + ) if param.kind == _VAR_KEYWORD: # Memorize that we have a '**kwargs'-like parameter @@ -746,10 +782,14 @@ class Signature(object): # if it has a default value, or it is an '*args'-like # parameter, left alone by the processing of positional # arguments. - if (not partial and param.kind != _VAR_POSITIONAL and - param.default is _empty): - raise TypeError('{arg!r} parameter lacking default value'. - format(arg=param_name)) + if ( + not partial + and param.kind != _VAR_POSITIONAL + and param.default is _empty + ): + raise TypeError( + "{arg!r} parameter lacking default value".format(arg=param_name) + ) else: arguments[param_name] = arg_val @@ -759,22 +799,22 @@ class Signature(object): # Process our '**kwargs'-like parameter arguments[kwargs_param.name] = kwargs else: - raise TypeError('too many keyword arguments') + raise TypeError("too many keyword arguments") return self._bound_arguments_cls(self, arguments) def bind(self, *args, **kwargs): - '''Get a BoundArguments object, that maps the passed `args` + """Get a BoundArguments object, that maps the passed `args` and `kwargs` to the function's signature. Raises `TypeError` if the passed arguments can not be bound. - ''' + """ return self._bind(args, kwargs) def bind_partial(self, *args, **kwargs): - '''Get a BoundArguments object, that partially maps the + """Get a BoundArguments object, that partially maps the passed `args` and `kwargs` to the function's signature. Raises `TypeError` if the passed arguments can not be bound. - ''' + """ return self._bind(args, kwargs, partial=True) def __str__(self): @@ -792,17 +832,17 @@ class Signature(object): # We have a keyword-only parameter to render and we haven't # rendered an '*args'-like parameter before, so add a '*' # separator to the parameters list ("foo(arg1, *, arg2)" case) - result.append('*') + result.append("*") # This condition should be only triggered once, so # reset the flag render_kw_only_separator = False result.append(formatted) - rendered = '({})'.format(', '.join(result)) + rendered = "({})".format(", ".join(result)) if self.return_annotation is not _empty: anno = formatannotation(self.return_annotation) - rendered += ' -> {}'.format(anno) + rendered += " -> {}".format(anno) return rendered diff --git a/graphene/pyutils/tests/test_enum.py b/graphene/pyutils/tests/test_enum.py index 8854f4c2..8e2755f2 100644 --- a/graphene/pyutils/tests/test_enum.py +++ b/graphene/pyutils/tests/test_enum.py @@ -2,18 +2,8 @@ from ..enum import _is_dunder, _is_sunder def test__is_dunder(): - dunder_names = [ - '__i__', - '__test__', - ] - non_dunder_names = [ - 'test', - '__test', - '_test', - '_test_', - 'test__', - '', - ] + dunder_names = ["__i__", "__test__"] + non_dunder_names = ["test", "__test", "_test", "_test_", "test__", ""] for name in dunder_names: assert _is_dunder(name) is True @@ -23,17 +13,9 @@ def test__is_dunder(): def test__is_sunder(): - sunder_names = [ - '_i_', - '_test_', - ] + sunder_names = ["_i_", "_test_"] - non_sunder_names = [ - '__i__', - '_i__', - '__i_', - '', - ] + non_sunder_names = ["__i__", "_i__", "__i_", ""] for name in sunder_names: assert _is_sunder(name) is True diff --git a/graphene/pyutils/version.py b/graphene/pyutils/version.py index e82128d8..f2005442 100644 --- a/graphene/pyutils/version.py +++ b/graphene/pyutils/version.py @@ -16,15 +16,15 @@ def get_version(version=None): main = get_main_version(version) - sub = '' - if version[3] == 'alpha' and version[4] == 0: + sub = "" + if version[3] == "alpha" and version[4] == 0: git_changeset = get_git_changeset() if git_changeset: - sub = '.dev%s' % git_changeset + sub = ".dev%s" % git_changeset else: - sub = '.dev' - elif version[3] != 'final': - mapping = {'alpha': 'a', 'beta': 'b', 'rc': 'rc'} + sub = ".dev" + elif version[3] != "final": + mapping = {"alpha": "a", "beta": "b", "rc": "rc"} sub = mapping[version[3]] + str(version[4]) return str(main + sub) @@ -34,7 +34,7 @@ def get_main_version(version=None): "Returns main version (X.Y[.Z]) from VERSION." version = get_complete_version(version) parts = 2 if version[2] == 0 else 3 - return '.'.join(str(x) for x in version[:parts]) + return ".".join(str(x) for x in version[:parts]) def get_complete_version(version=None): @@ -45,17 +45,17 @@ def get_complete_version(version=None): from graphene import VERSION as version else: assert len(version) == 5 - assert version[3] in ('alpha', 'beta', 'rc', 'final') + assert version[3] in ("alpha", "beta", "rc", "final") return version def get_docs_version(version=None): version = get_complete_version(version) - if version[3] != 'final': - return 'dev' + if version[3] != "final": + return "dev" else: - return '%d.%d' % version[:2] + return "%d.%d" % version[:2] def get_git_changeset(): @@ -67,12 +67,15 @@ def get_git_changeset(): repo_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) try: git_log = subprocess.Popen( - 'git log --pretty=format:%ct --quiet -1 HEAD', - stdout=subprocess.PIPE, stderr=subprocess.PIPE, - shell=True, cwd=repo_dir, universal_newlines=True, + "git log --pretty=format:%ct --quiet -1 HEAD", + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + shell=True, + cwd=repo_dir, + universal_newlines=True, ) timestamp = git_log.communicate()[0] timestamp = datetime.datetime.utcfromtimestamp(int(timestamp)) except: return None - return timestamp.strftime('%Y%m%d%H%M%S') + return timestamp.strftime("%Y%m%d%H%M%S") diff --git a/graphene/relay/__init__.py b/graphene/relay/__init__.py index 8cc26ebf..7238fa72 100644 --- a/graphene/relay/__init__.py +++ b/graphene/relay/__init__.py @@ -3,11 +3,11 @@ from .mutation import ClientIDMutation from .connection import Connection, ConnectionField, PageInfo __all__ = [ - 'Node', - 'is_node', - 'GlobalID', - 'ClientIDMutation', - 'Connection', - 'ConnectionField', - 'PageInfo', + "Node", + "is_node", + "GlobalID", + "ClientIDMutation", + "Connection", + "ConnectionField", + "PageInfo", ] diff --git a/graphene/relay/connection.py b/graphene/relay/connection.py index bcd238d3..421ab502 100644 --- a/graphene/relay/connection.py +++ b/graphene/relay/connection.py @@ -5,8 +5,7 @@ from functools import partial from graphql_relay import connection_from_list from promise import Promise, is_thenable -from ..types import (Boolean, Enum, Int, Interface, List, NonNull, Scalar, - String, Union) +from ..types import Boolean, Enum, Int, Interface, List, NonNull, Scalar, String, Union from ..types.field import Field from ..types.objecttype import ObjectType, ObjectTypeOptions from .node import is_node @@ -15,24 +14,24 @@ from .node import is_node class PageInfo(ObjectType): has_next_page = Boolean( required=True, - name='hasNextPage', - description='When paginating forwards, are there more items?', + name="hasNextPage", + description="When paginating forwards, are there more items?", ) has_previous_page = Boolean( required=True, - name='hasPreviousPage', - description='When paginating backwards, are there more items?', + name="hasPreviousPage", + description="When paginating backwards, are there more items?", ) start_cursor = String( - name='startCursor', - description='When paginating backwards, the cursor to continue.', + name="startCursor", + description="When paginating backwards, the cursor to continue.", ) end_cursor = String( - name='endCursor', - description='When paginating forwards, the cursor to continue.', + name="endCursor", + description="When paginating forwards, the cursor to continue.", ) @@ -48,52 +47,54 @@ class Connection(ObjectType): @classmethod def __init_subclass_with_meta__(cls, node=None, name=None, **options): _meta = ConnectionOptions(cls) - assert node, 'You have to provide a node in {}.Meta'.format(cls.__name__) - assert issubclass(node, (Scalar, Enum, ObjectType, Interface, Union, NonNull)), ( - 'Received incompatible node "{}" for Connection {}.' - ).format(node, cls.__name__) + assert node, "You have to provide a node in {}.Meta".format(cls.__name__) + assert issubclass( + node, (Scalar, Enum, ObjectType, Interface, Union, NonNull) + ), ('Received incompatible node "{}" for Connection {}.').format( + node, cls.__name__ + ) - base_name = re.sub('Connection$', '', name or cls.__name__) or node._meta.name + base_name = re.sub("Connection$", "", name or cls.__name__) or node._meta.name if not name: - name = '{}Connection'.format(base_name) + name = "{}Connection".format(base_name) - edge_class = getattr(cls, 'Edge', None) + edge_class = getattr(cls, "Edge", None) _node = node class EdgeBase(object): - node = Field(_node, description='The item at the end of the edge') - cursor = String(required=True, description='A cursor for use in pagination') + node = Field(_node, description="The item at the end of the edge") + cursor = String(required=True, description="A cursor for use in pagination") - edge_name = '{}Edge'.format(base_name) + edge_name = "{}Edge".format(base_name) if edge_class: - edge_bases = (edge_class, EdgeBase, ObjectType,) + edge_bases = (edge_class, EdgeBase, ObjectType) else: - edge_bases = (EdgeBase, ObjectType,) + edge_bases = (EdgeBase, ObjectType) edge = type(edge_name, edge_bases, {}) cls.Edge = edge - options['name'] = name + options["name"] = name _meta.node = node - _meta.fields = OrderedDict([ - ('page_info', Field(PageInfo, name='pageInfo', required=True)), - ('edges', Field(NonNull(List(edge)))), - ]) - return super(Connection, cls).__init_subclass_with_meta__(_meta=_meta, **options) + _meta.fields = OrderedDict( + [ + ("page_info", Field(PageInfo, name="pageInfo", required=True)), + ("edges", Field(NonNull(List(edge)))), + ] + ) + return super(Connection, cls).__init_subclass_with_meta__( + _meta=_meta, **options + ) class IterableConnectionField(Field): def __init__(self, type, *args, **kwargs): - kwargs.setdefault('before', String()) - kwargs.setdefault('after', String()) - kwargs.setdefault('first', Int()) - kwargs.setdefault('last', Int()) - super(IterableConnectionField, self).__init__( - type, - *args, - **kwargs - ) + kwargs.setdefault("before", String()) + kwargs.setdefault("after", String()) + kwargs.setdefault("first", Int()) + kwargs.setdefault("last", Int()) + super(IterableConnectionField, self).__init__(type, *args, **kwargs) @property def type(self): @@ -119,7 +120,7 @@ class IterableConnectionField(Field): return resolved assert isinstance(resolved, Iterable), ( - 'Resolved value from the connection field have to be iterable or instance of {}. ' + "Resolved value from the connection field have to be iterable or instance of {}. " 'Received "{}"' ).format(connection_type, resolved) connection = connection_from_list( @@ -127,7 +128,7 @@ class IterableConnectionField(Field): args, connection_type=connection_type, edge_type=connection_type.Edge, - pageinfo_type=PageInfo + pageinfo_type=PageInfo, ) connection.iterable = resolved return connection diff --git a/graphene/relay/mutation.py b/graphene/relay/mutation.py index 2f6d1ce5..cce49d11 100644 --- a/graphene/relay/mutation.py +++ b/graphene/relay/mutation.py @@ -13,56 +13,61 @@ class ClientIDMutation(Mutation): abstract = True @classmethod - def __init_subclass_with_meta__(cls, output=None, input_fields=None, - arguments=None, name=None, **options): - input_class = getattr(cls, 'Input', None) - base_name = re.sub('Payload$', '', name or cls.__name__) + def __init_subclass_with_meta__( + cls, output=None, input_fields=None, arguments=None, name=None, **options + ): + input_class = getattr(cls, "Input", None) + base_name = re.sub("Payload$", "", name or cls.__name__) assert not output, "Can't specify any output" assert not arguments, "Can't specify any arguments" - bases = (InputObjectType, ) + bases = (InputObjectType,) if input_class: - bases += (input_class, ) + bases += (input_class,) if not input_fields: input_fields = {} cls.Input = type( - '{}Input'.format(base_name), + "{}Input".format(base_name), bases, - OrderedDict(input_fields, client_mutation_id=String( - name='clientMutationId')) + OrderedDict( + input_fields, client_mutation_id=String(name="clientMutationId") + ), ) arguments = OrderedDict( input=cls.Input(required=True) # 'client_mutation_id': String(name='clientMutationId') ) - mutate_and_get_payload = getattr(cls, 'mutate_and_get_payload', None) + mutate_and_get_payload = getattr(cls, "mutate_and_get_payload", None) if cls.mutate and cls.mutate.__func__ == ClientIDMutation.mutate.__func__: assert mutate_and_get_payload, ( "{name}.mutate_and_get_payload method is required" - " in a ClientIDMutation.").format(name=name or cls.__name__) + " in a ClientIDMutation." + ).format(name=name or cls.__name__) if not name: - name = '{}Payload'.format(base_name) + name = "{}Payload".format(base_name) super(ClientIDMutation, cls).__init_subclass_with_meta__( - output=None, arguments=arguments, name=name, **options) - cls._meta.fields['client_mutation_id'] = ( - Field(String, name='clientMutationId') + output=None, arguments=arguments, name=name, **options ) + cls._meta.fields["client_mutation_id"] = Field(String, name="clientMutationId") @classmethod def mutate(cls, root, info, input): + def on_resolve(payload): try: - payload.client_mutation_id = input.get('client_mutation_id') + payload.client_mutation_id = input.get("client_mutation_id") except Exception: raise Exception( - ('Cannot set client_mutation_id in the payload object {}' - ).format(repr(payload))) + ("Cannot set client_mutation_id in the payload object {}").format( + repr(payload) + ) + ) return payload result = cls.mutate_and_get_payload(root, info, **input) diff --git a/graphene/relay/node.py b/graphene/relay/node.py index 5c787ffb..ab8778bf 100644 --- a/graphene/relay/node.py +++ b/graphene/relay/node.py @@ -10,9 +10,9 @@ from ..types.utils import get_type def is_node(objecttype): - ''' + """ Check if the given objecttype has Node as an interface - ''' + """ if not isclass(objecttype): return False @@ -41,15 +41,17 @@ class GlobalID(Field): def get_resolver(self, parent_resolver): return partial( - self.id_resolver, parent_resolver, self.node, parent_type_name=self.parent_type_name + self.id_resolver, + parent_resolver, + self.node, + parent_type_name=self.parent_type_name, ) class NodeField(Field): - def __init__(self, node, type=False, deprecation_reason=None, - name=None, **kwargs): - assert issubclass(node, Node), 'NodeField can only operate in Nodes' + def __init__(self, node, type=False, deprecation_reason=None, name=None, **kwargs): + assert issubclass(node, Node), "NodeField can only operate in Nodes" self.node_type = node self.field_type = type @@ -57,8 +59,8 @@ class NodeField(Field): # If we don's specify a type, the field type will be the node # interface type or node, - description='The ID of the object', - id=ID(required=True) + description="The ID of the object", + id=ID(required=True), ) def get_resolver(self, parent_resolver): @@ -74,14 +76,13 @@ class AbstractNode(Interface): def __init_subclass_with_meta__(cls, **options): _meta = InterfaceOptions(cls) _meta.fields = OrderedDict( - id=GlobalID(cls, description='The ID of the object.') + id=GlobalID(cls, description="The ID of the object.") ) - super(AbstractNode, cls).__init_subclass_with_meta__( - _meta=_meta, **options) + super(AbstractNode, cls).__init_subclass_with_meta__(_meta=_meta, **options) class Node(AbstractNode): - '''An object with an ID''' + """An object with an ID""" @classmethod def Field(cls, *args, **kwargs): # noqa: N802 @@ -100,15 +101,15 @@ class Node(AbstractNode): return None if only_type: - assert graphene_type == only_type, ( - 'Must receive a {} id.' - ).format(only_type._meta.name) + assert graphene_type == only_type, ("Must receive a {} id.").format( + only_type._meta.name + ) # We make sure the ObjectType implements the "Node" interface if cls not in graphene_type._meta.interfaces: return None - get_node = getattr(graphene_type, 'get_node', None) + get_node = getattr(graphene_type, "get_node", None) if get_node: return get_node(info, _id) diff --git a/graphene/relay/tests/test_connection.py b/graphene/relay/tests/test_connection.py index 28dd929f..f3dad969 100644 --- a/graphene/relay/tests/test_connection.py +++ b/graphene/relay/tests/test_connection.py @@ -1,7 +1,6 @@ import pytest -from ...types import (Argument, Field, Int, List, NonNull, ObjectType, Schema, - String) +from ...types import Argument, Field, Int, List, NonNull, ObjectType, Schema, String from ..connection import Connection, ConnectionField, PageInfo from ..node import Node @@ -10,10 +9,12 @@ class MyObject(ObjectType): class Meta: interfaces = [Node] + field = String() def test_connection(): + class MyObjectConnection(Connection): extra = String() @@ -23,11 +24,11 @@ def test_connection(): class Edge: other = String() - assert MyObjectConnection._meta.name == 'MyObjectConnection' + assert MyObjectConnection._meta.name == "MyObjectConnection" fields = MyObjectConnection._meta.fields - assert list(fields.keys()) == ['page_info', 'edges', 'extra'] - edge_field = fields['edges'] - pageinfo_field = fields['page_info'] + assert list(fields.keys()) == ["page_info", "edges", "extra"] + edge_field = fields["edges"] + pageinfo_field = fields["page_info"] assert isinstance(edge_field, Field) assert isinstance(edge_field.type, NonNull) @@ -40,6 +41,7 @@ def test_connection(): def test_connection_inherit_abstracttype(): + class BaseConnection(object): extra = String() @@ -48,9 +50,9 @@ def test_connection_inherit_abstracttype(): class Meta: node = MyObject - assert MyObjectConnection._meta.name == 'MyObjectConnection' + assert MyObjectConnection._meta.name == "MyObjectConnection" fields = MyObjectConnection._meta.fields - assert list(fields.keys()) == ['page_info', 'edges', 'extra'] + assert list(fields.keys()) == ["page_info", "edges", "extra"] def test_connection_name(): @@ -69,6 +71,7 @@ def test_connection_name(): def test_edge(): + class MyObjectConnection(Connection): class Meta: @@ -78,18 +81,19 @@ def test_edge(): other = String() Edge = MyObjectConnection.Edge - assert Edge._meta.name == 'MyObjectEdge' + assert Edge._meta.name == "MyObjectEdge" edge_fields = Edge._meta.fields - assert list(edge_fields.keys()) == ['node', 'cursor', 'other'] + assert list(edge_fields.keys()) == ["node", "cursor", "other"] - assert isinstance(edge_fields['node'], Field) - assert edge_fields['node'].type == MyObject + assert isinstance(edge_fields["node"], Field) + assert edge_fields["node"].type == MyObject - assert isinstance(edge_fields['other'], Field) - assert edge_fields['other'].type == String + assert isinstance(edge_fields["other"], Field) + assert edge_fields["other"].type == String def test_edge_with_bases(): + class BaseEdge(object): extra = String() @@ -102,24 +106,30 @@ def test_edge_with_bases(): other = String() Edge = MyObjectConnection.Edge - assert Edge._meta.name == 'MyObjectEdge' + assert Edge._meta.name == "MyObjectEdge" edge_fields = Edge._meta.fields - assert list(edge_fields.keys()) == ['node', 'cursor', 'extra', 'other'] + assert list(edge_fields.keys()) == ["node", "cursor", "extra", "other"] - assert isinstance(edge_fields['node'], Field) - assert edge_fields['node'].type == MyObject + assert isinstance(edge_fields["node"], Field) + assert edge_fields["node"].type == MyObject - assert isinstance(edge_fields['other'], Field) - assert edge_fields['other'].type == String + assert isinstance(edge_fields["other"], Field) + assert edge_fields["other"].type == String def test_pageinfo(): - assert PageInfo._meta.name == 'PageInfo' + assert PageInfo._meta.name == "PageInfo" fields = PageInfo._meta.fields - assert list(fields.keys()) == ['has_next_page', 'has_previous_page', 'start_cursor', 'end_cursor'] + assert list(fields.keys()) == [ + "has_next_page", + "has_previous_page", + "start_cursor", + "end_cursor", + ] def test_connectionfield(): + class MyObjectConnection(Connection): class Meta: @@ -127,10 +137,10 @@ def test_connectionfield(): field = ConnectionField(MyObjectConnection) assert field.args == { - 'before': Argument(String), - 'after': Argument(String), - 'first': Argument(Int), - 'last': Argument(Int), + "before": Argument(String), + "after": Argument(String), + "first": Argument(Int), + "last": Argument(Int), } @@ -139,26 +149,32 @@ def test_connectionfield_node_deprecated(): with pytest.raises(Exception) as exc_info: field.type - assert "ConnectionField's now need a explicit ConnectionType for Nodes." in str(exc_info.value) + assert "ConnectionField's now need a explicit ConnectionType for Nodes." in str( + exc_info.value + ) def test_connectionfield_custom_args(): + class MyObjectConnection(Connection): class Meta: node = MyObject - field = ConnectionField(MyObjectConnection, before=String(required=True), extra=String()) + field = ConnectionField( + MyObjectConnection, before=String(required=True), extra=String() + ) assert field.args == { - 'before': Argument(NonNull(String)), - 'after': Argument(String), - 'first': Argument(Int), - 'last': Argument(Int), - 'extra': Argument(String), + "before": Argument(NonNull(String)), + "after": Argument(String), + "first": Argument(Int), + "last": Argument(Int), + "extra": Argument(String), } def test_connectionfield_required(): + class MyObjectConnection(Connection): class Meta: @@ -171,8 +187,6 @@ def test_connectionfield_required(): return [] schema = Schema(query=Query) - executed = schema.execute( - '{ testConnection { edges { cursor } } }' - ) + executed = schema.execute("{ testConnection { edges { cursor } } }") assert not executed.errors - assert executed.data == {'testConnection': {'edges': []}} + assert executed.data == {"testConnection": {"edges": []}} diff --git a/graphene/relay/tests/test_connection_query.py b/graphene/relay/tests/test_connection_query.py index 0f266a55..12baa2d3 100644 --- a/graphene/relay/tests/test_connection_query.py +++ b/graphene/relay/tests/test_connection_query.py @@ -7,13 +7,13 @@ from ...types import ObjectType, Schema, String from ..connection import Connection, ConnectionField, PageInfo from ..node import Node -letter_chars = ['A', 'B', 'C', 'D', 'E'] +letter_chars = ["A", "B", "C", "D", "E"] class Letter(ObjectType): class Meta: - interfaces = (Node, ) + interfaces = (Node,) letter = String() @@ -39,16 +39,10 @@ class Query(ObjectType): def resolve_connection_letters(self, info, **args): return LetterConnection( - page_info=PageInfo( - has_next_page=True, - has_previous_page=False - ), + page_info=PageInfo(has_next_page=True, has_previous_page=False), edges=[ - LetterConnection.Edge( - node=Letter(id=0, letter='A'), - cursor='a-cursor' - ), - ] + LetterConnection.Edge(node=Letter(id=0, letter="A"), cursor="a-cursor") + ], ) @@ -62,11 +56,8 @@ for i, letter in enumerate(letter_chars): def edges(selected_letters): return [ { - 'node': { - 'id': base64('Letter:%s' % l.id), - 'letter': l.letter - }, - 'cursor': base64('arrayconnection:%s' % l.id) + "node": {"id": base64("Letter:%s" % l.id), "letter": l.letter}, + "cursor": base64("arrayconnection:%s" % l.id), } for l in [letters[i] for i in selected_letters] ] @@ -74,14 +65,15 @@ def edges(selected_letters): def cursor_for(ltr): letter = letters[ltr] - return base64('arrayconnection:%s' % letter.id) + return base64("arrayconnection:%s" % letter.id) -def execute(args=''): +def execute(args=""): if args: - args = '(' + args + ')' + args = "(" + args + ")" - return schema.execute(''' + return schema.execute( + """ { letters%s { edges { @@ -99,112 +91,136 @@ def execute(args=''): } } } - ''' % args) + """ + % args + ) def check(args, letters, has_previous_page=False, has_next_page=False): result = execute(args) expected_edges = edges(letters) expected_page_info = { - 'hasPreviousPage': has_previous_page, - 'hasNextPage': has_next_page, - 'endCursor': expected_edges[-1]['cursor'] if expected_edges else None, - 'startCursor': expected_edges[0]['cursor'] if expected_edges else None + "hasPreviousPage": has_previous_page, + "hasNextPage": has_next_page, + "endCursor": expected_edges[-1]["cursor"] if expected_edges else None, + "startCursor": expected_edges[0]["cursor"] if expected_edges else None, } assert not result.errors assert result.data == { - 'letters': { - 'edges': expected_edges, - 'pageInfo': expected_page_info - } + "letters": {"edges": expected_edges, "pageInfo": expected_page_info} } def test_returns_all_elements_without_filters(): - check('', 'ABCDE') + check("", "ABCDE") def test_respects_a_smaller_first(): - check('first: 2', 'AB', has_next_page=True) + check("first: 2", "AB", has_next_page=True) def test_respects_an_overly_large_first(): - check('first: 10', 'ABCDE') + check("first: 10", "ABCDE") def test_respects_a_smaller_last(): - check('last: 2', 'DE', has_previous_page=True) + check("last: 2", "DE", has_previous_page=True) def test_respects_an_overly_large_last(): - check('last: 10', 'ABCDE') + check("last: 10", "ABCDE") def test_respects_first_and_after(): - check('first: 2, after: "{}"'.format(cursor_for('B')), 'CD', has_next_page=True) + check('first: 2, after: "{}"'.format(cursor_for("B")), "CD", has_next_page=True) def test_respects_first_and_after_with_long_first(): - check('first: 10, after: "{}"'.format(cursor_for('B')), 'CDE') + check('first: 10, after: "{}"'.format(cursor_for("B")), "CDE") def test_respects_last_and_before(): - check('last: 2, before: "{}"'.format(cursor_for('D')), 'BC', has_previous_page=True) + check('last: 2, before: "{}"'.format(cursor_for("D")), "BC", has_previous_page=True) def test_respects_last_and_before_with_long_last(): - check('last: 10, before: "{}"'.format(cursor_for('D')), 'ABC') + check('last: 10, before: "{}"'.format(cursor_for("D")), "ABC") def test_respects_first_and_after_and_before_too_few(): - check('first: 2, after: "{}", before: "{}"'.format(cursor_for('A'), cursor_for('E')), 'BC', has_next_page=True) + check( + 'first: 2, after: "{}", before: "{}"'.format(cursor_for("A"), cursor_for("E")), + "BC", + has_next_page=True, + ) def test_respects_first_and_after_and_before_too_many(): - check('first: 4, after: "{}", before: "{}"'.format(cursor_for('A'), cursor_for('E')), 'BCD') + check( + 'first: 4, after: "{}", before: "{}"'.format(cursor_for("A"), cursor_for("E")), + "BCD", + ) def test_respects_first_and_after_and_before_exactly_right(): - check('first: 3, after: "{}", before: "{}"'.format(cursor_for('A'), cursor_for('E')), "BCD") + check( + 'first: 3, after: "{}", before: "{}"'.format(cursor_for("A"), cursor_for("E")), + "BCD", + ) def test_respects_last_and_after_and_before_too_few(): - check('last: 2, after: "{}", before: "{}"'.format(cursor_for('A'), cursor_for('E')), 'CD', has_previous_page=True) + check( + 'last: 2, after: "{}", before: "{}"'.format(cursor_for("A"), cursor_for("E")), + "CD", + has_previous_page=True, + ) def test_respects_last_and_after_and_before_too_many(): - check('last: 4, after: "{}", before: "{}"'.format(cursor_for('A'), cursor_for('E')), 'BCD') + check( + 'last: 4, after: "{}", before: "{}"'.format(cursor_for("A"), cursor_for("E")), + "BCD", + ) def test_respects_last_and_after_and_before_exactly_right(): - check('last: 3, after: "{}", before: "{}"'.format(cursor_for('A'), cursor_for('E')), 'BCD') + check( + 'last: 3, after: "{}", before: "{}"'.format(cursor_for("A"), cursor_for("E")), + "BCD", + ) def test_returns_no_elements_if_first_is_0(): - check('first: 0', '', has_next_page=True) + check("first: 0", "", has_next_page=True) def test_returns_all_elements_if_cursors_are_invalid(): - check('before: "invalid" after: "invalid"', 'ABCDE') + check('before: "invalid" after: "invalid"', "ABCDE") def test_returns_all_elements_if_cursors_are_on_the_outside(): check( 'before: "{}" after: "{}"'.format( - base64( - 'arrayconnection:%s' % 6), - base64( - 'arrayconnection:%s' % -1)), - 'ABCDE') + base64("arrayconnection:%s" % 6), base64("arrayconnection:%s" % -1) + ), + "ABCDE", + ) def test_returns_no_elements_if_cursors_cross(): - check('before: "{}" after: "{}"'.format(base64('arrayconnection:%s' % 2), base64('arrayconnection:%s' % 4)), '') + check( + 'before: "{}" after: "{}"'.format( + base64("arrayconnection:%s" % 2), base64("arrayconnection:%s" % 4) + ), + "", + ) def test_connection_type_nodes(): - result = schema.execute(''' + result = schema.execute( + """ { connectionLetters { edges { @@ -220,28 +236,23 @@ def test_connection_type_nodes(): } } } - ''') + """ + ) assert not result.errors assert result.data == { - 'connectionLetters': { - 'edges': [{ - 'node': { - 'id': 'TGV0dGVyOjA=', - 'letter': 'A', - }, - 'cursor': 'a-cursor', - }], - 'pageInfo': { - 'hasPreviousPage': False, - 'hasNextPage': True, - } + "connectionLetters": { + "edges": [ + {"node": {"id": "TGV0dGVyOjA=", "letter": "A"}, "cursor": "a-cursor"} + ], + "pageInfo": {"hasPreviousPage": False, "hasNextPage": True}, } } def test_connection_promise(): - result = schema.execute(''' + result = schema.execute( + """ { promiseLetters(first:1) { edges { @@ -256,20 +267,13 @@ def test_connection_promise(): } } } - ''') + """ + ) assert not result.errors assert result.data == { - 'promiseLetters': { - 'edges': [{ - 'node': { - 'id': 'TGV0dGVyOjA=', - 'letter': 'A', - }, - }], - 'pageInfo': { - 'hasPreviousPage': False, - 'hasNextPage': True, - } + "promiseLetters": { + "edges": [{"node": {"id": "TGV0dGVyOjA=", "letter": "A"}}], + "pageInfo": {"hasPreviousPage": False, "hasNextPage": True}, } } diff --git a/graphene/relay/tests/test_global_id.py b/graphene/relay/tests/test_global_id.py index 6301f954..74fd6458 100644 --- a/graphene/relay/tests/test_global_id.py +++ b/graphene/relay/tests/test_global_id.py @@ -8,13 +8,14 @@ from ..node import GlobalID, Node class CustomNode(Node): class Meta: - name = 'Node' + name = "Node" class User(ObjectType): class Meta: interfaces = [CustomNode] + name = String() @@ -27,7 +28,7 @@ class Info(object): description=parent_type._meta.description, fields=None, is_type_of=parent_type.is_type_of, - interfaces=None + interfaces=None, ) @@ -45,7 +46,7 @@ def test_global_id_allows_overriding_of_node_and_required(): def test_global_id_defaults_to_info_parent_type(): - my_id = '1' + my_id = "1" gid = GlobalID() id_resolver = gid.get_resolver(lambda *_: my_id) my_global_id = id_resolver(None, Info(User)) @@ -53,7 +54,7 @@ def test_global_id_defaults_to_info_parent_type(): def test_global_id_allows_setting_customer_parent_type(): - my_id = '1' + my_id = "1" gid = GlobalID(parent_type=User) id_resolver = gid.get_resolver(lambda *_: my_id) my_global_id = id_resolver(None, None) diff --git a/graphene/relay/tests/test_mutation.py b/graphene/relay/tests/test_mutation.py index a830ffbe..ba51f4a2 100644 --- a/graphene/relay/tests/test_mutation.py +++ b/graphene/relay/tests/test_mutation.py @@ -1,8 +1,16 @@ import pytest from promise import Promise -from ...types import (ID, Argument, Field, InputField, InputObjectType, - NonNull, ObjectType, Schema) +from ...types import ( + ID, + Argument, + Field, + InputField, + InputObjectType, + NonNull, + ObjectType, + Schema, +) from ...types.scalars import String from ..mutation import ClientIDMutation @@ -31,7 +39,7 @@ class SaySomething(ClientIDMutation): class FixedSaySomething(object): - __slots__ = 'phrase', + __slots__ = ("phrase",) def __init__(self, phrase): self.phrase = phrase @@ -76,11 +84,14 @@ class OtherMutation(ClientIDMutation): my_node_edge = Field(MyEdge) @staticmethod - def mutate_and_get_payload(self, info, shared='', additional_field='', client_mutation_id=None): + def mutate_and_get_payload( + self, info, shared="", additional_field="", client_mutation_id=None + ): edge_type = MyEdge return OtherMutation( name=shared + additional_field, - my_node_edge=edge_type(cursor='1', node=MyNode(name='name'))) + my_node_edge=edge_type(cursor="1", node=MyNode(name="name")), + ) class RootQuery(ObjectType): @@ -103,64 +114,62 @@ def test_no_mutate_and_get_payload(): class MyMutation(ClientIDMutation): pass - assert "MyMutation.mutate_and_get_payload method is required in a ClientIDMutation." == str( - excinfo.value) + assert ( + "MyMutation.mutate_and_get_payload method is required in a ClientIDMutation." + == str(excinfo.value) + ) def test_mutation(): fields = SaySomething._meta.fields - assert list(fields.keys()) == ['phrase', 'client_mutation_id'] + assert list(fields.keys()) == ["phrase", "client_mutation_id"] assert SaySomething._meta.name == "SaySomethingPayload" - assert isinstance(fields['phrase'], Field) + assert isinstance(fields["phrase"], Field) field = SaySomething.Field() assert field.type == SaySomething - assert list(field.args.keys()) == ['input'] - assert isinstance(field.args['input'], Argument) - assert isinstance(field.args['input'].type, NonNull) - assert field.args['input'].type.of_type == SaySomething.Input - assert isinstance(fields['client_mutation_id'], Field) - assert fields['client_mutation_id'].name == 'clientMutationId' - assert fields['client_mutation_id'].type == String + assert list(field.args.keys()) == ["input"] + assert isinstance(field.args["input"], Argument) + assert isinstance(field.args["input"].type, NonNull) + assert field.args["input"].type.of_type == SaySomething.Input + assert isinstance(fields["client_mutation_id"], Field) + assert fields["client_mutation_id"].name == "clientMutationId" + assert fields["client_mutation_id"].type == String def test_mutation_input(): Input = SaySomething.Input assert issubclass(Input, InputObjectType) fields = Input._meta.fields - assert list(fields.keys()) == ['what', 'client_mutation_id'] - assert isinstance(fields['what'], InputField) - assert fields['what'].type == String - assert isinstance(fields['client_mutation_id'], InputField) - assert fields['client_mutation_id'].type == String + assert list(fields.keys()) == ["what", "client_mutation_id"] + assert isinstance(fields["what"], InputField) + assert fields["what"].type == String + assert isinstance(fields["client_mutation_id"], InputField) + assert fields["client_mutation_id"].type == String def test_subclassed_mutation(): fields = OtherMutation._meta.fields - assert list(fields.keys()) == [ - 'name', 'my_node_edge', 'client_mutation_id' - ] - assert isinstance(fields['name'], Field) + assert list(fields.keys()) == ["name", "my_node_edge", "client_mutation_id"] + assert isinstance(fields["name"], Field) field = OtherMutation.Field() assert field.type == OtherMutation - assert list(field.args.keys()) == ['input'] - assert isinstance(field.args['input'], Argument) - assert isinstance(field.args['input'].type, NonNull) - assert field.args['input'].type.of_type == OtherMutation.Input + assert list(field.args.keys()) == ["input"] + assert isinstance(field.args["input"], Argument) + assert isinstance(field.args["input"].type, NonNull) + assert field.args["input"].type.of_type == OtherMutation.Input def test_subclassed_mutation_input(): Input = OtherMutation.Input assert issubclass(Input, InputObjectType) fields = Input._meta.fields - assert list(fields.keys()) == [ - 'shared', 'additional_field', 'client_mutation_id' - ] - assert isinstance(fields['shared'], InputField) - assert fields['shared'].type == String - assert isinstance(fields['additional_field'], InputField) - assert fields['additional_field'].type == String - assert isinstance(fields['client_mutation_id'], InputField) - assert fields['client_mutation_id'].type == String + assert list(fields.keys()) == ["shared", "additional_field", "client_mutation_id"] + assert isinstance(fields["shared"], InputField) + assert fields["shared"].type == String + assert isinstance(fields["additional_field"], InputField) + assert fields["additional_field"].type == String + assert isinstance(fields["client_mutation_id"], InputField) + assert fields["client_mutation_id"].type == String def test_node_query(): @@ -168,14 +177,16 @@ def test_node_query(): 'mutation a { say(input: {what:"hello", clientMutationId:"1"}) { phrase } }' ) assert not executed.errors - assert executed.data == {'say': {'phrase': 'hello'}} + assert executed.data == {"say": {"phrase": "hello"}} def test_node_query_fixed(): executed = schema.execute( 'mutation a { sayFixed(input: {what:"hello", clientMutationId:"1"}) { phrase } }' ) - assert "Cannot set client_mutation_id in the payload object" in str(executed.errors[0]) + assert "Cannot set client_mutation_id in the payload object" in str( + executed.errors[0] + ) def test_node_query_promise(): @@ -183,7 +194,7 @@ def test_node_query_promise(): 'mutation a { sayPromise(input: {what:"hello", clientMutationId:"1"}) { phrase } }' ) assert not executed.errors - assert executed.data == {'sayPromise': {'phrase': 'hello'}} + assert executed.data == {"sayPromise": {"phrase": "hello"}} def test_edge_query(): @@ -192,13 +203,8 @@ def test_edge_query(): ) assert not executed.errors assert dict(executed.data) == { - 'other': { - 'clientMutationId': '1', - 'myNodeEdge': { - 'cursor': '1', - 'node': { - 'name': 'name' - } - } + "other": { + "clientMutationId": "1", + "myNodeEdge": {"cursor": "1", "node": {"name": "name"}}, } } diff --git a/graphene/relay/tests/test_node.py b/graphene/relay/tests/test_node.py index df44fcb5..26fd73be 100644 --- a/graphene/relay/tests/test_node.py +++ b/graphene/relay/tests/test_node.py @@ -12,13 +12,14 @@ class SharedNodeFields(object): something_else = String() def resolve_something_else(*_): - return '----' + return "----" class MyNode(ObjectType): class Meta: - interfaces = (Node, ) + interfaces = (Node,) + name = String() @staticmethod @@ -30,10 +31,10 @@ class MyOtherNode(SharedNodeFields, ObjectType): extra_field = String() class Meta: - interfaces = (Node, ) + interfaces = (Node,) def resolve_extra_field(self, *_): - return 'extra field info.' + return "extra field info." @staticmethod def get_node(info, id): @@ -51,7 +52,7 @@ schema = Schema(query=RootQuery, types=[MyNode, MyOtherNode]) def test_node_good(): - assert 'id' in MyNode._meta.fields + assert "id" in MyNode._meta.fields assert is_node(MyNode) assert not is_node(object) @@ -61,25 +62,33 @@ def test_node_query(): '{ node(id:"%s") { ... on MyNode { name } } }' % Node.to_global_id("MyNode", 1) ) assert not executed.errors - assert executed.data == {'node': {'name': '1'}} + assert executed.data == {"node": {"name": "1"}} def test_subclassed_node_query(): executed = schema.execute( - '{ node(id:"%s") { ... on MyOtherNode { shared, extraField, somethingElse } } }' % - to_global_id("MyOtherNode", 1)) + '{ node(id:"%s") { ... on MyOtherNode { shared, extraField, somethingElse } } }' + % to_global_id("MyOtherNode", 1) + ) assert not executed.errors - assert executed.data == OrderedDict({'node': OrderedDict( - [('shared', '1'), ('extraField', 'extra field info.'), ('somethingElse', '----')])}) + assert executed.data == OrderedDict( + { + "node": OrderedDict( + [ + ("shared", "1"), + ("extraField", "extra field info."), + ("somethingElse", "----"), + ] + ) + } + ) def test_node_requesting_non_node(): executed = schema.execute( '{ node(id:"%s") { __typename } } ' % Node.to_global_id("RootQuery", 1) ) - assert executed.data == { - 'node': None - } + assert executed.data == {"node": None} def test_node_query_incorrect_id(): @@ -87,7 +96,7 @@ def test_node_query_incorrect_id(): '{ node(id:"%s") { ... on MyNode { name } } }' % "something:2" ) assert not executed.errors - assert executed.data == {'node': None} + assert executed.data == {"node": None} def test_node_field(): @@ -107,37 +116,42 @@ def test_node_field_only_type(): '{ onlyNode(id:"%s") { __typename, name } } ' % Node.to_global_id("MyNode", 1) ) assert not executed.errors - assert executed.data == {'onlyNode': {'__typename': 'MyNode', 'name': '1'}} + assert executed.data == {"onlyNode": {"__typename": "MyNode", "name": "1"}} def test_node_field_only_type_wrong(): executed = schema.execute( - '{ onlyNode(id:"%s") { __typename, name } } ' % Node.to_global_id("MyOtherNode", 1) + '{ onlyNode(id:"%s") { __typename, name } } ' + % Node.to_global_id("MyOtherNode", 1) ) assert len(executed.errors) == 1 - assert str(executed.errors[0]) == 'Must receive a MyNode id.' - assert executed.data == {'onlyNode': None} + assert str(executed.errors[0]) == "Must receive a MyNode id." + assert executed.data == {"onlyNode": None} def test_node_field_only_lazy_type(): executed = schema.execute( - '{ onlyNodeLazy(id:"%s") { __typename, name } } ' % Node.to_global_id("MyNode", 1) + '{ onlyNodeLazy(id:"%s") { __typename, name } } ' + % Node.to_global_id("MyNode", 1) ) assert not executed.errors - assert executed.data == {'onlyNodeLazy': {'__typename': 'MyNode', 'name': '1'}} + assert executed.data == {"onlyNodeLazy": {"__typename": "MyNode", "name": "1"}} def test_node_field_only_lazy_type_wrong(): executed = schema.execute( - '{ onlyNodeLazy(id:"%s") { __typename, name } } ' % Node.to_global_id("MyOtherNode", 1) + '{ onlyNodeLazy(id:"%s") { __typename, name } } ' + % Node.to_global_id("MyOtherNode", 1) ) assert len(executed.errors) == 1 - assert str(executed.errors[0]) == 'Must receive a MyNode id.' - assert executed.data == {'onlyNodeLazy': None} + assert str(executed.errors[0]) == "Must receive a MyNode id." + assert executed.data == {"onlyNodeLazy": None} def test_str_schema(): - assert str(schema) == """ + assert ( + str(schema) + == """ schema { query: RootQuery } @@ -165,3 +179,4 @@ type RootQuery { onlyNodeLazy(id: ID!): MyNode } """.lstrip() + ) diff --git a/graphene/relay/tests/test_node_custom.py b/graphene/relay/tests/test_node_custom.py index 80124c0d..59ecd23f 100644 --- a/graphene/relay/tests/test_node_custom.py +++ b/graphene/relay/tests/test_node_custom.py @@ -8,7 +8,7 @@ from ..node import Node class CustomNode(Node): class Meta: - name = 'Node' + name = "Node" @staticmethod def to_global_id(type, id): @@ -31,6 +31,7 @@ class User(ObjectType): class Meta: interfaces = [CustomNode] + name = String() @@ -40,15 +41,9 @@ class Photo(ObjectType): interfaces = [CustomNode, BasePhoto] -user_data = { - '1': User(id='1', name='John Doe'), - '2': User(id='2', name='Jane Smith'), -} +user_data = {"1": User(id="1", name="John Doe"), "2": User(id="2", name="Jane Smith")} -photo_data = { - '3': Photo(id='3', width=300), - '4': Photo(id='4', width=400), -} +photo_data = {"3": Photo(id="3", width=300), "4": Photo(id="4", width=400)} class RootQuery(ObjectType): @@ -59,7 +54,9 @@ schema = Schema(query=RootQuery, types=[User, Photo]) def test_str_schema_correct(): - assert str(schema) == '''schema { + assert ( + str(schema) + == """schema { query: RootQuery } @@ -84,47 +81,40 @@ type User implements Node { id: ID! name: String } -''' +""" + ) def test_gets_the_correct_id_for_users(): - query = ''' + query = """ { node(id: "1") { id } } - ''' - expected = { - 'node': { - 'id': '1', - } - } + """ + expected = {"node": {"id": "1"}} result = graphql(schema, query) assert not result.errors assert result.data == expected def test_gets_the_correct_id_for_photos(): - query = ''' + query = """ { node(id: "4") { id } } - ''' - expected = { - 'node': { - 'id': '4', - } - } + """ + expected = {"node": {"id": "4"}} result = graphql(schema, query) assert not result.errors assert result.data == expected def test_gets_the_correct_name_for_users(): - query = ''' + query = """ { node(id: "1") { id @@ -133,20 +123,15 @@ def test_gets_the_correct_name_for_users(): } } } - ''' - expected = { - 'node': { - 'id': '1', - 'name': 'John Doe' - } - } + """ + expected = {"node": {"id": "1", "name": "John Doe"}} result = graphql(schema, query) assert not result.errors assert result.data == expected def test_gets_the_correct_width_for_photos(): - query = ''' + query = """ { node(id: "4") { id @@ -155,60 +140,45 @@ def test_gets_the_correct_width_for_photos(): } } } - ''' - expected = { - 'node': { - 'id': '4', - 'width': 400 - } - } + """ + expected = {"node": {"id": "4", "width": 400}} result = graphql(schema, query) assert not result.errors assert result.data == expected def test_gets_the_correct_typename_for_users(): - query = ''' + query = """ { node(id: "1") { id __typename } } - ''' - expected = { - 'node': { - 'id': '1', - '__typename': 'User' - } - } + """ + expected = {"node": {"id": "1", "__typename": "User"}} result = graphql(schema, query) assert not result.errors assert result.data == expected def test_gets_the_correct_typename_for_photos(): - query = ''' + query = """ { node(id: "4") { id __typename } } - ''' - expected = { - 'node': { - 'id': '4', - '__typename': 'Photo' - } - } + """ + expected = {"node": {"id": "4", "__typename": "Photo"}} result = graphql(schema, query) assert not result.errors assert result.data == expected def test_ignores_photo_fragments_on_user(): - query = ''' + query = """ { node(id: "1") { id @@ -217,35 +187,29 @@ def test_ignores_photo_fragments_on_user(): } } } - ''' - expected = { - 'node': { - 'id': '1', - } - } + """ + expected = {"node": {"id": "1"}} result = graphql(schema, query) assert not result.errors assert result.data == expected def test_returns_null_for_bad_ids(): - query = ''' + query = """ { node(id: "5") { id } } - ''' - expected = { - 'node': None - } + """ + expected = {"node": None} result = graphql(schema, query) assert not result.errors assert result.data == expected def test_have_correct_node_interface(): - query = ''' + query = """ { __type(name: "Node") { name @@ -262,23 +226,20 @@ def test_have_correct_node_interface(): } } } - ''' + """ expected = { - '__type': { - 'name': 'Node', - 'kind': 'INTERFACE', - 'fields': [ + "__type": { + "name": "Node", + "kind": "INTERFACE", + "fields": [ { - 'name': 'id', - 'type': { - 'kind': 'NON_NULL', - 'ofType': { - 'name': 'ID', - 'kind': 'SCALAR' - } - } + "name": "id", + "type": { + "kind": "NON_NULL", + "ofType": {"name": "ID", "kind": "SCALAR"}, + }, } - ] + ], } } result = graphql(schema, query) @@ -287,7 +248,7 @@ def test_have_correct_node_interface(): def test_has_correct_node_root_field(): - query = ''' + query = """ { __schema { queryType { @@ -311,29 +272,23 @@ def test_has_correct_node_root_field(): } } } - ''' + """ expected = { - '__schema': { - 'queryType': { - 'fields': [ + "__schema": { + "queryType": { + "fields": [ { - 'name': 'node', - 'type': { - 'name': 'Node', - 'kind': 'INTERFACE' - }, - 'args': [ + "name": "node", + "type": {"name": "Node", "kind": "INTERFACE"}, + "args": [ { - 'name': 'id', - 'type': { - 'kind': 'NON_NULL', - 'ofType': { - 'name': 'ID', - 'kind': 'SCALAR' - } - } + "name": "id", + "type": { + "kind": "NON_NULL", + "ofType": {"name": "ID", "kind": "SCALAR"}, + }, } - ] + ], } ] } diff --git a/graphene/test/__init__.py b/graphene/test/__init__.py index f7823f48..ce10ac09 100644 --- a/graphene/test/__init__.py +++ b/graphene/test/__init__.py @@ -10,7 +10,7 @@ def default_format_error(error): if isinstance(error, GraphQLError): return format_graphql_error(error) - return {'message': six.text_type(error)} + return {"message": six.text_type(error)} def format_execution_result(execution_result, format_error): @@ -18,12 +18,10 @@ def format_execution_result(execution_result, format_error): response = {} if execution_result.errors: - response['errors'] = [ - format_error(e) for e in execution_result.errors - ] + response["errors"] = [format_error(e) for e in execution_result.errors] if not execution_result.invalid: - response['data'] = execution_result.data + response["data"] = execution_result.data return response @@ -40,8 +38,7 @@ class Client(object): return format_execution_result(result, self.format_error) def execute(self, *args, **kwargs): - executed = self.schema.execute(*args, - **dict(self.execute_options, **kwargs)) + executed = self.schema.execute(*args, **dict(self.execute_options, **kwargs)) if is_thenable(executed): return Promise.resolve(executed).then(self.format_result) diff --git a/graphene/tests/issues/test_313.py b/graphene/tests/issues/test_313.py index e524a85b..ab607325 100644 --- a/graphene/tests/issues/test_313.py +++ b/graphene/tests/issues/test_313.py @@ -29,7 +29,7 @@ class CreatePost(graphene.Mutation): result = graphene.Field(CreatePostResult) def mutate(self, info, text): - result = Success(yeah='yeah') + result = Success(yeah="yeah") return CreatePost(result=result) @@ -37,11 +37,12 @@ class CreatePost(graphene.Mutation): class Mutations(graphene.ObjectType): create_post = CreatePost.Field() + # tests.py def test_create_post(): - query_string = ''' + query_string = """ mutation { createPost(text: "Try this out") { result { @@ -49,10 +50,10 @@ def test_create_post(): } } } - ''' + """ schema = graphene.Schema(query=Query, mutation=Mutations) result = schema.execute(query_string) assert not result.errors - assert result.data['createPost']['result']['__typename'] == 'Success' + assert result.data["createPost"]["result"]["__typename"] == "Success" diff --git a/graphene/tests/issues/test_356.py b/graphene/tests/issues/test_356.py index 9d8fc77b..e7f4882b 100644 --- a/graphene/tests/issues/test_356.py +++ b/graphene/tests/issues/test_356.py @@ -21,6 +21,7 @@ class MyUnion(graphene.Union): def test_issue(): + class Query(graphene.ObjectType): things = relay.ConnectionField(MyUnion) @@ -28,6 +29,6 @@ def test_issue(): graphene.Schema(query=Query) assert str(exc_info.value) == ( - 'IterableConnectionField type have to be a subclass of Connection. ' + "IterableConnectionField type have to be a subclass of Connection. " 'Received "MyUnion".' ) diff --git a/graphene/tests/issues/test_425.py b/graphene/tests/issues/test_425.py index 525e0b76..4f367380 100644 --- a/graphene/tests/issues/test_425.py +++ b/graphene/tests/issues/test_425.py @@ -14,33 +14,38 @@ class SpecialOptions(ObjectTypeOptions): class SpecialObjectType(ObjectType): @classmethod - def __init_subclass_with_meta__(cls, other_attr='default', **options): + def __init_subclass_with_meta__(cls, other_attr="default", **options): _meta = SpecialOptions(cls) _meta.other_attr = other_attr - super(SpecialObjectType, cls).__init_subclass_with_meta__(_meta=_meta, **options) + super(SpecialObjectType, cls).__init_subclass_with_meta__( + _meta=_meta, **options + ) def test_special_objecttype_could_be_subclassed(): + class MyType(SpecialObjectType): class Meta: - other_attr = 'yeah!' + other_attr = "yeah!" - assert MyType._meta.other_attr == 'yeah!' + assert MyType._meta.other_attr == "yeah!" def test_special_objecttype_could_be_subclassed_default(): + class MyType(SpecialObjectType): pass - assert MyType._meta.other_attr == 'default' + assert MyType._meta.other_attr == "default" def test_special_objecttype_inherit_meta_options(): + class MyType(SpecialObjectType): pass - assert MyType._meta.name == 'MyType' + assert MyType._meta.name == "MyType" assert MyType._meta.default_resolver is None assert MyType._meta.interfaces == () @@ -53,33 +58,38 @@ class SpecialInputObjectTypeOptions(ObjectTypeOptions): class SpecialInputObjectType(InputObjectType): @classmethod - def __init_subclass_with_meta__(cls, other_attr='default', **options): + def __init_subclass_with_meta__(cls, other_attr="default", **options): _meta = SpecialInputObjectTypeOptions(cls) _meta.other_attr = other_attr - super(SpecialInputObjectType, cls).__init_subclass_with_meta__(_meta=_meta, **options) + super(SpecialInputObjectType, cls).__init_subclass_with_meta__( + _meta=_meta, **options + ) def test_special_inputobjecttype_could_be_subclassed(): + class MyInputObjectType(SpecialInputObjectType): class Meta: - other_attr = 'yeah!' + other_attr = "yeah!" - assert MyInputObjectType._meta.other_attr == 'yeah!' + assert MyInputObjectType._meta.other_attr == "yeah!" def test_special_inputobjecttype_could_be_subclassed_default(): + class MyInputObjectType(SpecialInputObjectType): pass - assert MyInputObjectType._meta.other_attr == 'default' + assert MyInputObjectType._meta.other_attr == "default" def test_special_inputobjecttype_inherit_meta_options(): + class MyInputObjectType(SpecialInputObjectType): pass - assert MyInputObjectType._meta.name == 'MyInputObjectType' + assert MyInputObjectType._meta.name == "MyInputObjectType" # Enum @@ -90,30 +100,33 @@ class SpecialEnumOptions(EnumOptions): class SpecialEnum(Enum): @classmethod - def __init_subclass_with_meta__(cls, other_attr='default', **options): + def __init_subclass_with_meta__(cls, other_attr="default", **options): _meta = SpecialEnumOptions(cls) _meta.other_attr = other_attr super(SpecialEnum, cls).__init_subclass_with_meta__(_meta=_meta, **options) def test_special_enum_could_be_subclassed(): + class MyEnum(SpecialEnum): class Meta: - other_attr = 'yeah!' + other_attr = "yeah!" - assert MyEnum._meta.other_attr == 'yeah!' + assert MyEnum._meta.other_attr == "yeah!" def test_special_enum_could_be_subclassed_default(): + class MyEnum(SpecialEnum): pass - assert MyEnum._meta.other_attr == 'default' + assert MyEnum._meta.other_attr == "default" def test_special_enum_inherit_meta_options(): + class MyEnum(SpecialEnum): pass - assert MyEnum._meta.name == 'MyEnum' + assert MyEnum._meta.name == "MyEnum" diff --git a/graphene/tests/issues/test_490.py b/graphene/tests/issues/test_490.py index 9bd00590..4453e2a6 100644 --- a/graphene/tests/issues/test_490.py +++ b/graphene/tests/issues/test_490.py @@ -11,14 +11,14 @@ class Query(graphene.ObjectType): def test_issue(): - query_string = ''' + query_string = """ query myQuery { someField(from: "Oh") } - ''' + """ schema = graphene.Schema(query=Query) result = schema.execute(query_string) assert not result.errors - assert result.data['someField'] == 'Oh' + assert result.data["someField"] == "Oh" diff --git a/graphene/tests/issues/test_720.py b/graphene/tests/issues/test_720.py index 8cd99bdd..8ac611ee 100644 --- a/graphene/tests/issues/test_720.py +++ b/graphene/tests/issues/test_720.py @@ -10,12 +10,14 @@ class MyInputClass(graphene.InputObjectType): @classmethod def __init_subclass_with_meta__( - cls, container=None, _meta=None, fields=None, **options): + cls, container=None, _meta=None, fields=None, **options + ): if _meta is None: _meta = graphene.types.inputobjecttype.InputObjectTypeOptions(cls) _meta.fields = fields super(MyInputClass, cls).__init_subclass_with_meta__( - container=container, _meta=_meta, **options) + container=container, _meta=_meta, **options + ) class MyInput(MyInputClass): @@ -28,15 +30,15 @@ class Query(graphene.ObjectType): myField = graphene.Field(graphene.String, input=graphene.Argument(MyInput)) def resolve_myField(parent, info, input): - return 'ok' + return "ok" def test_issue(): - query_string = ''' + query_string = """ query myQuery { myField(input: {x: 1}) } - ''' + """ schema = graphene.Schema(query=Query) result = schema.execute(query_string) diff --git a/graphene/types/__init__.py b/graphene/types/__init__.py index b5b9427c..570664db 100644 --- a/graphene/types/__init__.py +++ b/graphene/types/__init__.py @@ -24,33 +24,32 @@ from .abstracttype import AbstractType __all__ = [ - 'ObjectType', - 'InputObjectType', - 'Interface', - 'Mutation', - 'Enum', - 'Field', - 'InputField', - 'Schema', - 'Scalar', - 'String', - 'ID', - 'Int', - 'Float', - 'Date', - 'DateTime', - 'Time', - 'JSONString', - 'UUID', - 'Boolean', - 'List', - 'NonNull', - 'Argument', - 'Dynamic', - 'Union', - 'Context', - 'ResolveInfo', - + "ObjectType", + "InputObjectType", + "Interface", + "Mutation", + "Enum", + "Field", + "InputField", + "Schema", + "Scalar", + "String", + "ID", + "Int", + "Float", + "Date", + "DateTime", + "Time", + "JSONString", + "UUID", + "Boolean", + "List", + "NonNull", + "Argument", + "Dynamic", + "Union", + "Context", + "ResolveInfo", # Deprecated - 'AbstractType', + "AbstractType", ] diff --git a/graphene/types/argument.py b/graphene/types/argument.py index 4431de53..20ea84b7 100644 --- a/graphene/types/argument.py +++ b/graphene/types/argument.py @@ -9,7 +9,15 @@ from .utils import get_type class Argument(MountedType): - def __init__(self, type, default_value=None, description=None, name=None, required=False, _creation_counter=None): + def __init__( + self, + type, + default_value=None, + description=None, + name=None, + required=False, + _creation_counter=None, + ): super(Argument, self).__init__(_creation_counter=_creation_counter) if required: @@ -26,10 +34,10 @@ class Argument(MountedType): def __eq__(self, other): return isinstance(other, Argument) and ( - self.name == other.name and - self.type == other.type and - self.default_value == other.default_value and - self.description == other.description + self.name == other.name + and self.type == other.type + and self.default_value == other.default_value + and self.description == other.description ) @@ -37,6 +45,7 @@ def to_arguments(args, extra_args=None): from .unmountedtype import UnmountedType from .field import Field from .inputfield import InputField + if extra_args: extra_args = sorted(extra_args.items(), key=lambda f: f[1]) else: @@ -55,17 +64,21 @@ def to_arguments(args, extra_args=None): arg = Argument.mounted(arg) if isinstance(arg, (InputField, Field)): - raise ValueError('Expected {} to be Argument, but received {}. Try using Argument({}).'.format( - default_name, - type(arg).__name__, - arg.type - )) + raise ValueError( + "Expected {} to be Argument, but received {}. Try using Argument({}).".format( + default_name, type(arg).__name__, arg.type + ) + ) if not isinstance(arg, Argument): raise ValueError('Unknown argument "{}".'.format(default_name)) arg_name = default_name or arg.name - assert arg_name not in arguments, 'More than one Argument have same name "{}".'.format(arg_name) + assert ( + arg_name not in arguments + ), 'More than one Argument have same name "{}".'.format( + arg_name + ) arguments[arg_name] = arg return arguments diff --git a/graphene/types/base.py b/graphene/types/base.py index 3bbd42d1..3c37b8dd 100644 --- a/graphene/types/base.py +++ b/graphene/types/base.py @@ -28,7 +28,7 @@ class BaseType(SubclassWithMeta): @classmethod def create_type(cls, class_name, **options): - return type(class_name, (cls, ), {'Meta': options}) + return type(class_name, (cls,), {"Meta": options}) @classmethod def __init_subclass_with_meta__(cls, name=None, description=None, _meta=None): diff --git a/graphene/types/context.py b/graphene/types/context.py index bac2073c..dba51958 100644 --- a/graphene/types/context.py +++ b/graphene/types/context.py @@ -1,4 +1,5 @@ class Context(object): + def __init__(self, **params): for key, value in params.items(): setattr(self, key, value) diff --git a/graphene/types/datetime.py b/graphene/types/datetime.py index bdf45f55..739032b0 100644 --- a/graphene/types/datetime.py +++ b/graphene/types/datetime.py @@ -9,19 +9,19 @@ from .scalars import Scalar class Date(Scalar): - ''' + """ The `Date` scalar type represents a Date value as specified by [iso8601](https://en.wikipedia.org/wiki/ISO_8601). - ''' + """ @staticmethod def serialize(date): if isinstance(date, datetime.datetime): date = date.date() - assert isinstance(date, datetime.date), ( - 'Received not compatible date "{}"'.format(repr(date)) - ) + assert isinstance( + date, datetime.date + ), 'Received not compatible date "{}"'.format(repr(date)) return date.isoformat() @classmethod @@ -38,17 +38,17 @@ class Date(Scalar): class DateTime(Scalar): - ''' + """ The `DateTime` scalar type represents a DateTime value as specified by [iso8601](https://en.wikipedia.org/wiki/ISO_8601). - ''' + """ @staticmethod def serialize(dt): - assert isinstance(dt, (datetime.datetime, datetime.date)), ( - 'Received not compatible datetime "{}"'.format(repr(dt)) - ) + assert isinstance( + dt, (datetime.datetime, datetime.date) + ), 'Received not compatible datetime "{}"'.format(repr(dt)) return dt.isoformat() @classmethod @@ -65,17 +65,17 @@ class DateTime(Scalar): class Time(Scalar): - ''' + """ The `Time` scalar type represents a Time value as specified by [iso8601](https://en.wikipedia.org/wiki/ISO_8601). - ''' + """ @staticmethod def serialize(time): - assert isinstance(time, datetime.time), ( - 'Received not compatible time "{}"'.format(repr(time)) - ) + assert isinstance( + time, datetime.time + ), 'Received not compatible time "{}"'.format(repr(time)) return time.isoformat() @classmethod diff --git a/graphene/types/definitions.py b/graphene/types/definitions.py index 1fdb2d47..a914008c 100644 --- a/graphene/types/definitions.py +++ b/graphene/types/definitions.py @@ -1,16 +1,21 @@ -from graphql import (GraphQLEnumType, GraphQLInputObjectType, - GraphQLInterfaceType, GraphQLObjectType, - GraphQLScalarType, GraphQLUnionType) +from graphql import ( + GraphQLEnumType, + GraphQLInputObjectType, + GraphQLInterfaceType, + GraphQLObjectType, + GraphQLScalarType, + GraphQLUnionType, +) class GrapheneGraphQLType(object): - ''' + """ A class for extending the base GraphQLType with the related graphene_type - ''' + """ def __init__(self, *args, **kwargs): - self.graphene_type = kwargs.pop('graphene_type') + self.graphene_type = kwargs.pop("graphene_type") super(GrapheneGraphQLType, self).__init__(*args, **kwargs) diff --git a/graphene/types/dynamic.py b/graphene/types/dynamic.py index 0efbd081..588c53bb 100644 --- a/graphene/types/dynamic.py +++ b/graphene/types/dynamic.py @@ -5,10 +5,10 @@ from .mountedtype import MountedType class Dynamic(MountedType): - ''' + """ A Dynamic Type let us get the type in runtime when we generate the schema. So we can have lazy fields. - ''' + """ def __init__(self, type, with_schema=False, _creation_counter=None): super(Dynamic, self).__init__(_creation_counter=_creation_counter) diff --git a/graphene/types/enum.py b/graphene/types/enum.py index 4f571214..96a322ad 100644 --- a/graphene/types/enum.py +++ b/graphene/types/enum.py @@ -29,9 +29,11 @@ class EnumMeta(SubclassWithMeta_Meta): enum_members = OrderedDict(classdict, __eq__=eq_enum) # We remove the Meta attribute from the class to not collide # with the enum values. - enum_members.pop('Meta', None) + enum_members.pop("Meta", None) enum = PyEnum(cls.__name__, enum_members) - return SubclassWithMeta_Meta.__new__(cls, name, bases, OrderedDict(classdict, __enum__=enum), **options) + return SubclassWithMeta_Meta.__new__( + cls, name, bases, OrderedDict(classdict, __enum__=enum), **options + ) def get(cls, value): return cls._meta.enum(value) @@ -44,7 +46,7 @@ class EnumMeta(SubclassWithMeta_Meta): def __call__(cls, *args, **kwargs): # noqa: N805 if cls is Enum: - description = kwargs.pop('description', None) + description = kwargs.pop("description", None) return cls.from_enum(PyEnum(*args, **kwargs), description=description) return super(EnumMeta, cls).__call__(*args, **kwargs) # return cls._meta.enum(*args, **kwargs) @@ -52,12 +54,12 @@ class EnumMeta(SubclassWithMeta_Meta): def from_enum(cls, enum, description=None, deprecation_reason=None): # noqa: N805 description = description or enum.__doc__ meta_dict = { - 'enum': enum, - 'description': description, - 'deprecation_reason': deprecation_reason + "enum": enum, + "description": description, + "deprecation_reason": deprecation_reason, } - meta_class = type('Meta', (object,), meta_dict) - return type(meta_class.enum.__name__, (Enum,), {'Meta': meta_class}) + meta_class = type("Meta", (object,), meta_dict) + return type(meta_class.enum.__name__, (Enum,), {"Meta": meta_class}) class Enum(six.with_metaclass(EnumMeta, UnmountedType, BaseType)): @@ -67,7 +69,7 @@ class Enum(six.with_metaclass(EnumMeta, UnmountedType, BaseType)): if not _meta: _meta = EnumOptions(cls) _meta.enum = enum or cls.__enum__ - _meta.deprecation_reason = options.pop('deprecation_reason', None) + _meta.deprecation_reason = options.pop("deprecation_reason", None) for key, value in _meta.enum.__members__.items(): setattr(cls, key, value) @@ -75,8 +77,8 @@ class Enum(six.with_metaclass(EnumMeta, UnmountedType, BaseType)): @classmethod def get_type(cls): - ''' + """ This function is called when the unmounted type (Enum instance) is mounted (as a Field, InputField or Argument) - ''' + """ return cls diff --git a/graphene/types/field.py b/graphene/types/field.py index 4a79fcac..5db5530e 100644 --- a/graphene/types/field.py +++ b/graphene/types/field.py @@ -20,17 +20,27 @@ def source_resolver(source, root, info, **args): class Field(MountedType): - def __init__(self, type, args=None, resolver=None, source=None, - deprecation_reason=None, name=None, description=None, - required=False, _creation_counter=None, default_value=None, - **extra_args): + def __init__( + self, + type, + args=None, + resolver=None, + source=None, + deprecation_reason=None, + name=None, + description=None, + required=False, + _creation_counter=None, + default_value=None, + **extra_args + ): super(Field, self).__init__(_creation_counter=_creation_counter) assert not args or isinstance(args, Mapping), ( 'Arguments in a field have to be a mapping, received "{}".' ).format(args) - assert not (source and resolver), ( - 'A Field cannot have a source and a resolver in at the same time.' - ) + assert not ( + source and resolver + ), "A Field cannot have a source and a resolver in at the same time." assert not callable(default_value), ( 'The default value can not be a function but received "{}".' ).format(base_type(default_value)) @@ -40,12 +50,12 @@ class Field(MountedType): # Check if name is actually an argument of the field if isinstance(name, (Argument, UnmountedType)): - extra_args['name'] = name + extra_args["name"] = name name = None # Check if source is actually an argument of the field if isinstance(source, (Argument, UnmountedType)): - extra_args['source'] = source + extra_args["source"] = source source = None self.name = name diff --git a/graphene/types/generic.py b/graphene/types/generic.py index b2b15f00..e5470dd9 100644 --- a/graphene/types/generic.py +++ b/graphene/types/generic.py @@ -1,7 +1,13 @@ from __future__ import unicode_literals -from graphql.language.ast import (BooleanValue, FloatValue, IntValue, - ListValue, ObjectValue, StringValue) +from graphql.language.ast import ( + BooleanValue, + FloatValue, + IntValue, + ListValue, + ObjectValue, + StringValue, +) from graphene.types.scalars import MAX_INT, MIN_INT @@ -35,6 +41,9 @@ class GenericScalar(Scalar): elif isinstance(ast, ListValue): return [GenericScalar.parse_literal(value) for value in ast.values] elif isinstance(ast, ObjectValue): - return {field.name.value: GenericScalar.parse_literal(field.value) for field in ast.fields} + return { + field.name.value: GenericScalar.parse_literal(field.value) + for field in ast.fields + } else: return None diff --git a/graphene/types/inputfield.py b/graphene/types/inputfield.py index 0510ab4a..df6285b5 100644 --- a/graphene/types/inputfield.py +++ b/graphene/types/inputfield.py @@ -5,9 +5,17 @@ from .utils import get_type class InputField(MountedType): - def __init__(self, type, name=None, default_value=None, - deprecation_reason=None, description=None, - required=False, _creation_counter=None, **extra_args): + def __init__( + self, + type, + name=None, + default_value=None, + deprecation_reason=None, + description=None, + required=False, + _creation_counter=None, + **extra_args + ): super(InputField, self).__init__(_creation_counter=_creation_counter) self.name = name if required: diff --git a/graphene/types/inputobjecttype.py b/graphene/types/inputobjecttype.py index b84fc0fd..dc6e0048 100644 --- a/graphene/types/inputobjecttype.py +++ b/graphene/types/inputobjecttype.py @@ -17,6 +17,7 @@ class InputObjectTypeOptions(BaseOptions): class InputObjectTypeContainer(dict, BaseType): + class Meta: abstract = True @@ -30,14 +31,14 @@ class InputObjectTypeContainer(dict, BaseType): class InputObjectType(UnmountedType, BaseType): - ''' + """ Input Object Type Definition An input object defines a structured collection of fields which may be supplied to a field argument. Using `NonNull` will ensure that a value must be provided by the query - ''' + """ @classmethod def __init_subclass_with_meta__(cls, container=None, _meta=None, **options): @@ -46,9 +47,7 @@ class InputObjectType(UnmountedType, BaseType): fields = OrderedDict() for base in reversed(cls.__mro__): - fields.update( - yank_fields_from_attrs(base.__dict__, _as=InputField) - ) + fields.update(yank_fields_from_attrs(base.__dict__, _as=InputField)) if _meta.fields: _meta.fields.update(fields) @@ -57,13 +56,12 @@ class InputObjectType(UnmountedType, BaseType): if container is None: container = type(cls.__name__, (InputObjectTypeContainer, cls), {}) _meta.container = container - super(InputObjectType, cls).__init_subclass_with_meta__( - _meta=_meta, **options) + super(InputObjectType, cls).__init_subclass_with_meta__(_meta=_meta, **options) @classmethod def get_type(cls): - ''' + """ This function is called when the unmounted type (InputObjectType instance) is mounted (as a Field, InputField or Argument) - ''' + """ return cls diff --git a/graphene/types/interface.py b/graphene/types/interface.py index dbc3b476..f2c9749c 100644 --- a/graphene/types/interface.py +++ b/graphene/types/interface.py @@ -15,14 +15,15 @@ class InterfaceOptions(BaseOptions): class Interface(BaseType): - ''' + """ Interface Type Definition When a field can return one of a heterogeneous set of types, a Interface type is used to describe what types are possible, what fields are in common across all types, as well as a function to determine which type is actually used when the field is resolved. - ''' + """ + @classmethod def __init_subclass_with_meta__(cls, _meta=None, **options): if not _meta: @@ -30,9 +31,7 @@ class Interface(BaseType): fields = OrderedDict() for base in reversed(cls.__mro__): - fields.update( - yank_fields_from_attrs(base.__dict__, _as=Field) - ) + fields.update(yank_fields_from_attrs(base.__dict__, _as=Field)) if _meta.fields: _meta.fields.update(fields) @@ -44,6 +43,7 @@ class Interface(BaseType): @classmethod def resolve_type(cls, instance, info): from .objecttype import ObjectType + if isinstance(instance, ObjectType): return type(instance) diff --git a/graphene/types/json.py b/graphene/types/json.py index 4c37e11b..495943a9 100644 --- a/graphene/types/json.py +++ b/graphene/types/json.py @@ -8,7 +8,7 @@ from .scalars import Scalar class JSONString(Scalar): - '''JSON String''' + """JSON String""" @staticmethod def serialize(dt): diff --git a/graphene/types/mountedtype.py b/graphene/types/mountedtype.py index dae0cc61..47c828b9 100644 --- a/graphene/types/mountedtype.py +++ b/graphene/types/mountedtype.py @@ -6,12 +6,12 @@ class MountedType(OrderedType): @classmethod def mounted(cls, unmounted): # noqa: N802 - ''' + """ Mount the UnmountedType instance - ''' - assert isinstance(unmounted, UnmountedType), ( - '{} can\'t mount {}' - ).format(cls.__name__, repr(unmounted)) + """ + assert isinstance(unmounted, UnmountedType), ("{} can't mount {}").format( + cls.__name__, repr(unmounted) + ) return cls( unmounted.get_type(), diff --git a/graphene/types/mutation.py b/graphene/types/mutation.py index fdfd5515..aa8f86bb 100644 --- a/graphene/types/mutation.py +++ b/graphene/types/mutation.py @@ -21,37 +21,39 @@ class MutationOptions(ObjectTypeOptions): class Mutation(ObjectType): - ''' + """ Mutation Type Definition - ''' + """ + @classmethod - def __init_subclass_with_meta__(cls, resolver=None, output=None, arguments=None, - _meta=None, **options): + def __init_subclass_with_meta__( + cls, resolver=None, output=None, arguments=None, _meta=None, **options + ): if not _meta: _meta = MutationOptions(cls) - output = output or getattr(cls, 'Output', None) + output = output or getattr(cls, "Output", None) fields = {} if not output: # If output is defined, we don't need to get the fields fields = OrderedDict() for base in reversed(cls.__mro__): - fields.update( - yank_fields_from_attrs(base.__dict__, _as=Field) - ) + fields.update(yank_fields_from_attrs(base.__dict__, _as=Field)) output = cls if not arguments: - input_class = getattr(cls, 'Arguments', None) + input_class = getattr(cls, "Arguments", None) if not input_class: - input_class = getattr(cls, 'Input', None) + input_class = getattr(cls, "Input", None) if input_class: - warn_deprecation(( - "Please use {name}.Arguments instead of {name}.Input." - "Input is now only used in ClientMutationID.\n" - "Read more:" - " https://github.com/graphql-python/graphene/blob/v2.0.0/UPGRADE-v2.0.md#mutation-input" - ).format(name=cls.__name__)) + warn_deprecation( + ( + "Please use {name}.Arguments instead of {name}.Input." + "Input is now only used in ClientMutationID.\n" + "Read more:" + " https://github.com/graphql-python/graphene/blob/v2.0.0/UPGRADE-v2.0.md#mutation-input" + ).format(name=cls.__name__) + ) if input_class: arguments = props(input_class) @@ -59,8 +61,8 @@ class Mutation(ObjectType): arguments = {} if not resolver: - mutate = getattr(cls, 'mutate', None) - assert mutate, 'All mutations must define a mutate method in it' + mutate = getattr(cls, "mutate", None) + assert mutate, "All mutations must define a mutate method in it" resolver = get_unbound_function(mutate) if _meta.fields: @@ -72,11 +74,12 @@ class Mutation(ObjectType): _meta.resolver = resolver _meta.arguments = arguments - super(Mutation, cls).__init_subclass_with_meta__( - _meta=_meta, **options) + super(Mutation, cls).__init_subclass_with_meta__(_meta=_meta, **options) @classmethod - def Field(cls, name=None, description=None, deprecation_reason=None, required=False): + def Field( + cls, name=None, description=None, deprecation_reason=None, required=False + ): return Field( cls._meta.output, args=cls._meta.arguments, diff --git a/graphene/types/objecttype.py b/graphene/types/objecttype.py index c6e4d5d7..be4addb2 100644 --- a/graphene/types/objecttype.py +++ b/graphene/types/objecttype.py @@ -17,17 +17,22 @@ class ObjectTypeOptions(BaseOptions): class ObjectType(BaseType): - ''' + """ Object Type Definition Almost all of the GraphQL types you define will be object types. Object types have a name, but most importantly describe their fields. - ''' + """ + @classmethod def __init_subclass_with_meta__( - cls, interfaces=(), - possible_types=(), - default_resolver=None, _meta=None, **options): + cls, + interfaces=(), + possible_types=(), + default_resolver=None, + _meta=None, + **options + ): if not _meta: _meta = ObjectTypeOptions(cls) @@ -40,13 +45,11 @@ class ObjectType(BaseType): fields.update(interface._meta.fields) for base in reversed(cls.__mro__): - fields.update( - yank_fields_from_attrs(base.__dict__, _as=Field) - ) + fields.update(yank_fields_from_attrs(base.__dict__, _as=Field)) assert not (possible_types and cls.is_type_of), ( - '{name}.Meta.possible_types will cause type collision with {name}.is_type_of. ' - 'Please use one or other.' + "{name}.Meta.possible_types will cause type collision with {name}.is_type_of. " + "Please use one or other." ).format(name=cls.__name__) if _meta.fields: @@ -82,8 +85,7 @@ class ObjectType(BaseType): for name, field in fields_iter: try: val = kwargs.pop( - name, - field.default_value if isinstance(field, Field) else None + name, field.default_value if isinstance(field, Field) else None ) setattr(self, name, val) except KeyError: @@ -92,14 +94,15 @@ class ObjectType(BaseType): if kwargs: for prop in list(kwargs): try: - if isinstance(getattr(self.__class__, prop), property) or prop.startswith('_'): + if isinstance( + getattr(self.__class__, prop), property + ) or prop.startswith("_"): setattr(self, prop, kwargs.pop(prop)) except AttributeError: pass if kwargs: raise TypeError( "'{}' is an invalid keyword argument for {}".format( - list(kwargs)[0], - self.__class__.__name__ + list(kwargs)[0], self.__class__.__name__ ) ) diff --git a/graphene/types/resolver.py b/graphene/types/resolver.py index e5652c2d..888aba8a 100644 --- a/graphene/types/resolver.py +++ b/graphene/types/resolver.py @@ -11,7 +11,7 @@ default_resolver = attr_resolver def set_default_resolver(resolver): global default_resolver - assert callable(resolver), 'Received non-callable resolver.' + assert callable(resolver), "Received non-callable resolver." default_resolver = resolver diff --git a/graphene/types/scalars.py b/graphene/types/scalars.py index e34d7a10..dfb63e52 100644 --- a/graphene/types/scalars.py +++ b/graphene/types/scalars.py @@ -1,6 +1,5 @@ import six -from graphql.language.ast import (BooleanValue, FloatValue, IntValue, - StringValue) +from graphql.language.ast import BooleanValue, FloatValue, IntValue, StringValue from .base import BaseOptions, BaseType from .unmountedtype import UnmountedType @@ -11,13 +10,14 @@ class ScalarOptions(BaseOptions): class Scalar(UnmountedType, BaseType): - ''' + """ Scalar Type Definition The leaf values of any request and input values to arguments are Scalars (or Enums) and are defined with a name and a series of functions used to parse input from ast or variables and to ensure validity. - ''' + """ + @classmethod def __init_subclass_with_meta__(cls, **options): _meta = ScalarOptions(cls) @@ -29,10 +29,10 @@ class Scalar(UnmountedType, BaseType): @classmethod def get_type(cls): - ''' + """ This function is called when the unmounted type (Scalar instance) is mounted (as a Field, InputField or Argument) - ''' + """ return cls @@ -46,12 +46,12 @@ MIN_INT = -2147483648 class Int(Scalar): - ''' + """ The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^53 - 1) and 2^53 - 1 since represented in JSON as double-precision floating point numbers specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point). - ''' + """ @staticmethod def coerce_int(value): @@ -77,11 +77,11 @@ class Int(Scalar): class Float(Scalar): - ''' + """ The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point). - ''' + """ @staticmethod def coerce_float(value): @@ -101,16 +101,16 @@ class Float(Scalar): class String(Scalar): - ''' + """ The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text. - ''' + """ @staticmethod def coerce_string(value): if isinstance(value, bool): - return u'true' if value else u'false' + return u"true" if value else u"false" return six.text_type(value) serialize = coerce_string @@ -123,9 +123,9 @@ class String(Scalar): class Boolean(Scalar): - ''' + """ The `Boolean` scalar type represents `true` or `false`. - ''' + """ serialize = bool parse_value = bool @@ -137,13 +137,13 @@ class Boolean(Scalar): class ID(Scalar): - ''' + """ The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `"4"`) or integer (such as `4`) input value will be accepted as an ID. - ''' + """ serialize = str parse_value = str diff --git a/graphene/types/schema.py b/graphene/types/schema.py index 72bae81f..a885c88a 100644 --- a/graphene/types/schema.py +++ b/graphene/types/schema.py @@ -1,8 +1,11 @@ import inspect from graphql import GraphQLObjectType, GraphQLSchema, graphql, is_type -from graphql.type.directives import (GraphQLDirective, GraphQLIncludeDirective, - GraphQLSkipDirective) +from graphql.type.directives import ( + GraphQLDirective, + GraphQLIncludeDirective, + GraphQLSkipDirective, +) from graphql.type.introspection import IntrospectionSchema from graphql.utils.introspection_query import introspection_query from graphql.utils.schema_printer import print_schema @@ -15,8 +18,7 @@ from .typemap import TypeMap, is_graphene_type def assert_valid_root_type(_type): if _type is None: return - is_graphene_objecttype = inspect.isclass( - _type) and issubclass(_type, ObjectType) + is_graphene_objecttype = inspect.isclass(_type) and issubclass(_type, ObjectType) is_graphql_objecttype = isinstance(_type, GraphQLObjectType) assert is_graphene_objecttype or is_graphql_objecttype, ( "Type {} is not a valid ObjectType." @@ -24,20 +26,22 @@ def assert_valid_root_type(_type): class Schema(GraphQLSchema): - ''' + """ Schema Definition A Schema is created by supplying the root types of each type of operation, query and mutation (optional). - ''' + """ - def __init__(self, - query=None, - mutation=None, - subscription=None, - directives=None, - types=None, - auto_camelcase=True): + def __init__( + self, + query=None, + mutation=None, + subscription=None, + directives=None, + types=None, + auto_camelcase=True, + ): assert_valid_root_type(query) assert_valid_root_type(mutation) assert_valid_root_type(subscription) @@ -49,9 +53,10 @@ class Schema(GraphQLSchema): if directives is None: directives = [GraphQLIncludeDirective, GraphQLSkipDirective] - assert all(isinstance(d, GraphQLDirective) for d in directives), \ - 'Schema directives must be List[GraphQLDirective] if provided but got: {}.'.format( - directives + assert all( + isinstance(d, GraphQLDirective) for d in directives + ), "Schema directives must be List[GraphQLDirective] if provided but got: {}.".format( + directives ) self._directives = directives self.build_typemap() @@ -66,16 +71,15 @@ class Schema(GraphQLSchema): return self.get_graphql_type(self._subscription) def __getattr__(self, type_name): - ''' + """ This function let the developer select a type in a given schema by accessing its attrs. Example: using schema.Query for accessing the "Query" type in the Schema - ''' + """ _type = super(Schema, self).get_type(type_name) if _type is None: - raise AttributeError( - 'Type "{}" not found in the Schema'.format(type_name)) + raise AttributeError('Type "{}" not found in the Schema'.format(type_name)) if isinstance(_type, GrapheneGraphQLType): return _type.graphene_type return _type @@ -88,7 +92,8 @@ class Schema(GraphQLSchema): if is_graphene_type(_type): graphql_type = self.get_type(_type._meta.name) assert graphql_type, "Type {} not found in this schema.".format( - _type._meta.name) + _type._meta.name + ) assert graphql_type.graphene_type == _type return graphql_type raise Exception("{} is not a valid GraphQL type.".format(_type)) @@ -113,12 +118,10 @@ class Schema(GraphQLSchema): self._query, self._mutation, self._subscription, - IntrospectionSchema + IntrospectionSchema, ] if self.types: initial_types += self.types self._type_map = TypeMap( - initial_types, - auto_camelcase=self.auto_camelcase, - schema=self + initial_types, auto_camelcase=self.auto_camelcase, schema=self ) diff --git a/graphene/types/structures.py b/graphene/types/structures.py index dcd9d5e3..dde68f0f 100644 --- a/graphene/types/structures.py +++ b/graphene/types/structures.py @@ -3,22 +3,21 @@ from .utils import get_type class Structure(UnmountedType): - ''' + """ A structure is a GraphQL type instance that wraps a main type with certain structure. - ''' + """ def __init__(self, of_type, *args, **kwargs): super(Structure, self).__init__(*args, **kwargs) if not isinstance(of_type, Structure) and isinstance(of_type, UnmountedType): cls_name = type(self).__name__ of_type_name = type(of_type).__name__ - raise Exception("{} could not have a mounted {}() as inner type. Try with {}({}).".format( - cls_name, - of_type_name, - cls_name, - of_type_name, - )) + raise Exception( + "{} could not have a mounted {}() as inner type. Try with {}({}).".format( + cls_name, of_type_name, cls_name, of_type_name + ) + ) self._of_type = of_type @property @@ -26,35 +25,35 @@ class Structure(UnmountedType): return get_type(self._of_type) def get_type(self): - ''' + """ This function is called when the unmounted type (List or NonNull instance) is mounted (as a Field, InputField or Argument) - ''' + """ return self class List(Structure): - ''' + """ List Modifier A list is a kind of type marker, a wrapping type which points to another type. Lists are often created within the context of defining the fields of an object type. - ''' + """ def __str__(self): - return '[{}]'.format(self.of_type) + return "[{}]".format(self.of_type) def __eq__(self, other): return isinstance(other, List) and ( - self.of_type == other.of_type and - self.args == other.args and - self.kwargs == other.kwargs + self.of_type == other.of_type + and self.args == other.args + and self.kwargs == other.kwargs ) class NonNull(Structure): - ''' + """ Non-Null Modifier A non-null is a kind of type marker, a wrapping type which points to another @@ -64,20 +63,20 @@ class NonNull(Structure): usually the id field of a database row will never be null. Note: the enforcement of non-nullability occurs within the executor. - ''' + """ def __init__(self, *args, **kwargs): super(NonNull, self).__init__(*args, **kwargs) assert not isinstance(self._of_type, NonNull), ( - 'Can only create NonNull of a Nullable GraphQLType but got: {}.' + "Can only create NonNull of a Nullable GraphQLType but got: {}." ).format(self._of_type) def __str__(self): - return '{}!'.format(self.of_type) + return "{}!".format(self.of_type) def __eq__(self, other): return isinstance(other, NonNull) and ( - self.of_type == other.of_type and - self.args == other.args and - self.kwargs == other.kwargs + self.of_type == other.of_type + and self.args == other.args + and self.kwargs == other.kwargs ) diff --git a/graphene/types/tests/test_abstracttype.py b/graphene/types/tests/test_abstracttype.py index 6ad35b75..6fee3b11 100644 --- a/graphene/types/tests/test_abstracttype.py +++ b/graphene/types/tests/test_abstracttype.py @@ -16,7 +16,7 @@ class MyScalar(UnmountedType): def test_abstract_objecttype_warn_deprecation(mocker): - mocker.patch.object(abstracttype, 'warn_deprecation') + mocker.patch.object(abstracttype, "warn_deprecation") class MyAbstractType(AbstractType): field1 = MyScalar() @@ -25,6 +25,7 @@ def test_abstract_objecttype_warn_deprecation(mocker): def test_generate_objecttype_inherit_abstracttype(): + class MyAbstractType(AbstractType): field1 = MyScalar() @@ -34,5 +35,5 @@ def test_generate_objecttype_inherit_abstracttype(): assert MyObjectType._meta.description is None assert MyObjectType._meta.interfaces == () assert MyObjectType._meta.name == "MyObjectType" - assert list(MyObjectType._meta.fields.keys()) == ['field1', 'field2'] + assert list(MyObjectType._meta.fields.keys()) == ["field1", "field2"] assert list(map(type, MyObjectType._meta.fields.values())) == [Field, Field] diff --git a/graphene/types/tests/test_argument.py b/graphene/types/tests/test_argument.py index bc7b6e1c..b8f49a47 100644 --- a/graphene/types/tests/test_argument.py +++ b/graphene/types/tests/test_argument.py @@ -10,16 +10,16 @@ from ..structures import NonNull def test_argument(): - arg = Argument(String, default_value='a', description='desc', name='b') + arg = Argument(String, default_value="a", description="desc", name="b") assert arg.type == String - assert arg.default_value == 'a' - assert arg.description == 'desc' - assert arg.name == 'b' + assert arg.default_value == "a" + assert arg.description == "desc" + assert arg.name == "b" def test_argument_comparasion(): - arg1 = Argument(String, name='Hey', description='Desc', default_value='default') - arg2 = Argument(String, name='Hey', description='Desc', default_value='default') + arg1 = Argument(String, name="Hey", description="Desc", default_value="default") + arg2 = Argument(String, name="Hey", description="Desc", default_value="default") assert arg1 == arg2 assert arg1 != String() @@ -31,43 +31,36 @@ def test_argument_required(): def test_to_arguments(): - args = { - 'arg_string': Argument(String), - 'unmounted_arg': String(required=True) - } + args = {"arg_string": Argument(String), "unmounted_arg": String(required=True)} my_args = to_arguments(args) assert my_args == { - 'arg_string': Argument(String), - 'unmounted_arg': Argument(String, required=True) + "arg_string": Argument(String), + "unmounted_arg": Argument(String, required=True), } def test_to_arguments_raises_if_field(): - args = { - 'arg_string': Field(String), - } + args = {"arg_string": Field(String)} with pytest.raises(ValueError) as exc_info: to_arguments(args) assert str(exc_info.value) == ( - 'Expected arg_string to be Argument, but received Field. Try using ' - 'Argument(String).' + "Expected arg_string to be Argument, but received Field. Try using " + "Argument(String)." ) def test_to_arguments_raises_if_inputfield(): - args = { - 'arg_string': InputField(String), - } + args = {"arg_string": InputField(String)} with pytest.raises(ValueError) as exc_info: to_arguments(args) assert str(exc_info.value) == ( - 'Expected arg_string to be Argument, but received InputField. Try ' - 'using Argument(String).' + "Expected arg_string to be Argument, but received InputField. Try " + "using Argument(String)." ) diff --git a/graphene/types/tests/test_base.py b/graphene/types/tests/test_base.py index cd555ad5..d42d54fb 100644 --- a/graphene/types/tests/test_base.py +++ b/graphene/types/tests/test_base.py @@ -6,6 +6,7 @@ class CustomOptions(BaseOptions): class CustomType(BaseType): + @classmethod def __init_subclass_with_meta__(cls, **options): _meta = CustomOptions(cls) @@ -13,6 +14,7 @@ class CustomType(BaseType): def test_basetype(): + class MyBaseType(CustomType): pass @@ -22,8 +24,10 @@ def test_basetype(): def test_basetype_nones(): + class MyBaseType(CustomType): - '''Documentation''' + """Documentation""" + class Meta: name = None description = None @@ -34,11 +38,13 @@ def test_basetype_nones(): def test_basetype_custom(): + class MyBaseType(CustomType): - '''Documentation''' + """Documentation""" + class Meta: - name = 'Base' - description = 'Desc' + name = "Base" + description = "Desc" assert isinstance(MyBaseType._meta, CustomOptions) assert MyBaseType._meta.name == "Base" @@ -46,7 +52,7 @@ def test_basetype_custom(): def test_basetype_create(): - MyBaseType = CustomType.create_type('MyBaseType') + MyBaseType = CustomType.create_type("MyBaseType") assert isinstance(MyBaseType._meta, CustomOptions) assert MyBaseType._meta.name == "MyBaseType" @@ -54,7 +60,7 @@ def test_basetype_create(): def test_basetype_create_extra(): - MyBaseType = CustomType.create_type('MyBaseType', name='Base', description='Desc') + MyBaseType = CustomType.create_type("MyBaseType", name="Base", description="Desc") assert isinstance(MyBaseType._meta, CustomOptions) assert MyBaseType._meta.name == "Base" diff --git a/graphene/types/tests/test_datetime.py b/graphene/types/tests/test_datetime.py index 35e8c785..5165aa61 100644 --- a/graphene/types/tests/test_datetime.py +++ b/graphene/types/tests/test_datetime.py @@ -9,9 +9,9 @@ from ..schema import Schema class Query(ObjectType): - datetime = DateTime(_in=DateTime(name='in')) - date = Date(_in=Date(name='in')) - time = Time(_at=Time(name='at')) + datetime = DateTime(_in=DateTime(name="in")) + date = Date(_in=Date(name="in")) + time = Time(_at=Time(name="at")) def resolve_datetime(self, info, _in=None): return _in @@ -30,35 +30,34 @@ def test_datetime_query(): now = datetime.datetime.now().replace(tzinfo=pytz.utc) isoformat = now.isoformat() - result = schema.execute('''{ datetime(in: "%s") }''' % isoformat) + result = schema.execute("""{ datetime(in: "%s") }""" % isoformat) assert not result.errors - assert result.data == {'datetime': isoformat} + assert result.data == {"datetime": isoformat} def test_date_query(): now = datetime.datetime.now().replace(tzinfo=pytz.utc).date() isoformat = now.isoformat() - result = schema.execute('''{ date(in: "%s") }''' % isoformat) + result = schema.execute("""{ date(in: "%s") }""" % isoformat) assert not result.errors - assert result.data == {'date': isoformat} + assert result.data == {"date": isoformat} def test_time_query(): now = datetime.datetime.now().replace(tzinfo=pytz.utc) - time = datetime.time(now.hour, now.minute, now.second, now.microsecond, - now.tzinfo) + time = datetime.time(now.hour, now.minute, now.second, now.microsecond, now.tzinfo) isoformat = time.isoformat() - result = schema.execute('''{ time(at: "%s") }''' % isoformat) + result = schema.execute("""{ time(at: "%s") }""" % isoformat) assert not result.errors - assert result.data == {'time': isoformat} + assert result.data == {"time": isoformat} def test_bad_datetime_query(): not_a_date = "Some string that's not a date" - result = schema.execute('''{ datetime(in: "%s") }''' % not_a_date) + result = schema.execute("""{ datetime(in: "%s") }""" % not_a_date) assert len(result.errors) == 1 assert isinstance(result.errors[0], GraphQLError) @@ -68,7 +67,7 @@ def test_bad_datetime_query(): def test_bad_date_query(): not_a_date = "Some string that's not a date" - result = schema.execute('''{ date(in: "%s") }''' % not_a_date) + result = schema.execute("""{ date(in: "%s") }""" % not_a_date) assert len(result.errors) == 1 assert isinstance(result.errors[0], GraphQLError) @@ -78,7 +77,7 @@ def test_bad_date_query(): def test_bad_time_query(): not_a_date = "Some string that's not a date" - result = schema.execute('''{ time(at: "%s") }''' % not_a_date) + result = schema.execute("""{ time(at: "%s") }""" % not_a_date) assert len(result.errors) == 1 assert isinstance(result.errors[0], GraphQLError) @@ -90,10 +89,11 @@ def test_datetime_query_variable(): isoformat = now.isoformat() result = schema.execute( - '''query Test($date: DateTime){ datetime(in: $date) }''', - variable_values={'date': isoformat}) + """query Test($date: DateTime){ datetime(in: $date) }""", + variable_values={"date": isoformat}, + ) assert not result.errors - assert result.data == {'datetime': isoformat} + assert result.data == {"datetime": isoformat} def test_date_query_variable(): @@ -101,20 +101,21 @@ def test_date_query_variable(): isoformat = now.isoformat() result = schema.execute( - '''query Test($date: Date){ date(in: $date) }''', - variable_values={'date': isoformat}) + """query Test($date: Date){ date(in: $date) }""", + variable_values={"date": isoformat}, + ) assert not result.errors - assert result.data == {'date': isoformat} + assert result.data == {"date": isoformat} def test_time_query_variable(): now = datetime.datetime.now().replace(tzinfo=pytz.utc) - time = datetime.time(now.hour, now.minute, now.second, now.microsecond, - now.tzinfo) + time = datetime.time(now.hour, now.minute, now.second, now.microsecond, now.tzinfo) isoformat = time.isoformat() result = schema.execute( - '''query Test($time: Time){ time(at: $time) }''', - variable_values={'time': isoformat}) + """query Test($time: Time){ time(at: $time) }""", + variable_values={"time": isoformat}, + ) assert not result.errors - assert result.data == {'time': isoformat} + assert result.data == {"time": isoformat} diff --git a/graphene/types/tests/test_definition.py b/graphene/types/tests/test_definition.py index d3cd2c38..2cff3002 100644 --- a/graphene/types/tests/test_definition.py +++ b/graphene/types/tests/test_definition.py @@ -58,11 +58,11 @@ class MyInterface(Interface): class MyUnion(Union): class Meta: - types = (Article, ) + types = (Article,) class MyEnum(Enum): - foo = 'foo' + foo = "foo" class MyInputObjectType(InputObjectType): @@ -74,24 +74,24 @@ def test_defines_a_query_only_schema(): assert blog_schema.get_query_type().graphene_type == Query - article_field = Query._meta.fields['article'] + article_field = Query._meta.fields["article"] assert article_field.type == Article - assert article_field.type._meta.name == 'Article' + assert article_field.type._meta.name == "Article" article_field_type = article_field.type assert issubclass(article_field_type, ObjectType) - title_field = article_field_type._meta.fields['title'] + title_field = article_field_type._meta.fields["title"] assert title_field.type == String - author_field = article_field_type._meta.fields['author'] + author_field = article_field_type._meta.fields["author"] author_field_type = author_field.type assert issubclass(author_field_type, ObjectType) - recent_article_field = author_field_type._meta.fields['recent_article'] + recent_article_field = author_field_type._meta.fields["recent_article"] assert recent_article_field.type == Article - feed_field = Query._meta.fields['feed'] + feed_field = Query._meta.fields["feed"] assert feed_field.type.of_type == Article @@ -100,9 +100,9 @@ def test_defines_a_mutation_schema(): assert blog_schema.get_mutation_type().graphene_type == Mutation - write_mutation = Mutation._meta.fields['write_article'] + write_mutation = Mutation._meta.fields["write_article"] assert write_mutation.type == Article - assert write_mutation.type._meta.name == 'Article' + assert write_mutation.type._meta.name == "Article" def test_defines_a_subscription_schema(): @@ -110,12 +110,13 @@ def test_defines_a_subscription_schema(): assert blog_schema.get_subscription_type().graphene_type == Subscription - subscription = Subscription._meta.fields['article_subscribe'] + subscription = Subscription._meta.fields["article_subscribe"] assert subscription.type == Article - assert subscription.type._meta.name == 'Article' + assert subscription.type._meta.name == "Article" def test_includes_nested_input_objects_in_the_map(): + class NestedInputObject(InputObjectType): value = String() @@ -128,36 +129,31 @@ def test_includes_nested_input_objects_in_the_map(): class SomeSubscription(Mutation): subscribe_to_something = Field(Article, input=Argument(SomeInputObject)) - schema = Schema( - query=Query, - mutation=SomeMutation, - subscription=SomeSubscription - ) + schema = Schema(query=Query, mutation=SomeMutation, subscription=SomeSubscription) - assert schema.get_type_map()['NestedInputObject'].graphene_type is NestedInputObject + assert schema.get_type_map()["NestedInputObject"].graphene_type is NestedInputObject def test_includes_interfaces_thunk_subtypes_in_the_type_map(): + class SomeInterface(Interface): f = Int() class SomeSubtype(ObjectType): class Meta: - interfaces = (SomeInterface, ) + interfaces = (SomeInterface,) class Query(ObjectType): iface = Field(lambda: SomeInterface) - schema = Schema( - query=Query, - types=[SomeSubtype] - ) + schema = Schema(query=Query, types=[SomeSubtype]) - assert schema.get_type_map()['SomeSubtype'].graphene_type is SomeSubtype + assert schema.get_type_map()["SomeSubtype"].graphene_type is SomeSubtype def test_includes_types_in_union(): + class SomeType(ObjectType): a = String() @@ -172,15 +168,14 @@ def test_includes_types_in_union(): class Query(ObjectType): union = Field(MyUnion) - schema = Schema( - query=Query, - ) + schema = Schema(query=Query) - assert schema.get_type_map()['OtherType'].graphene_type is OtherType - assert schema.get_type_map()['SomeType'].graphene_type is SomeType + assert schema.get_type_map()["OtherType"].graphene_type is OtherType + assert schema.get_type_map()["SomeType"].graphene_type is SomeType def test_maps_enum(): + class SomeType(ObjectType): a = String() @@ -195,46 +190,42 @@ def test_maps_enum(): class Query(ObjectType): union = Field(MyUnion) - schema = Schema( - query=Query, - ) + schema = Schema(query=Query) - assert schema.get_type_map()['OtherType'].graphene_type is OtherType - assert schema.get_type_map()['SomeType'].graphene_type is SomeType + assert schema.get_type_map()["OtherType"].graphene_type is OtherType + assert schema.get_type_map()["SomeType"].graphene_type is SomeType def test_includes_interfaces_subtypes_in_the_type_map(): + class SomeInterface(Interface): f = Int() class SomeSubtype(ObjectType): class Meta: - interfaces = (SomeInterface, ) + interfaces = (SomeInterface,) class Query(ObjectType): iface = Field(SomeInterface) - schema = Schema( - query=Query, - types=[SomeSubtype] - ) + schema = Schema(query=Query, types=[SomeSubtype]) - assert schema.get_type_map()['SomeSubtype'].graphene_type is SomeSubtype + assert schema.get_type_map()["SomeSubtype"].graphene_type is SomeSubtype def test_stringifies_simple_types(): - assert str(Int) == 'Int' - assert str(Article) == 'Article' - assert str(MyInterface) == 'MyInterface' - assert str(MyUnion) == 'MyUnion' - assert str(MyEnum) == 'MyEnum' - assert str(MyInputObjectType) == 'MyInputObjectType' - assert str(NonNull(Int)) == 'Int!' - assert str(List(Int)) == '[Int]' - assert str(NonNull(List(Int))) == '[Int]!' - assert str(List(NonNull(Int))) == '[Int!]' - assert str(List(List(Int))) == '[[Int]]' + assert str(Int) == "Int" + assert str(Article) == "Article" + assert str(MyInterface) == "MyInterface" + assert str(MyUnion) == "MyUnion" + assert str(MyEnum) == "MyEnum" + assert str(MyInputObjectType) == "MyInputObjectType" + assert str(NonNull(Int)) == "Int!" + assert str(List(Int)) == "[Int]" + assert str(NonNull(List(Int))) == "[Int]!" + assert str(List(NonNull(Int))) == "[Int!]" + assert str(List(List(Int))) == "[[Int]]" # def test_identifies_input_types(): @@ -302,6 +293,7 @@ def test_stringifies_simple_types(): def test_does_not_mutate_passed_field_definitions(): + class CommonFields(object): field1 = String() field2 = String(id=String()) diff --git a/graphene/types/tests/test_dynamic.py b/graphene/types/tests/test_dynamic.py index 5e4dfca8..f2c4c627 100644 --- a/graphene/types/tests/test_dynamic.py +++ b/graphene/types/tests/test_dynamic.py @@ -8,30 +8,32 @@ from ..structures import List, NonNull def test_dynamic(): dynamic = Dynamic(lambda: String) assert dynamic.get_type() == String - assert str(dynamic.get_type()) == 'String' + assert str(dynamic.get_type()) == "String" def test_nonnull(): dynamic = Dynamic(lambda: NonNull(String)) assert dynamic.get_type().of_type == String - assert str(dynamic.get_type()) == 'String!' + assert str(dynamic.get_type()) == "String!" def test_list(): dynamic = Dynamic(lambda: List(String)) assert dynamic.get_type().of_type == String - assert str(dynamic.get_type()) == '[String]' + assert str(dynamic.get_type()) == "[String]" def test_list_non_null(): dynamic = Dynamic(lambda: List(NonNull(String))) assert dynamic.get_type().of_type.of_type == String - assert str(dynamic.get_type()) == '[String!]' + assert str(dynamic.get_type()) == "[String!]" def test_partial(): + def __type(_type): return _type + dynamic = Dynamic(partial(__type, String)) assert dynamic.get_type() == String - assert str(dynamic.get_type()) == 'String' + assert str(dynamic.get_type()) == "String" diff --git a/graphene/types/tests/test_enum.py b/graphene/types/tests/test_enum.py index 231abba6..081ccc62 100644 --- a/graphene/types/tests/test_enum.py +++ b/graphene/types/tests/test_enum.py @@ -8,8 +8,9 @@ from ..schema import ObjectType, Schema def test_enum_construction(): + class RGB(Enum): - '''Description''' + """Description""" RED = 1 GREEN = 2 BLUE = 3 @@ -18,49 +19,43 @@ def test_enum_construction(): def description(self): return "Description {}".format(self.name) - assert RGB._meta.name == 'RGB' - assert RGB._meta.description == 'Description' + assert RGB._meta.name == "RGB" + assert RGB._meta.description == "Description" values = RGB._meta.enum.__members__.values() - assert sorted([v.name for v in values]) == [ - 'BLUE', - 'GREEN', - 'RED' - ] + assert sorted([v.name for v in values]) == ["BLUE", "GREEN", "RED"] assert sorted([v.description for v in values]) == [ - 'Description BLUE', - 'Description GREEN', - 'Description RED' + "Description BLUE", + "Description GREEN", + "Description RED", ] def test_enum_construction_meta(): + class RGB(Enum): class Meta: - name = 'RGBEnum' - description = 'Description' + name = "RGBEnum" + description = "Description" + RED = 1 GREEN = 2 BLUE = 3 - assert RGB._meta.name == 'RGBEnum' - assert RGB._meta.description == 'Description' + assert RGB._meta.name == "RGBEnum" + assert RGB._meta.description == "Description" def test_enum_instance_construction(): - RGB = Enum('RGB', 'RED,GREEN,BLUE') + RGB = Enum("RGB", "RED,GREEN,BLUE") values = RGB._meta.enum.__members__.values() - assert sorted([v.name for v in values]) == [ - 'BLUE', - 'GREEN', - 'RED' - ] + assert sorted([v.name for v in values]) == ["BLUE", "GREEN", "RED"] def test_enum_from_builtin_enum(): - PyRGB = PyEnum('RGB', 'RED,GREEN,BLUE') + PyRGB = PyEnum("RGB", "RED,GREEN,BLUE") RGB = Enum.from_enum(PyRGB) assert RGB._meta.enum == PyRGB @@ -70,34 +65,56 @@ def test_enum_from_builtin_enum(): def test_enum_from_builtin_enum_accepts_lambda_description(): + def custom_description(value): if not value: return "StarWars Episodes" - return 'New Hope Episode' if value == Episode.NEWHOPE else 'Other' + return "New Hope Episode" if value == Episode.NEWHOPE else "Other" def custom_deprecation_reason(value): - return 'meh' if value == Episode.NEWHOPE else None + return "meh" if value == Episode.NEWHOPE else None - PyEpisode = PyEnum('PyEpisode', 'NEWHOPE,EMPIRE,JEDI') - Episode = Enum.from_enum(PyEpisode, description=custom_description, - deprecation_reason=custom_deprecation_reason) + PyEpisode = PyEnum("PyEpisode", "NEWHOPE,EMPIRE,JEDI") + Episode = Enum.from_enum( + PyEpisode, + description=custom_description, + deprecation_reason=custom_deprecation_reason, + ) class Query(ObjectType): foo = Episode() schema = Schema(query=Query) - GraphQLPyEpisode = schema._type_map['PyEpisode'].values + GraphQLPyEpisode = schema._type_map["PyEpisode"].values - assert schema._type_map['PyEpisode'].description == "StarWars Episodes" - assert GraphQLPyEpisode[0].name == 'NEWHOPE' and GraphQLPyEpisode[0].description == 'New Hope Episode' - assert GraphQLPyEpisode[1].name == 'EMPIRE' and GraphQLPyEpisode[1].description == 'Other' - assert GraphQLPyEpisode[2].name == 'JEDI' and GraphQLPyEpisode[2].description == 'Other' + assert schema._type_map["PyEpisode"].description == "StarWars Episodes" + assert ( + GraphQLPyEpisode[0].name == "NEWHOPE" + and GraphQLPyEpisode[0].description == "New Hope Episode" + ) + assert ( + GraphQLPyEpisode[1].name == "EMPIRE" + and GraphQLPyEpisode[1].description == "Other" + ) + assert ( + GraphQLPyEpisode[2].name == "JEDI" + and GraphQLPyEpisode[2].description == "Other" + ) - assert GraphQLPyEpisode[0].name == 'NEWHOPE' and GraphQLPyEpisode[0].deprecation_reason == 'meh' - assert GraphQLPyEpisode[1].name == 'EMPIRE' and GraphQLPyEpisode[1].deprecation_reason is None - assert GraphQLPyEpisode[2].name == 'JEDI' and GraphQLPyEpisode[2].deprecation_reason is None + assert ( + GraphQLPyEpisode[0].name == "NEWHOPE" + and GraphQLPyEpisode[0].deprecation_reason == "meh" + ) + assert ( + GraphQLPyEpisode[1].name == "EMPIRE" + and GraphQLPyEpisode[1].deprecation_reason is None + ) + assert ( + GraphQLPyEpisode[2].name == "JEDI" + and GraphQLPyEpisode[2].deprecation_reason is None + ) def test_enum_from_python3_enum_uses_enum_doc(): @@ -122,6 +139,7 @@ def test_enum_from_python3_enum_uses_enum_doc(): def test_enum_value_from_class(): + class RGB(Enum): RED = 1 GREEN = 2 @@ -133,6 +151,7 @@ def test_enum_value_from_class(): def test_enum_value_as_unmounted_field(): + class RGB(Enum): RED = 1 GREEN = 2 @@ -145,6 +164,7 @@ def test_enum_value_as_unmounted_field(): def test_enum_value_as_unmounted_inputfield(): + class RGB(Enum): RED = 1 GREEN = 2 @@ -157,6 +177,7 @@ def test_enum_value_as_unmounted_inputfield(): def test_enum_value_as_unmounted_argument(): + class RGB(Enum): RED = 1 GREEN = 2 @@ -169,6 +190,7 @@ def test_enum_value_as_unmounted_argument(): def test_enum_can_be_compared(): + class RGB(Enum): RED = 1 GREEN = 2 @@ -180,6 +202,7 @@ def test_enum_can_be_compared(): def test_enum_can_be_initialzied(): + class RGB(Enum): RED = 1 GREEN = 2 @@ -191,17 +214,19 @@ def test_enum_can_be_initialzied(): def test_enum_can_retrieve_members(): + class RGB(Enum): RED = 1 GREEN = 2 BLUE = 3 - assert RGB['RED'] == RGB.RED - assert RGB['GREEN'] == RGB.GREEN - assert RGB['BLUE'] == RGB.BLUE + assert RGB["RED"] == RGB.RED + assert RGB["GREEN"] == RGB.GREEN + assert RGB["BLUE"] == RGB.BLUE def test_enum_to_enum_comparison_should_differ(): + class RGB1(Enum): RED = 1 GREEN = 2 @@ -218,16 +243,18 @@ def test_enum_to_enum_comparison_should_differ(): def test_enum_skip_meta_from_members(): + class RGB1(Enum): + class Meta: - name = 'RGB' + name = "RGB" RED = 1 GREEN = 2 BLUE = 3 assert dict(RGB1._meta.enum.__members__) == { - 'RED': RGB1.RED, - 'GREEN': RGB1.GREEN, - 'BLUE': RGB1.BLUE, + "RED": RGB1.RED, + "GREEN": RGB1.GREEN, + "BLUE": RGB1.BLUE, } diff --git a/graphene/types/tests/test_field.py b/graphene/types/tests/test_field.py index d2bb8c36..13c755fc 100644 --- a/graphene/types/tests/test_field.py +++ b/graphene/types/tests/test_field.py @@ -10,31 +10,33 @@ from .utils import MyLazyType class MyInstance(object): - value = 'value' - value_func = staticmethod(lambda: 'value_func') + value = "value" + value_func = staticmethod(lambda: "value_func") def value_method(self): - return 'value_method' + return "value_method" def test_field_basic(): MyType = object() - args = {'my arg': Argument(True)} + args = {"my arg": Argument(True)} - def resolver(): return None - deprecation_reason = 'Deprecated now' - description = 'My Field' - my_default = 'something' + def resolver(): + return None + + deprecation_reason = "Deprecated now" + description = "My Field" + my_default = "something" field = Field( MyType, - name='name', + name="name", args=args, resolver=resolver, description=description, deprecation_reason=deprecation_reason, default_value=my_default, ) - assert field.name == 'name' + assert field.name == "name" assert field.args == args assert field.resolver == resolver assert field.deprecation_reason == deprecation_reason @@ -55,12 +57,12 @@ def test_field_default_value_not_callable(): Field(MyType, default_value=lambda: True) except AssertionError as e: # substring comparison for py 2/3 compatibility - assert 'The default value can not be a function but received' in str(e) + assert "The default value can not be a function but received" in str(e) def test_field_source(): MyType = object() - field = Field(MyType, source='value') + field = Field(MyType, source="value") assert field.resolver(MyInstance(), None) == MyInstance.value @@ -84,46 +86,48 @@ def test_field_with_string_type(): def test_field_not_source_and_resolver(): MyType = object() with pytest.raises(Exception) as exc_info: - Field(MyType, source='value', resolver=lambda: None) - assert str( - exc_info.value) == 'A Field cannot have a source and a resolver in at the same time.' + Field(MyType, source="value", resolver=lambda: None) + assert ( + str(exc_info.value) + == "A Field cannot have a source and a resolver in at the same time." + ) def test_field_source_func(): MyType = object() - field = Field(MyType, source='value_func') + field = Field(MyType, source="value_func") assert field.resolver(MyInstance(), None) == MyInstance.value_func() def test_field_source_method(): MyType = object() - field = Field(MyType, source='value_method') + field = Field(MyType, source="value_method") assert field.resolver(MyInstance(), None) == MyInstance().value_method() def test_field_source_as_argument(): MyType = object() field = Field(MyType, source=String()) - assert 'source' in field.args - assert field.args['source'].type == String + assert "source" in field.args + assert field.args["source"].type == String def test_field_name_as_argument(): MyType = object() field = Field(MyType, name=String()) - assert 'name' in field.args - assert field.args['name'].type == String + assert "name" in field.args + assert field.args["name"].type == String def test_field_source_argument_as_kw(): MyType = object() field = Field(MyType, b=NonNull(True), c=Argument(None), a=NonNull(False)) - assert list(field.args.keys()) == ['b', 'c', 'a'] - assert isinstance(field.args['b'], Argument) - assert isinstance(field.args['b'].type, NonNull) - assert field.args['b'].type.of_type is True - assert isinstance(field.args['c'], Argument) - assert field.args['c'].type is None - assert isinstance(field.args['a'], Argument) - assert isinstance(field.args['a'].type, NonNull) - assert field.args['a'].type.of_type is False + assert list(field.args.keys()) == ["b", "c", "a"] + assert isinstance(field.args["b"], Argument) + assert isinstance(field.args["b"].type, NonNull) + assert field.args["b"].type.of_type is True + assert isinstance(field.args["c"], Argument) + assert field.args["c"].type is None + assert isinstance(field.args["a"], Argument) + assert isinstance(field.args["a"].type, NonNull) + assert field.args["a"].type.of_type is False diff --git a/graphene/types/tests/test_generic.py b/graphene/types/tests/test_generic.py index be832763..83e9bc88 100644 --- a/graphene/types/tests/test_generic.py +++ b/graphene/types/tests/test_generic.py @@ -18,44 +18,36 @@ def test_generic_query_variable(): 1, 1.1, True, - 'str', + "str", [1, 2, 3], [1.1, 2.2, 3.3], [True, False], - ['str1', 'str2'], + ["str1", "str2"], + {"key_a": "a", "key_b": "b"}, { - 'key_a': 'a', - 'key_b': 'b' + "int": 1, + "float": 1.1, + "boolean": True, + "string": "str", + "int_list": [1, 2, 3], + "float_list": [1.1, 2.2, 3.3], + "boolean_list": [True, False], + "string_list": ["str1", "str2"], + "nested_dict": {"key_a": "a", "key_b": "b"}, }, - { - 'int': 1, - 'float': 1.1, - 'boolean': True, - 'string': 'str', - 'int_list': [1, 2, 3], - 'float_list': [1.1, 2.2, 3.3], - 'boolean_list': [True, False], - 'string_list': ['str1', 'str2'], - 'nested_dict': { - 'key_a': 'a', - 'key_b': 'b' - } - }, - None + None, ]: result = schema.execute( - '''query Test($generic: GenericScalar){ generic(input: $generic) }''', - variable_values={'generic': generic_value} + """query Test($generic: GenericScalar){ generic(input: $generic) }""", + variable_values={"generic": generic_value}, ) assert not result.errors - assert result.data == { - 'generic': generic_value - } + assert result.data == {"generic": generic_value} def test_generic_parse_literal_query(): result = schema.execute( - ''' + """ query { generic(input: { int: 1, @@ -73,23 +65,20 @@ def test_generic_parse_literal_query(): empty_key: undefined }) } - ''' + """ ) assert not result.errors assert result.data == { - 'generic': { - 'int': 1, - 'float': 1.1, - 'boolean': True, - 'string': 'str', - 'int_list': [1, 2, 3], - 'float_list': [1.1, 2.2, 3.3], - 'boolean_list': [True, False], - 'string_list': ['str1', 'str2'], - 'nested_dict': { - 'key_a': 'a', - 'key_b': 'b' - }, - 'empty_key': None + "generic": { + "int": 1, + "float": 1.1, + "boolean": True, + "string": "str", + "int_list": [1, 2, 3], + "float_list": [1.1, 2.2, 3.3], + "boolean_list": [True, False], + "string_list": ["str1", "str2"], + "nested_dict": {"key_a": "a", "key_b": "b"}, + "empty_key": None, } } diff --git a/graphene/types/tests/test_inputobjecttype.py b/graphene/types/tests/test_inputobjecttype.py index 8d6ed904..0100cf42 100644 --- a/graphene/types/tests/test_inputobjecttype.py +++ b/graphene/types/tests/test_inputobjecttype.py @@ -20,8 +20,9 @@ class MyScalar(UnmountedType): def test_generate_inputobjecttype(): + class MyInputObjectType(InputObjectType): - '''Documentation''' + """Documentation""" assert MyInputObjectType._meta.name == "MyInputObjectType" assert MyInputObjectType._meta.description == "Documentation" @@ -29,83 +30,94 @@ def test_generate_inputobjecttype(): def test_generate_inputobjecttype_with_meta(): + class MyInputObjectType(InputObjectType): class Meta: - name = 'MyOtherInputObjectType' - description = 'Documentation' + name = "MyOtherInputObjectType" + description = "Documentation" assert MyInputObjectType._meta.name == "MyOtherInputObjectType" assert MyInputObjectType._meta.description == "Documentation" def test_generate_inputobjecttype_with_fields(): + class MyInputObjectType(InputObjectType): field = Field(MyType) - assert 'field' in MyInputObjectType._meta.fields + assert "field" in MyInputObjectType._meta.fields def test_ordered_fields_in_inputobjecttype(): + class MyInputObjectType(InputObjectType): b = InputField(MyType) a = InputField(MyType) field = MyScalar() asa = InputField(MyType) - assert list(MyInputObjectType._meta.fields.keys()) == [ - 'b', 'a', 'field', 'asa'] + assert list(MyInputObjectType._meta.fields.keys()) == ["b", "a", "field", "asa"] def test_generate_inputobjecttype_unmountedtype(): + class MyInputObjectType(InputObjectType): field = MyScalar(MyType) - assert 'field' in MyInputObjectType._meta.fields - assert isinstance(MyInputObjectType._meta.fields['field'], InputField) + assert "field" in MyInputObjectType._meta.fields + assert isinstance(MyInputObjectType._meta.fields["field"], InputField) def test_generate_inputobjecttype_as_argument(): + class MyInputObjectType(InputObjectType): field = MyScalar() class MyObjectType(ObjectType): field = Field(MyType, input=MyInputObjectType()) - assert 'field' in MyObjectType._meta.fields - field = MyObjectType._meta.fields['field'] + assert "field" in MyObjectType._meta.fields + field = MyObjectType._meta.fields["field"] assert isinstance(field, Field) assert field.type == MyType - assert 'input' in field.args - assert isinstance(field.args['input'], Argument) - assert field.args['input'].type == MyInputObjectType + assert "input" in field.args + assert isinstance(field.args["input"], Argument) + assert field.args["input"].type == MyInputObjectType def test_generate_inputobjecttype_inherit_abstracttype(): + class MyAbstractType(object): field1 = MyScalar(MyType) class MyInputObjectType(InputObjectType, MyAbstractType): field2 = MyScalar(MyType) - assert list(MyInputObjectType._meta.fields.keys()) == ['field1', 'field2'] + assert list(MyInputObjectType._meta.fields.keys()) == ["field1", "field2"] assert [type(x) for x in MyInputObjectType._meta.fields.values()] == [ - InputField, InputField] + InputField, + InputField, + ] def test_generate_inputobjecttype_inherit_abstracttype_reversed(): + class MyAbstractType(object): field1 = MyScalar(MyType) class MyInputObjectType(MyAbstractType, InputObjectType): field2 = MyScalar(MyType) - assert list(MyInputObjectType._meta.fields.keys()) == ['field1', 'field2'] + assert list(MyInputObjectType._meta.fields.keys()) == ["field1", "field2"] assert [type(x) for x in MyInputObjectType._meta.fields.values()] == [ - InputField, InputField] + InputField, + InputField, + ] def test_inputobjecttype_of_input(): + class Child(InputObjectType): first_name = String() last_name = String() @@ -121,14 +133,17 @@ def test_inputobjecttype_of_input(): is_child = Boolean(parent=Parent()) def resolve_is_child(self, info, parent): - return isinstance(parent.child, Child) and parent.child.full_name == "Peter Griffin" + return ( + isinstance(parent.child, Child) + and parent.child.full_name == "Peter Griffin" + ) schema = Schema(query=Query) - result = schema.execute('''query basequery { + result = schema.execute( + """query basequery { isChild(parent: {child: {firstName: "Peter", lastName: "Griffin"}}) } - ''') + """ + ) assert not result.errors - assert result.data == { - 'isChild': True - } + assert result.data == {"isChild": True} diff --git a/graphene/types/tests/test_interface.py b/graphene/types/tests/test_interface.py index 444ff4a6..4657b437 100644 --- a/graphene/types/tests/test_interface.py +++ b/graphene/types/tests/test_interface.py @@ -14,8 +14,9 @@ class MyScalar(UnmountedType): def test_generate_interface(): + class MyInterface(Interface): - '''Documentation''' + """Documentation""" assert MyInterface._meta.name == "MyInterface" assert MyInterface._meta.description == "Documentation" @@ -23,70 +24,77 @@ def test_generate_interface(): def test_generate_interface_with_meta(): + class MyInterface(Interface): class Meta: - name = 'MyOtherInterface' - description = 'Documentation' + name = "MyOtherInterface" + description = "Documentation" assert MyInterface._meta.name == "MyOtherInterface" assert MyInterface._meta.description == "Documentation" def test_generate_interface_with_fields(): + class MyInterface(Interface): field = Field(MyType) - assert 'field' in MyInterface._meta.fields + assert "field" in MyInterface._meta.fields def test_ordered_fields_in_interface(): + class MyInterface(Interface): b = Field(MyType) a = Field(MyType) field = MyScalar() asa = Field(MyType) - assert list(MyInterface._meta.fields.keys()) == ['b', 'a', 'field', 'asa'] + assert list(MyInterface._meta.fields.keys()) == ["b", "a", "field", "asa"] def test_generate_interface_unmountedtype(): + class MyInterface(Interface): field = MyScalar() - assert 'field' in MyInterface._meta.fields - assert isinstance(MyInterface._meta.fields['field'], Field) + assert "field" in MyInterface._meta.fields + assert isinstance(MyInterface._meta.fields["field"], Field) def test_generate_interface_inherit_abstracttype(): + class MyAbstractType(object): field1 = MyScalar() class MyInterface(Interface, MyAbstractType): field2 = MyScalar() - assert list(MyInterface._meta.fields.keys()) == ['field1', 'field2'] + assert list(MyInterface._meta.fields.keys()) == ["field1", "field2"] assert [type(x) for x in MyInterface._meta.fields.values()] == [Field, Field] def test_generate_interface_inherit_interface(): + class MyBaseInterface(Interface): field1 = MyScalar() class MyInterface(MyBaseInterface): field2 = MyScalar() - assert MyInterface._meta.name == 'MyInterface' - assert list(MyInterface._meta.fields.keys()) == ['field1', 'field2'] + assert MyInterface._meta.name == "MyInterface" + assert list(MyInterface._meta.fields.keys()) == ["field1", "field2"] assert [type(x) for x in MyInterface._meta.fields.values()] == [Field, Field] def test_generate_interface_inherit_abstracttype_reversed(): + class MyAbstractType(object): field1 = MyScalar() class MyInterface(MyAbstractType, Interface): field2 = MyScalar() - assert list(MyInterface._meta.fields.keys()) == ['field1', 'field2'] + assert list(MyInterface._meta.fields.keys()) == ["field1", "field2"] assert [type(x) for x in MyInterface._meta.fields.values()] == [Field, Field] diff --git a/graphene/types/tests/test_json.py b/graphene/types/tests/test_json.py index c33bd696..c6b93586 100644 --- a/graphene/types/tests/test_json.py +++ b/graphene/types/tests/test_json.py @@ -18,21 +18,17 @@ def test_jsonstring_query(): json_value = '{"key": "value"}' json_value_quoted = json_value.replace('"', '\\"') - result = schema.execute('''{ json(input: "%s") }''' % json_value_quoted) + result = schema.execute("""{ json(input: "%s") }""" % json_value_quoted) assert not result.errors - assert result.data == { - 'json': json_value - } + assert result.data == {"json": json_value} def test_jsonstring_query_variable(): json_value = '{"key": "value"}' result = schema.execute( - '''query Test($json: JSONString){ json(input: $json) }''', - variable_values={'json': json_value} + """query Test($json: JSONString){ json(input: $json) }""", + variable_values={"json": json_value}, ) assert not result.errors - assert result.data == { - 'json': json_value - } + assert result.data == {"json": json_value} diff --git a/graphene/types/tests/test_mountedtype.py b/graphene/types/tests/test_mountedtype.py index 9dcc11c7..c510aee4 100644 --- a/graphene/types/tests/test_mountedtype.py +++ b/graphene/types/tests/test_mountedtype.py @@ -6,7 +6,7 @@ from ..scalars import String class CustomField(Field): def __init__(self, *args, **kwargs): - self.metadata = kwargs.pop('metadata', None) + self.metadata = kwargs.pop("metadata", None) super(CustomField, self).__init__(*args, **kwargs) @@ -18,8 +18,8 @@ def test_mounted_type(): def test_mounted_type_custom(): - unmounted = String(metadata={'hey': 'yo!'}) + unmounted = String(metadata={"hey": "yo!"}) mounted = CustomField.mounted(unmounted) assert isinstance(mounted, CustomField) assert mounted.type == String - assert mounted.metadata == {'hey': 'yo!'} + assert mounted.metadata == {"hey": "yo!"} diff --git a/graphene/types/tests/test_mutation.py b/graphene/types/tests/test_mutation.py index df17477d..6268192a 100644 --- a/graphene/types/tests/test_mutation.py +++ b/graphene/types/tests/test_mutation.py @@ -10,8 +10,9 @@ from ..structures import NonNull def test_generate_mutation_no_args(): + class MyMutation(Mutation): - '''Documentation''' + """Documentation""" def mutate(self, info, **args): return args @@ -19,24 +20,25 @@ def test_generate_mutation_no_args(): assert issubclass(MyMutation, ObjectType) assert MyMutation._meta.name == "MyMutation" assert MyMutation._meta.description == "Documentation" - resolved = MyMutation.Field().resolver(None, None, name='Peter') - assert resolved == {'name': 'Peter'} + resolved = MyMutation.Field().resolver(None, None, name="Peter") + assert resolved == {"name": "Peter"} def test_generate_mutation_with_meta(): + class MyMutation(Mutation): class Meta: - name = 'MyOtherMutation' - description = 'Documentation' + name = "MyOtherMutation" + description = "Documentation" def mutate(self, info, **args): return args assert MyMutation._meta.name == "MyOtherMutation" assert MyMutation._meta.description == "Documentation" - resolved = MyMutation.Field().resolver(None, None, name='Peter') - assert resolved == {'name': 'Peter'} + resolved = MyMutation.Field().resolver(None, None, name="Peter") + assert resolved == {"name": "Peter"} def test_mutation_raises_exception_if_no_mutate(): @@ -45,11 +47,11 @@ def test_mutation_raises_exception_if_no_mutate(): class MyMutation(Mutation): pass - assert "All mutations must define a mutate method in it" == str( - excinfo.value) + assert "All mutations must define a mutate method in it" == str(excinfo.value) def test_mutation_custom_output_type(): + class User(ObjectType): name = String() @@ -65,13 +67,14 @@ def test_mutation_custom_output_type(): field = CreateUser.Field() assert field.type == User - assert field.args == {'name': Argument(String)} - resolved = field.resolver(None, None, name='Peter') + assert field.args == {"name": Argument(String)} + resolved = field.resolver(None, None, name="Peter") assert isinstance(resolved, User) - assert resolved.name == 'Peter' + assert resolved.name == "Peter" def test_mutation_execution(): + class CreateUser(Mutation): class Arguments: @@ -92,23 +95,21 @@ def test_mutation_execution(): create_user = CreateUser.Field() schema = Schema(query=Query, mutation=MyMutation) - result = schema.execute(''' mutation mymutation { + result = schema.execute( + """ mutation mymutation { createUser(name:"Peter", dynamic: "dynamic") { name dynamic } } - ''') + """ + ) assert not result.errors - assert result.data == { - 'createUser': { - 'name': 'Peter', - 'dynamic': 'dynamic', - } - } + assert result.data == {"createUser": {"name": "Peter", "dynamic": "dynamic"}} def test_mutation_no_fields_output(): + class CreateUser(Mutation): name = String() @@ -122,21 +123,20 @@ def test_mutation_no_fields_output(): create_user = CreateUser.Field() schema = Schema(query=Query, mutation=MyMutation) - result = schema.execute(''' mutation mymutation { + result = schema.execute( + """ mutation mymutation { createUser { name } } - ''') + """ + ) assert not result.errors - assert result.data == { - 'createUser': { - 'name': None, - } - } + assert result.data == {"createUser": {"name": None}} def test_mutation_allow_to_have_custom_args(): + class CreateUser(Mutation): class Arguments: @@ -149,12 +149,12 @@ def test_mutation_allow_to_have_custom_args(): class MyMutation(ObjectType): create_user = CreateUser.Field( - description='Create a user', - deprecation_reason='Is deprecated', - required=True + description="Create a user", + deprecation_reason="Is deprecated", + required=True, ) - field = MyMutation._meta.fields['create_user'] - assert field.description == 'Create a user' - assert field.deprecation_reason == 'Is deprecated' + field = MyMutation._meta.fields["create_user"] + assert field.description == "Create a user" + assert field.deprecation_reason == "Is deprecated" assert field.type == NonNull(CreateUser) diff --git a/graphene/types/tests/test_objecttype.py b/graphene/types/tests/test_objecttype.py index 766f62fe..4c6fabd4 100644 --- a/graphene/types/tests/test_objecttype.py +++ b/graphene/types/tests/test_objecttype.py @@ -25,7 +25,8 @@ class MyInterface(Interface): class ContainerWithInterface(ObjectType): class Meta: - interfaces = (MyInterface, ) + interfaces = (MyInterface,) + field1 = Field(MyType) field2 = Field(MyType) @@ -37,31 +38,36 @@ class MyScalar(UnmountedType): def test_generate_objecttype(): + class MyObjectType(ObjectType): - '''Documentation''' + """Documentation""" assert MyObjectType._meta.name == "MyObjectType" assert MyObjectType._meta.description == "Documentation" assert MyObjectType._meta.interfaces == tuple() assert MyObjectType._meta.fields == {} - assert repr( - MyObjectType) == ">" + assert ( + repr(MyObjectType) + == ">" + ) def test_generate_objecttype_with_meta(): + class MyObjectType(ObjectType): class Meta: - name = 'MyOtherObjectType' - description = 'Documentation' - interfaces = (MyType, ) + name = "MyOtherObjectType" + description = "Documentation" + interfaces = (MyType,) assert MyObjectType._meta.name == "MyOtherObjectType" assert MyObjectType._meta.description == "Documentation" - assert MyObjectType._meta.interfaces == (MyType, ) + assert MyObjectType._meta.interfaces == (MyType,) def test_generate_lazy_objecttype(): + class MyObjectType(ObjectType): example = Field(lambda: InnerObjectType, required=True) @@ -69,43 +75,47 @@ def test_generate_lazy_objecttype(): field = Field(MyType) assert MyObjectType._meta.name == "MyObjectType" - example_field = MyObjectType._meta.fields['example'] + example_field = MyObjectType._meta.fields["example"] assert isinstance(example_field.type, NonNull) assert example_field.type.of_type == InnerObjectType def test_generate_objecttype_with_fields(): + class MyObjectType(ObjectType): field = Field(MyType) - assert 'field' in MyObjectType._meta.fields + assert "field" in MyObjectType._meta.fields def test_generate_objecttype_with_private_attributes(): + class MyObjectType(ObjectType): _private_state = None - assert '_private_state' not in MyObjectType._meta.fields - assert hasattr(MyObjectType, '_private_state') + assert "_private_state" not in MyObjectType._meta.fields + assert hasattr(MyObjectType, "_private_state") - m = MyObjectType(_private_state='custom') - assert m._private_state == 'custom' + m = MyObjectType(_private_state="custom") + assert m._private_state == "custom" with pytest.raises(TypeError): - MyObjectType(_other_private_state='Wrong') + MyObjectType(_other_private_state="Wrong") def test_ordered_fields_in_objecttype(): + class MyObjectType(ObjectType): b = Field(MyType) a = Field(MyType) field = MyScalar() asa = Field(MyType) - assert list(MyObjectType._meta.fields.keys()) == ['b', 'a', 'field', 'asa'] + assert list(MyObjectType._meta.fields.keys()) == ["b", "a", "field", "asa"] def test_generate_objecttype_inherit_abstracttype(): + class MyAbstractType(object): field1 = MyScalar() @@ -115,12 +125,12 @@ def test_generate_objecttype_inherit_abstracttype(): assert MyObjectType._meta.description is None assert MyObjectType._meta.interfaces == () assert MyObjectType._meta.name == "MyObjectType" - assert list(MyObjectType._meta.fields.keys()) == ['field1', 'field2'] - assert list(map(type, MyObjectType._meta.fields.values())) == [ - Field, Field] + assert list(MyObjectType._meta.fields.keys()) == ["field1", "field2"] + assert list(map(type, MyObjectType._meta.fields.values())) == [Field, Field] def test_generate_objecttype_inherit_abstracttype_reversed(): + class MyAbstractType(object): field1 = MyScalar() @@ -130,26 +140,29 @@ def test_generate_objecttype_inherit_abstracttype_reversed(): assert MyObjectType._meta.description is None assert MyObjectType._meta.interfaces == () assert MyObjectType._meta.name == "MyObjectType" - assert list(MyObjectType._meta.fields.keys()) == ['field1', 'field2'] - assert list(map(type, MyObjectType._meta.fields.values())) == [ - Field, Field] + assert list(MyObjectType._meta.fields.keys()) == ["field1", "field2"] + assert list(map(type, MyObjectType._meta.fields.values())) == [Field, Field] def test_generate_objecttype_unmountedtype(): + class MyObjectType(ObjectType): field = MyScalar() - assert 'field' in MyObjectType._meta.fields - assert isinstance(MyObjectType._meta.fields['field'], Field) + assert "field" in MyObjectType._meta.fields + assert isinstance(MyObjectType._meta.fields["field"], Field) def test_parent_container_get_fields(): - assert list(Container._meta.fields.keys()) == ['field1', 'field2'] + assert list(Container._meta.fields.keys()) == ["field1", "field2"] def test_parent_container_interface_get_fields(): assert list(ContainerWithInterface._meta.fields.keys()) == [ - 'ifield', 'field1', 'field2'] + "ifield", + "field1", + "field2", + ] def test_objecttype_as_container_only_args(): @@ -187,53 +200,59 @@ def test_objecttype_as_container_invalid_kwargs(): Container(unexisting_field="3") assert "'unexisting_field' is an invalid keyword argument for Container" == str( - excinfo.value) + excinfo.value + ) def test_objecttype_container_benchmark(benchmark): + @benchmark def create_objecttype(): - Container(field1='field1', field2='field2') + Container(field1="field1", field2="field2") def test_generate_objecttype_description(): + class MyObjectType(ObjectType): - ''' + """ Documentation Documentation line 2 - ''' + """ assert MyObjectType._meta.description == "Documentation\n\nDocumentation line 2" def test_objecttype_with_possible_types(): + class MyObjectType(ObjectType): class Meta: - possible_types = (dict, ) + possible_types = (dict,) - assert MyObjectType._meta.possible_types == (dict, ) + assert MyObjectType._meta.possible_types == (dict,) def test_objecttype_with_possible_types_and_is_type_of_should_raise(): with pytest.raises(AssertionError) as excinfo: + class MyObjectType(ObjectType): class Meta: - possible_types = (dict, ) + possible_types = (dict,) @classmethod def is_type_of(cls, root, context, info): return False assert str(excinfo.value) == ( - 'MyObjectType.Meta.possible_types will cause type collision with ' - 'MyObjectType.is_type_of. Please use one or other.' + "MyObjectType.Meta.possible_types will cause type collision with " + "MyObjectType.is_type_of. Please use one or other." ) def test_objecttype_no_fields_output(): + class User(ObjectType): name = String() @@ -244,24 +263,25 @@ def test_objecttype_no_fields_output(): return User() schema = Schema(query=Query) - result = schema.execute(''' query basequery { + result = schema.execute( + """ query basequery { user { name } } - ''') + """ + ) assert not result.errors - assert result.data == { - 'user': { - 'name': None, - } - } + assert result.data == {"user": {"name": None}} def test_abstract_objecttype_can_str(): + class MyObjectType(ObjectType): + class Meta: abstract = True + field = MyScalar() assert str(MyObjectType) == "MyObjectType" diff --git a/graphene/types/tests/test_query.py b/graphene/types/tests/test_query.py index 7bdde001..0535e4e7 100644 --- a/graphene/types/tests/test_query.py +++ b/graphene/types/tests/test_query.py @@ -17,17 +17,19 @@ from ..union import Union def test_query(): + class Query(ObjectType): - hello = String(resolver=lambda *_: 'World') + hello = String(resolver=lambda *_: "World") hello_schema = Schema(Query) - executed = hello_schema.execute('{ hello }') + executed = hello_schema.execute("{ hello }") assert not executed.errors - assert executed.data == {'hello': 'World'} + assert executed.data == {"hello": "World"} def test_query_source(): + class Root(object): _hello = "World" @@ -39,12 +41,13 @@ def test_query_source(): hello_schema = Schema(Query) - executed = hello_schema.execute('{ hello }', Root()) + executed = hello_schema.execute("{ hello }", Root()) assert not executed.errors - assert executed.data == {'hello': 'World'} + assert executed.data == {"hello": "World"} def test_query_union(): + class one_object(object): pass @@ -78,18 +81,13 @@ def test_query_union(): hello_schema = Schema(Query) - executed = hello_schema.execute('{ unions { __typename } }') + executed = hello_schema.execute("{ unions { __typename } }") assert not executed.errors - assert executed.data == { - 'unions': [{ - '__typename': 'One' - }, { - '__typename': 'Two' - }] - } + assert executed.data == {"unions": [{"__typename": "One"}, {"__typename": "Two"}]} def test_query_interface(): + class one_object(object): pass @@ -102,7 +100,7 @@ def test_query_interface(): class One(ObjectType): class Meta: - interfaces = (MyInterface, ) + interfaces = (MyInterface,) one = String() @@ -113,7 +111,7 @@ def test_query_interface(): class Two(ObjectType): class Meta: - interfaces = (MyInterface, ) + interfaces = (MyInterface,) two = String() @@ -129,47 +127,48 @@ def test_query_interface(): hello_schema = Schema(Query, types=[One, Two]) - executed = hello_schema.execute('{ interfaces { __typename } }') + executed = hello_schema.execute("{ interfaces { __typename } }") assert not executed.errors assert executed.data == { - 'interfaces': [{ - '__typename': 'One' - }, { - '__typename': 'Two' - }] + "interfaces": [{"__typename": "One"}, {"__typename": "Two"}] } def test_query_dynamic(): + class Query(ObjectType): - hello = Dynamic(lambda: String(resolver=lambda *_: 'World')) - hellos = Dynamic(lambda: List(String, resolver=lambda *_: ['Worlds'])) - hello_field = Dynamic(lambda: Field( - String, resolver=lambda *_: 'Field World')) + hello = Dynamic(lambda: String(resolver=lambda *_: "World")) + hellos = Dynamic(lambda: List(String, resolver=lambda *_: ["Worlds"])) + hello_field = Dynamic(lambda: Field(String, resolver=lambda *_: "Field World")) hello_schema = Schema(Query) - executed = hello_schema.execute('{ hello hellos helloField }') + executed = hello_schema.execute("{ hello hellos helloField }") assert not executed.errors - assert executed.data == {'hello': 'World', 'hellos': [ - 'Worlds'], 'helloField': 'Field World'} + assert executed.data == { + "hello": "World", + "hellos": ["Worlds"], + "helloField": "Field World", + } def test_query_default_value(): + class MyType(ObjectType): field = String() class Query(ObjectType): - hello = Field(MyType, default_value=MyType(field='something else!')) + hello = Field(MyType, default_value=MyType(field="something else!")) hello_schema = Schema(Query) - executed = hello_schema.execute('{ hello { field } }') + executed = hello_schema.execute("{ hello { field } }") assert not executed.errors - assert executed.data == {'hello': {'field': 'something else!'}} + assert executed.data == {"hello": {"field": "something else!"}} def test_query_wrong_default_value(): + class MyType(ObjectType): field = String() @@ -178,73 +177,81 @@ def test_query_wrong_default_value(): return isinstance(root, MyType) class Query(ObjectType): - hello = Field(MyType, default_value='hello') + hello = Field(MyType, default_value="hello") hello_schema = Schema(Query) - executed = hello_schema.execute('{ hello { field } }') + executed = hello_schema.execute("{ hello { field } }") assert len(executed.errors) == 1 - assert executed.errors[0].message == GraphQLError( - 'Expected value of type "MyType" but got: str.').message - assert executed.data == {'hello': None} + assert ( + executed.errors[0].message + == GraphQLError('Expected value of type "MyType" but got: str.').message + ) + assert executed.data == {"hello": None} def test_query_default_value_ignored_by_resolver(): + class MyType(ObjectType): field = String() class Query(ObjectType): - hello = Field(MyType, default_value='hello', - resolver=lambda *_: MyType(field='no default.')) + hello = Field( + MyType, + default_value="hello", + resolver=lambda *_: MyType(field="no default."), + ) hello_schema = Schema(Query) - executed = hello_schema.execute('{ hello { field } }') + executed = hello_schema.execute("{ hello { field } }") assert not executed.errors - assert executed.data == {'hello': {'field': 'no default.'}} + assert executed.data == {"hello": {"field": "no default."}} def test_query_resolve_function(): + class Query(ObjectType): hello = String() def resolve_hello(self, info): - return 'World' + return "World" hello_schema = Schema(Query) - executed = hello_schema.execute('{ hello }') + executed = hello_schema.execute("{ hello }") assert not executed.errors - assert executed.data == {'hello': 'World'} + assert executed.data == {"hello": "World"} def test_query_arguments(): + class Query(ObjectType): test = String(a_str=String(), a_int=Int()) def resolve_test(self, info, **args): - return json.dumps([self, args], separators=(',', ':')) + return json.dumps([self, args], separators=(",", ":")) test_schema = Schema(Query) - result = test_schema.execute('{ test }', None) + result = test_schema.execute("{ test }", None) assert not result.errors - assert result.data == {'test': '[null,{}]'} + assert result.data == {"test": "[null,{}]"} - result = test_schema.execute('{ test(aStr: "String!") }', 'Source!') + result = test_schema.execute('{ test(aStr: "String!") }', "Source!") assert not result.errors - assert result.data == {'test': '["Source!",{"a_str":"String!"}]'} + assert result.data == {"test": '["Source!",{"a_str":"String!"}]'} - result = test_schema.execute( - '{ test(aInt: -123, aStr: "String!") }', 'Source!') + result = test_schema.execute('{ test(aInt: -123, aStr: "String!") }', "Source!") assert not result.errors assert result.data in [ - {'test': '["Source!",{"a_str":"String!","a_int":-123}]'}, - {'test': '["Source!",{"a_int":-123,"a_str":"String!"}]'} + {"test": '["Source!",{"a_str":"String!","a_int":-123}]'}, + {"test": '["Source!",{"a_int":-123,"a_str":"String!"}]'}, ] def test_query_input_field(): + class Input(InputObjectType): a_field = String() recursive_field = InputField(lambda: Input) @@ -253,37 +260,38 @@ def test_query_input_field(): test = String(a_input=Input()) def resolve_test(self, info, **args): - return json.dumps([self, args], separators=(',', ':')) + return json.dumps([self, args], separators=(",", ":")) test_schema = Schema(Query) - result = test_schema.execute('{ test }', None) + result = test_schema.execute("{ test }", None) assert not result.errors - assert result.data == {'test': '[null,{}]'} + assert result.data == {"test": "[null,{}]"} + + result = test_schema.execute('{ test(aInput: {aField: "String!"} ) }', "Source!") + assert not result.errors + assert result.data == {"test": '["Source!",{"a_input":{"a_field":"String!"}}]'} result = test_schema.execute( - '{ test(aInput: {aField: "String!"} ) }', 'Source!') + '{ test(aInput: {recursiveField: {aField: "String!"}}) }', "Source!" + ) assert not result.errors assert result.data == { - 'test': '["Source!",{"a_input":{"a_field":"String!"}}]'} - - result = test_schema.execute( - '{ test(aInput: {recursiveField: {aField: "String!"}}) }', 'Source!') - assert not result.errors - assert result.data == { - 'test': '["Source!",{"a_input":{"recursive_field":{"a_field":"String!"}}}]'} + "test": '["Source!",{"a_input":{"recursive_field":{"a_field":"String!"}}}]' + } def test_query_middlewares(): + class Query(ObjectType): hello = String() other = String() def resolve_hello(self, info): - return 'World' + return "World" def resolve_other(self, info): - return 'other' + return "other" def reversed_middleware(next, *args, **kwargs): p = next(*args, **kwargs) @@ -292,12 +300,14 @@ def test_query_middlewares(): hello_schema = Schema(Query) executed = hello_schema.execute( - '{ hello, other }', middleware=[reversed_middleware]) + "{ hello, other }", middleware=[reversed_middleware] + ) assert not executed.errors - assert executed.data == {'hello': 'dlroW', 'other': 'rehto'} + assert executed.data == {"hello": "dlroW", "other": "rehto"} def test_objecttype_on_instances(): + class Ship: def __init__(self, name): @@ -314,12 +324,12 @@ def test_objecttype_on_instances(): ship = Field(ShipType) def resolve_ship(self, info): - return Ship(name='xwing') + return Ship(name="xwing") schema = Schema(query=Query) - executed = schema.execute('{ ship { name } }') + executed = schema.execute("{ ship { name } }") assert not executed.errors - assert executed.data == {'ship': {'name': 'xwing'}} + assert executed.data == {"ship": {"name": "xwing"}} def test_big_list_query_benchmark(benchmark): @@ -333,10 +343,10 @@ def test_big_list_query_benchmark(benchmark): hello_schema = Schema(Query) - big_list_query = partial(hello_schema.execute, '{ allInts }') + big_list_query = partial(hello_schema.execute, "{ allInts }") result = benchmark(big_list_query) assert not result.errors - assert result.data == {'allInts': list(big_list)} + assert result.data == {"allInts": list(big_list)} def test_big_list_query_compiled_query_benchmark(benchmark): @@ -349,16 +359,17 @@ def test_big_list_query_compiled_query_benchmark(benchmark): return big_list hello_schema = Schema(Query) - source = Source('{ allInts }') + source = Source("{ allInts }") query_ast = parse(source) big_list_query = partial(execute, hello_schema, query_ast) result = benchmark(big_list_query) assert not result.errors - assert result.data == {'allInts': list(big_list)} + assert result.data == {"allInts": list(big_list)} def test_big_list_of_containers_query_benchmark(benchmark): + class Container(ObjectType): x = Int() @@ -372,14 +383,14 @@ def test_big_list_of_containers_query_benchmark(benchmark): hello_schema = Schema(Query) - big_list_query = partial(hello_schema.execute, '{ allContainers { x } }') + big_list_query = partial(hello_schema.execute, "{ allContainers { x } }") result = benchmark(big_list_query) assert not result.errors - assert result.data == {'allContainers': [ - {'x': c.x} for c in big_container_list]} + assert result.data == {"allContainers": [{"x": c.x} for c in big_container_list]} def test_big_list_of_containers_multiple_fields_query_benchmark(benchmark): + class Container(ObjectType): x = Int() y = Int() @@ -396,15 +407,20 @@ def test_big_list_of_containers_multiple_fields_query_benchmark(benchmark): hello_schema = Schema(Query) - big_list_query = partial(hello_schema.execute, - '{ allContainers { x, y, z, o } }') + big_list_query = partial(hello_schema.execute, "{ allContainers { x, y, z, o } }") result = benchmark(big_list_query) assert not result.errors - assert result.data == {'allContainers': [ - {'x': c.x, 'y': c.y, 'z': c.z, 'o': c.o} for c in big_container_list]} + assert result.data == { + "allContainers": [ + {"x": c.x, "y": c.y, "z": c.z, "o": c.o} for c in big_container_list + ] + } -def test_big_list_of_containers_multiple_fields_custom_resolvers_query_benchmark(benchmark): +def test_big_list_of_containers_multiple_fields_custom_resolvers_query_benchmark( + benchmark +): + class Container(ObjectType): x = Int() y = Int() @@ -433,12 +449,14 @@ def test_big_list_of_containers_multiple_fields_custom_resolvers_query_benchmark hello_schema = Schema(Query) - big_list_query = partial(hello_schema.execute, - '{ allContainers { x, y, z, o } }') + big_list_query = partial(hello_schema.execute, "{ allContainers { x, y, z, o } }") result = benchmark(big_list_query) assert not result.errors - assert result.data == {'allContainers': [ - {'x': c.x, 'y': c.y, 'z': c.z, 'o': c.o} for c in big_container_list]} + assert result.data == { + "allContainers": [ + {"x": c.x, "y": c.y, "z": c.z, "o": c.o} for c in big_container_list + ] + } def test_query_annotated_resolvers(): @@ -464,15 +482,15 @@ def test_query_annotated_resolvers(): result = test_schema.execute('{ annotated(id:"self") }', "base") assert not result.errors - assert result.data == {'annotated': 'base-self'} + assert result.data == {"annotated": "base-self"} - result = test_schema.execute('{ context }', "base", context_value=context) + result = test_schema.execute("{ context }", "base", context_value=context) assert not result.errors - assert result.data == {'context': 'base-context'} + assert result.data == {"context": "base-context"} - result = test_schema.execute('{ info }', "base") + result = test_schema.execute("{ info }", "base") assert not result.errors - assert result.data == {'info': 'base-info'} + assert result.data == {"info": "base-info"} def test_default_as_kwarg_to_NonNull(): @@ -488,7 +506,7 @@ def test_default_as_kwarg_to_NonNull(): return User(name="foo") schema = Schema(query=Query) - expected = {'user': {'name': 'foo', 'isAdmin': False}} + expected = {"user": {"name": "foo", "isAdmin": False}} result = schema.execute("{ user { name isAdmin } }") assert not result.errors diff --git a/graphene/types/tests/test_resolver.py b/graphene/types/tests/test_resolver.py index 2beb607e..3be9a492 100644 --- a/graphene/types/tests/test_resolver.py +++ b/graphene/types/tests/test_resolver.py @@ -1,38 +1,40 @@ -from ..resolver import (attr_resolver, dict_resolver, get_default_resolver, - set_default_resolver) +from ..resolver import ( + attr_resolver, + dict_resolver, + get_default_resolver, + set_default_resolver, +) args = {} context = None info = None -demo_dict = { - 'attr': 'value' -} +demo_dict = {"attr": "value"} class demo_obj(object): - attr = 'value' + attr = "value" def test_attr_resolver(): - resolved = attr_resolver('attr', None, demo_obj, info, **args) - assert resolved == 'value' + resolved = attr_resolver("attr", None, demo_obj, info, **args) + assert resolved == "value" def test_attr_resolver_default_value(): - resolved = attr_resolver('attr2', 'default', demo_obj, info, **args) - assert resolved == 'default' + resolved = attr_resolver("attr2", "default", demo_obj, info, **args) + assert resolved == "default" def test_dict_resolver(): - resolved = dict_resolver('attr', None, demo_dict, info, **args) - assert resolved == 'value' + resolved = dict_resolver("attr", None, demo_dict, info, **args) + assert resolved == "value" def test_dict_resolver_default_value(): - resolved = dict_resolver('attr2', 'default', demo_dict, info, **args) - assert resolved == 'default' + resolved = dict_resolver("attr2", "default", demo_dict, info, **args) + assert resolved == "default" def test_get_default_resolver_is_attr_resolver(): diff --git a/graphene/types/tests/test_scalar.py b/graphene/types/tests/test_scalar.py index 3c6383fa..fb20980d 100644 --- a/graphene/types/tests/test_scalar.py +++ b/graphene/types/tests/test_scalar.py @@ -3,8 +3,9 @@ from ..scalars import Scalar def test_scalar(): + class JSONScalar(Scalar): - '''Documentation''' + """Documentation""" assert JSONScalar._meta.name == "JSONScalar" assert JSONScalar._meta.description == "Documentation" diff --git a/graphene/types/tests/test_scalars_serialization.py b/graphene/types/tests/test_scalars_serialization.py index eab09e64..a95e8bd4 100644 --- a/graphene/types/tests/test_scalars_serialization.py +++ b/graphene/types/tests/test_scalars_serialization.py @@ -13,8 +13,8 @@ def test_serializes_output_int(): assert Int.serialize(-9876504321) is None assert Int.serialize(1e100) is None assert Int.serialize(-1e100) is None - assert Int.serialize('-1.1') == -1 - assert Int.serialize('one') is None + assert Int.serialize("-1.1") == -1 + assert Int.serialize("one") is None assert Int.serialize(False) == 0 assert Int.serialize(True) == 1 @@ -26,24 +26,24 @@ def test_serializes_output_float(): assert Float.serialize(0.1) == 0.1 assert Float.serialize(1.1) == 1.1 assert Float.serialize(-1.1) == -1.1 - assert Float.serialize('-1.1') == -1.1 - assert Float.serialize('one') is None + assert Float.serialize("-1.1") == -1.1 + assert Float.serialize("one") is None assert Float.serialize(False) == 0 assert Float.serialize(True) == 1 def test_serializes_output_string(): - assert String.serialize('string') == 'string' - assert String.serialize(1) == '1' - assert String.serialize(-1.1) == '-1.1' - assert String.serialize(True) == 'true' - assert String.serialize(False) == 'false' - assert String.serialize(u'\U0001F601') == u'\U0001F601' + assert String.serialize("string") == "string" + assert String.serialize(1) == "1" + assert String.serialize(-1.1) == "-1.1" + assert String.serialize(True) == "true" + assert String.serialize(False) == "false" + assert String.serialize(u"\U0001F601") == u"\U0001F601" def test_serializes_output_boolean(): - assert Boolean.serialize('string') is True - assert Boolean.serialize('') is False + assert Boolean.serialize("string") is True + assert Boolean.serialize("") is False assert Boolean.serialize(1) is True assert Boolean.serialize(0) is False assert Boolean.serialize(True) is True diff --git a/graphene/types/tests/test_schema.py b/graphene/types/tests/test_schema.py index 2ed5c099..d4f2e33e 100644 --- a/graphene/types/tests/test_schema.py +++ b/graphene/types/tests/test_schema.py @@ -35,7 +35,9 @@ def test_schema_get_type_error(): def test_schema_str(): schema = Schema(Query) - assert str(schema) == """schema { + assert ( + str(schema) + == """schema { query: Query } @@ -47,8 +49,9 @@ type Query { inner: MyOtherType } """ + ) def test_schema_introspect(): schema = Schema(Query) - assert '__schema' in schema.introspect() + assert "__schema" in schema.introspect() diff --git a/graphene/types/tests/test_structures.py b/graphene/types/tests/test_structures.py index 6fb290fd..5359278f 100644 --- a/graphene/types/tests/test_structures.py +++ b/graphene/types/tests/test_structures.py @@ -10,14 +10,17 @@ from .utils import MyLazyType def test_list(): _list = List(String) assert _list.of_type == String - assert str(_list) == '[String]' + assert str(_list) == "[String]" def test_list_with_unmounted_type(): with pytest.raises(Exception) as exc_info: List(String()) - assert str(exc_info.value) == 'List could not have a mounted String() as inner type. Try with List(String).' + assert ( + str(exc_info.value) + == "List could not have a mounted String() as inner type. Try with List(String)." + ) def test_list_with_lazy_type(): @@ -52,7 +55,7 @@ def test_list_inherited_works_nonnull(): def test_nonnull(): nonnull = NonNull(String) assert nonnull.of_type == String - assert str(nonnull) == 'String!' + assert str(nonnull) == "String!" def test_nonnull_with_lazy_type(): @@ -82,14 +85,20 @@ def test_nonnull_inherited_dont_work_nonnull(): with pytest.raises(Exception) as exc_info: NonNull(NonNull(String)) - assert str(exc_info.value) == 'Can only create NonNull of a Nullable GraphQLType but got: String!.' + assert ( + str(exc_info.value) + == "Can only create NonNull of a Nullable GraphQLType but got: String!." + ) def test_nonnull_with_unmounted_type(): with pytest.raises(Exception) as exc_info: NonNull(String()) - assert str(exc_info.value) == 'NonNull could not have a mounted String() as inner type. Try with NonNull(String).' + assert ( + str(exc_info.value) + == "NonNull could not have a mounted String() as inner type. Try with NonNull(String)." + ) def test_list_comparasion(): diff --git a/graphene/types/tests/test_typemap.py b/graphene/types/tests/test_typemap.py index 7d441bfb..0f60986b 100644 --- a/graphene/types/tests/test_typemap.py +++ b/graphene/types/tests/test_typemap.py @@ -1,8 +1,15 @@ import pytest -from graphql.type import (GraphQLArgument, GraphQLEnumType, GraphQLEnumValue, - GraphQLField, GraphQLInputObjectField, - GraphQLInputObjectType, GraphQLInterfaceType, - GraphQLObjectType, GraphQLString) +from graphql.type import ( + GraphQLArgument, + GraphQLEnumType, + GraphQLEnumValue, + GraphQLField, + GraphQLInputObjectField, + GraphQLInputObjectType, + GraphQLInterfaceType, + GraphQLObjectType, + GraphQLString, +) from ..dynamic import Dynamic from ..enum import Enum @@ -17,112 +24,134 @@ from ..typemap import TypeMap, resolve_type def test_enum(): + class MyEnum(Enum): - '''Description''' + """Description""" foo = 1 bar = 2 @property def description(self): - return 'Description {}={}'.format(self.name, self.value) + return "Description {}={}".format(self.name, self.value) @property def deprecation_reason(self): if self == MyEnum.foo: - return 'Is deprecated' + return "Is deprecated" typemap = TypeMap([MyEnum]) - assert 'MyEnum' in typemap - graphql_enum = typemap['MyEnum'] + assert "MyEnum" in typemap + graphql_enum = typemap["MyEnum"] assert isinstance(graphql_enum, GraphQLEnumType) - assert graphql_enum.name == 'MyEnum' - assert graphql_enum.description == 'Description' + assert graphql_enum.name == "MyEnum" + assert graphql_enum.description == "Description" values = graphql_enum.values assert values == [ - GraphQLEnumValue(name='foo', value=1, description='Description foo=1', - deprecation_reason='Is deprecated'), - GraphQLEnumValue(name='bar', value=2, description='Description bar=2'), + GraphQLEnumValue( + name="foo", + value=1, + description="Description foo=1", + deprecation_reason="Is deprecated", + ), + GraphQLEnumValue(name="bar", value=2, description="Description bar=2"), ] def test_objecttype(): + class MyObjectType(ObjectType): - '''Description''' - foo = String(bar=String(description='Argument description', - default_value='x'), description='Field description') - bar = String(name='gizmo') + """Description""" + foo = String( + bar=String(description="Argument description", default_value="x"), + description="Field description", + ) + bar = String(name="gizmo") def resolve_foo(self, bar): return bar typemap = TypeMap([MyObjectType]) - assert 'MyObjectType' in typemap - graphql_type = typemap['MyObjectType'] + assert "MyObjectType" in typemap + graphql_type = typemap["MyObjectType"] assert isinstance(graphql_type, GraphQLObjectType) - assert graphql_type.name == 'MyObjectType' - assert graphql_type.description == 'Description' + assert graphql_type.name == "MyObjectType" + assert graphql_type.description == "Description" fields = graphql_type.fields - assert list(fields.keys()) == ['foo', 'gizmo'] - foo_field = fields['foo'] + assert list(fields.keys()) == ["foo", "gizmo"] + foo_field = fields["foo"] assert isinstance(foo_field, GraphQLField) - assert foo_field.description == 'Field description' + assert foo_field.description == "Field description" assert foo_field.args == { - 'bar': GraphQLArgument(GraphQLString, description='Argument description', default_value='x', out_name='bar') + "bar": GraphQLArgument( + GraphQLString, + description="Argument description", + default_value="x", + out_name="bar", + ) } def test_dynamic_objecttype(): + class MyObjectType(ObjectType): - '''Description''' + """Description""" bar = Dynamic(lambda: Field(String)) own = Field(lambda: MyObjectType) typemap = TypeMap([MyObjectType]) - assert 'MyObjectType' in typemap - assert list(MyObjectType._meta.fields.keys()) == ['bar', 'own'] - graphql_type = typemap['MyObjectType'] + assert "MyObjectType" in typemap + assert list(MyObjectType._meta.fields.keys()) == ["bar", "own"] + graphql_type = typemap["MyObjectType"] fields = graphql_type.fields - assert list(fields.keys()) == ['bar', 'own'] - assert fields['bar'].type == GraphQLString - assert fields['own'].type == graphql_type + assert list(fields.keys()) == ["bar", "own"] + assert fields["bar"].type == GraphQLString + assert fields["own"].type == graphql_type def test_interface(): + class MyInterface(Interface): - '''Description''' - foo = String(bar=String(description='Argument description', - default_value='x'), description='Field description') - bar = String(name='gizmo', first_arg=String(), - other_arg=String(name='oth_arg')) + """Description""" + foo = String( + bar=String(description="Argument description", default_value="x"), + description="Field description", + ) + bar = String(name="gizmo", first_arg=String(), other_arg=String(name="oth_arg")) own = Field(lambda: MyInterface) def resolve_foo(self, args, info): - return args.get('bar') + return args.get("bar") typemap = TypeMap([MyInterface]) - assert 'MyInterface' in typemap - graphql_type = typemap['MyInterface'] + assert "MyInterface" in typemap + graphql_type = typemap["MyInterface"] assert isinstance(graphql_type, GraphQLInterfaceType) - assert graphql_type.name == 'MyInterface' - assert graphql_type.description == 'Description' + assert graphql_type.name == "MyInterface" + assert graphql_type.description == "Description" fields = graphql_type.fields - assert list(fields.keys()) == ['foo', 'gizmo', 'own'] - assert fields['own'].type == graphql_type - assert list(fields['gizmo'].args.keys()) == ['firstArg', 'oth_arg'] - foo_field = fields['foo'] + assert list(fields.keys()) == ["foo", "gizmo", "own"] + assert fields["own"].type == graphql_type + assert list(fields["gizmo"].args.keys()) == ["firstArg", "oth_arg"] + foo_field = fields["foo"] assert isinstance(foo_field, GraphQLField) - assert foo_field.description == 'Field description' + assert foo_field.description == "Field description" assert not foo_field.resolver # Resolver not attached in interfaces assert foo_field.args == { - 'bar': GraphQLArgument(GraphQLString, description='Argument description', default_value='x', out_name='bar') + "bar": GraphQLArgument( + GraphQLString, + description="Argument description", + default_value="x", + out_name="bar", + ) } def test_inputobject(): + class OtherObjectType(InputObjectType): thingy = NonNull(Int) @@ -131,109 +160,118 @@ def test_inputobject(): some_other_field = List(OtherObjectType) class MyInputObjectType(InputObjectType): - '''Description''' - foo_bar = String(description='Field description') - bar = String(name='gizmo') + """Description""" + foo_bar = String(description="Field description") + bar = String(name="gizmo") baz = NonNull(MyInnerObjectType) own = InputField(lambda: MyInputObjectType) def resolve_foo_bar(self, args, info): - return args.get('bar') + return args.get("bar") typemap = TypeMap([MyInputObjectType]) - assert 'MyInputObjectType' in typemap - graphql_type = typemap['MyInputObjectType'] + assert "MyInputObjectType" in typemap + graphql_type = typemap["MyInputObjectType"] assert isinstance(graphql_type, GraphQLInputObjectType) - assert graphql_type.name == 'MyInputObjectType' - assert graphql_type.description == 'Description' + assert graphql_type.name == "MyInputObjectType" + assert graphql_type.description == "Description" - other_graphql_type = typemap['OtherObjectType'] - inner_graphql_type = typemap['MyInnerObjectType'] - container = graphql_type.create_container({ - 'bar': 'oh!', - 'baz': inner_graphql_type.create_container({ - 'some_other_field': [ - other_graphql_type.create_container({'thingy': 1}), - other_graphql_type.create_container({'thingy': 2}) - ] - }) - }) + other_graphql_type = typemap["OtherObjectType"] + inner_graphql_type = typemap["MyInnerObjectType"] + container = graphql_type.create_container( + { + "bar": "oh!", + "baz": inner_graphql_type.create_container( + { + "some_other_field": [ + other_graphql_type.create_container({"thingy": 1}), + other_graphql_type.create_container({"thingy": 2}), + ] + } + ), + } + ) assert isinstance(container, MyInputObjectType) - assert 'bar' in container - assert container.bar == 'oh!' - assert 'foo_bar' not in container + assert "bar" in container + assert container.bar == "oh!" + assert "foo_bar" not in container assert container.foo_bar is None assert container.baz.some_field is None assert container.baz.some_other_field[0].thingy == 1 assert container.baz.some_other_field[1].thingy == 2 fields = graphql_type.fields - assert list(fields.keys()) == ['fooBar', 'gizmo', 'baz', 'own'] - own_field = fields['own'] + assert list(fields.keys()) == ["fooBar", "gizmo", "baz", "own"] + own_field = fields["own"] assert own_field.type == graphql_type - foo_field = fields['fooBar'] + foo_field = fields["fooBar"] assert isinstance(foo_field, GraphQLInputObjectField) - assert foo_field.description == 'Field description' + assert foo_field.description == "Field description" def test_objecttype_camelcase(): + class MyObjectType(ObjectType): - '''Description''' + """Description""" foo_bar = String(bar_foo=String()) typemap = TypeMap([MyObjectType]) - assert 'MyObjectType' in typemap - graphql_type = typemap['MyObjectType'] + assert "MyObjectType" in typemap + graphql_type = typemap["MyObjectType"] assert isinstance(graphql_type, GraphQLObjectType) - assert graphql_type.name == 'MyObjectType' - assert graphql_type.description == 'Description' + assert graphql_type.name == "MyObjectType" + assert graphql_type.description == "Description" fields = graphql_type.fields - assert list(fields.keys()) == ['fooBar'] - foo_field = fields['fooBar'] + assert list(fields.keys()) == ["fooBar"] + foo_field = fields["fooBar"] assert isinstance(foo_field, GraphQLField) assert foo_field.args == { - 'barFoo': GraphQLArgument(GraphQLString, out_name='bar_foo') + "barFoo": GraphQLArgument(GraphQLString, out_name="bar_foo") } def test_objecttype_camelcase_disabled(): + class MyObjectType(ObjectType): - '''Description''' + """Description""" foo_bar = String(bar_foo=String()) typemap = TypeMap([MyObjectType], auto_camelcase=False) - assert 'MyObjectType' in typemap - graphql_type = typemap['MyObjectType'] + assert "MyObjectType" in typemap + graphql_type = typemap["MyObjectType"] assert isinstance(graphql_type, GraphQLObjectType) - assert graphql_type.name == 'MyObjectType' - assert graphql_type.description == 'Description' + assert graphql_type.name == "MyObjectType" + assert graphql_type.description == "Description" fields = graphql_type.fields - assert list(fields.keys()) == ['foo_bar'] - foo_field = fields['foo_bar'] + assert list(fields.keys()) == ["foo_bar"] + foo_field = fields["foo_bar"] assert isinstance(foo_field, GraphQLField) assert foo_field.args == { - 'bar_foo': GraphQLArgument(GraphQLString, out_name='bar_foo') + "bar_foo": GraphQLArgument(GraphQLString, out_name="bar_foo") } def test_objecttype_with_possible_types(): + class MyObjectType(ObjectType): - '''Description''' + """Description""" + class Meta: - possible_types = (dict, ) + possible_types = (dict,) foo_bar = String() typemap = TypeMap([MyObjectType]) - graphql_type = typemap['MyObjectType'] + graphql_type = typemap["MyObjectType"] assert graphql_type.is_type_of assert graphql_type.is_type_of({}, None) is True assert graphql_type.is_type_of(MyObjectType(), None) is False def test_resolve_type_with_missing_type(): + class MyObjectType(ObjectType): foo_bar = String() @@ -245,8 +283,6 @@ def test_resolve_type_with_missing_type(): typemap = TypeMap([MyObjectType]) with pytest.raises(AssertionError) as excinfo: - resolve_type( - resolve_type_func, typemap, 'MyOtherObjectType', {}, {} - ) + resolve_type(resolve_type_func, typemap, "MyOtherObjectType", {}, {}) - assert 'MyOtherObjectTyp' in str(excinfo.value) + assert "MyOtherObjectTyp" in str(excinfo.value) diff --git a/graphene/types/tests/test_union.py b/graphene/types/tests/test_union.py index ac2708ad..8d46b00b 100644 --- a/graphene/types/tests/test_union.py +++ b/graphene/types/tests/test_union.py @@ -15,8 +15,10 @@ class MyObjectType2(ObjectType): def test_generate_union(): + class MyUnion(Union): - '''Documentation''' + """Documentation""" + class Meta: types = (MyObjectType1, MyObjectType2) @@ -26,11 +28,12 @@ def test_generate_union(): def test_generate_union_with_meta(): + class MyUnion(Union): class Meta: - name = 'MyOtherUnion' - description = 'Documentation' + name = "MyOtherUnion" + description = "Documentation" types = (MyObjectType1, MyObjectType2) assert MyUnion._meta.name == "MyOtherUnion" @@ -39,13 +42,15 @@ def test_generate_union_with_meta(): def test_generate_union_with_no_types(): with pytest.raises(Exception) as exc_info: + class MyUnion(Union): pass - assert str(exc_info.value) == 'Must provide types for Union MyUnion.' + assert str(exc_info.value) == "Must provide types for Union MyUnion." def test_union_can_be_mounted(): + class MyUnion(Union): class Meta: diff --git a/graphene/types/tests/test_uuid.py b/graphene/types/tests/test_uuid.py index 188ebcb8..9b3f93a0 100644 --- a/graphene/types/tests/test_uuid.py +++ b/graphene/types/tests/test_uuid.py @@ -14,22 +14,18 @@ schema = Schema(query=Query) def test_uuidstring_query(): - uuid_value = 'dfeb3bcf-70fd-11e7-a61a-6003088f8204' - result = schema.execute('''{ uuid(input: "%s") }''' % uuid_value) + uuid_value = "dfeb3bcf-70fd-11e7-a61a-6003088f8204" + result = schema.execute("""{ uuid(input: "%s") }""" % uuid_value) assert not result.errors - assert result.data == { - 'uuid': uuid_value - } + assert result.data == {"uuid": uuid_value} def test_uuidstring_query_variable(): - uuid_value = 'dfeb3bcf-70fd-11e7-a61a-6003088f8204' + uuid_value = "dfeb3bcf-70fd-11e7-a61a-6003088f8204" result = schema.execute( - '''query Test($uuid: UUID){ uuid(input: $uuid) }''', - variable_values={'uuid': uuid_value} + """query Test($uuid: UUID){ uuid(input: $uuid) }""", + variable_values={"uuid": uuid_value}, ) assert not result.errors - assert result.data == { - 'uuid': uuid_value - } + assert result.data == {"uuid": uuid_value} diff --git a/graphene/types/typemap.py b/graphene/types/typemap.py index b2bc4a0e..cb44175a 100644 --- a/graphene/types/typemap.py +++ b/graphene/types/typemap.py @@ -2,19 +2,33 @@ import inspect from collections import OrderedDict from functools import partial -from graphql import (GraphQLArgument, GraphQLBoolean, GraphQLField, - GraphQLFloat, GraphQLID, GraphQLInputObjectField, - GraphQLInt, GraphQLList, GraphQLNonNull, GraphQLString) +from graphql import ( + GraphQLArgument, + GraphQLBoolean, + GraphQLField, + GraphQLFloat, + GraphQLID, + GraphQLInputObjectField, + GraphQLInt, + GraphQLList, + GraphQLNonNull, + GraphQLString, +) from graphql.execution.executor import get_default_resolve_type_fn from graphql.type import GraphQLEnumValue from graphql.type.typemap import GraphQLTypeMap from ..utils.get_unbound_function import get_unbound_function from ..utils.str_converters import to_camel_case -from .definitions import (GrapheneEnumType, GrapheneGraphQLType, - GrapheneInputObjectType, GrapheneInterfaceType, - GrapheneObjectType, GrapheneScalarType, - GrapheneUnionType) +from .definitions import ( + GrapheneEnumType, + GrapheneGraphQLType, + GrapheneInputObjectType, + GrapheneInterfaceType, + GrapheneObjectType, + GrapheneScalarType, + GrapheneUnionType, +) from .dynamic import Dynamic from .enum import Enum from .field import Field @@ -31,9 +45,9 @@ from .utils import get_field_as def is_graphene_type(_type): if isinstance(_type, (List, NonNull)): return True - if inspect.isclass(_type) and issubclass(_type, - (ObjectType, InputObjectType, - Scalar, Interface, Union, Enum)): + if inspect.isclass(_type) and issubclass( + _type, (ObjectType, InputObjectType, Scalar, Interface, Union, Enum) + ): return True @@ -46,11 +60,9 @@ def resolve_type(resolve_type_func, map, type_name, root, info): if inspect.isclass(_type) and issubclass(_type, ObjectType): graphql_type = map.get(_type._meta.name) - assert graphql_type, "Can't find type {} in schema".format( - _type._meta.name - ) + assert graphql_type, "Can't find type {} in schema".format(_type._meta.name) assert graphql_type.graphene_type == _type, ( - 'The type {} does not match with the associated graphene type {}.' + "The type {} does not match with the associated graphene type {}." ).format(_type, graphql_type.graphene_type) return graphql_type @@ -84,7 +96,7 @@ class TypeMap(GraphQLTypeMap): _type = map[type._meta.name] if isinstance(_type, GrapheneGraphQLType): assert _type.graphene_type == type, ( - 'Found different types with the same name in the schema: {}, {}.' + "Found different types with the same name in the schema: {}, {}." ).format(_type.graphene_type, type) return map @@ -101,8 +113,7 @@ class TypeMap(GraphQLTypeMap): elif issubclass(type, Union): internal_type = self.construct_union(map, type) else: - raise Exception( - "Expected Graphene type, but received: {}.".format(type)) + raise Exception("Expected Graphene type, but received: {}.".format(type)) return GraphQLTypeMap.reducer(map, internal_type) @@ -114,7 +125,7 @@ class TypeMap(GraphQLTypeMap): Int: GraphQLInt, Float: GraphQLFloat, Boolean: GraphQLBoolean, - ID: GraphQLID + ID: GraphQLID, } if type in _scalars: return _scalars[type] @@ -123,15 +134,16 @@ class TypeMap(GraphQLTypeMap): graphene_type=type, name=type._meta.name, description=type._meta.description, - serialize=getattr(type, 'serialize', None), - parse_value=getattr(type, 'parse_value', None), - parse_literal=getattr(type, 'parse_literal', None), ) + serialize=getattr(type, "serialize", None), + parse_value=getattr(type, "parse_value", None), + parse_literal=getattr(type, "parse_literal", None), + ) def construct_enum(self, map, type): values = OrderedDict() for name, value in type._meta.enum.__members__.items(): - description = getattr(value, 'description', None) - deprecation_reason = getattr(value, 'deprecation_reason', None) + description = getattr(value, "description", None) + deprecation_reason = getattr(value, "deprecation_reason", None) if not description and callable(type._meta.description): description = type._meta.description(value) @@ -142,22 +154,28 @@ class TypeMap(GraphQLTypeMap): name=name, value=value.value, description=description, - deprecation_reason=deprecation_reason) + deprecation_reason=deprecation_reason, + ) - type_description = type._meta.description(None) if callable(type._meta.description) else type._meta.description + type_description = ( + type._meta.description(None) + if callable(type._meta.description) + else type._meta.description + ) return GrapheneEnumType( graphene_type=type, values=values, name=type._meta.name, - description=type_description, ) + description=type_description, + ) def construct_objecttype(self, map, type): if type._meta.name in map: _type = map[type._meta.name] if isinstance(_type, GrapheneGraphQLType): assert _type.graphene_type == type, ( - 'Found different types with the same name in the schema: {}, {}.' + "Found different types with the same name in the schema: {}, {}." ).format(_type.graphene_type, type) return _type @@ -171,8 +189,9 @@ class TypeMap(GraphQLTypeMap): return interfaces if type._meta.possible_types: - is_type_of = partial(is_type_of_from_possible_types, - type._meta.possible_types) + is_type_of = partial( + is_type_of_from_possible_types, type._meta.possible_types + ) else: is_type_of = type.is_type_of @@ -182,27 +201,30 @@ class TypeMap(GraphQLTypeMap): description=type._meta.description, fields=partial(self.construct_fields_for_type, map, type), is_type_of=is_type_of, - interfaces=interfaces) + interfaces=interfaces, + ) def construct_interface(self, map, type): if type._meta.name in map: _type = map[type._meta.name] if isinstance(_type, GrapheneInterfaceType): assert _type.graphene_type == type, ( - 'Found different types with the same name in the schema: {}, {}.' + "Found different types with the same name in the schema: {}, {}." ).format(_type.graphene_type, type) return _type _resolve_type = None if type.resolve_type: - _resolve_type = partial(resolve_type, type.resolve_type, map, - type._meta.name) + _resolve_type = partial( + resolve_type, type.resolve_type, map, type._meta.name + ) return GrapheneInterfaceType( graphene_type=type, name=type._meta.name, description=type._meta.description, fields=partial(self.construct_fields_for_type, map, type), - resolve_type=_resolve_type, ) + resolve_type=_resolve_type, + ) def construct_inputobjecttype(self, map, type): return GrapheneInputObjectType( @@ -211,14 +233,16 @@ class TypeMap(GraphQLTypeMap): description=type._meta.description, container_type=type._meta.container, fields=partial( - self.construct_fields_for_type, map, type, is_input_type=True), + self.construct_fields_for_type, map, type, is_input_type=True + ), ) def construct_union(self, map, type): _resolve_type = None if type.resolve_type: - _resolve_type = partial(resolve_type, type.resolve_type, map, - type._meta.name) + _resolve_type = partial( + resolve_type, type.resolve_type, map, type._meta.name + ) def types(): union_types = [] @@ -233,7 +257,8 @@ class TypeMap(GraphQLTypeMap): graphene_type=type, name=type._meta.name, types=types, - resolve_type=_resolve_type, ) + resolve_type=_resolve_type, + ) def get_name(self, name): if self.auto_camelcase: @@ -254,7 +279,8 @@ class TypeMap(GraphQLTypeMap): field_type, default_value=field.default_value, out_name=name, - description=field.description) + description=field.description, + ) else: args = OrderedDict() for arg_name, arg in field.args.items(): @@ -265,19 +291,17 @@ class TypeMap(GraphQLTypeMap): arg_type, out_name=arg_name, description=arg.description, - default_value=arg.default_value) + default_value=arg.default_value, + ) _field = GraphQLField( field_type, args=args, resolver=field.get_resolver( - self.get_resolver_for_type( - type, - name, - field.default_value - ) + self.get_resolver_for_type(type, name, field.default_value) ), deprecation_reason=field.deprecation_reason, - description=field.description) + description=field.description, + ) field_name = field.name or self.get_name(name) fields[field_name] = _field return fields @@ -285,7 +309,7 @@ class TypeMap(GraphQLTypeMap): def get_resolver_for_type(self, type, name, default_value): if not issubclass(type, ObjectType): return - resolver = getattr(type, 'resolve_{}'.format(name), None) + resolver = getattr(type, "resolve_{}".format(name), None) if not resolver: # If we don't find the resolver in the ObjectType class, then try to # find it in each of the interfaces @@ -293,8 +317,7 @@ class TypeMap(GraphQLTypeMap): for interface in type._meta.interfaces: if name not in interface._meta.fields: continue - interface_resolver = getattr(interface, - 'resolve_{}'.format(name), None) + interface_resolver = getattr(interface, "resolve_{}".format(name), None) if interface_resolver: break resolver = interface_resolver @@ -303,8 +326,7 @@ class TypeMap(GraphQLTypeMap): if resolver: return get_unbound_function(resolver) - default_resolver = type._meta.default_resolver or get_default_resolver( - ) + default_resolver = type._meta.default_resolver or get_default_resolver() return partial(default_resolver, name, default_value) def get_field_type(self, map, type): diff --git a/graphene/types/union.py b/graphene/types/union.py index 45e03b0c..dc207e8e 100644 --- a/graphene/types/union.py +++ b/graphene/types/union.py @@ -13,19 +13,19 @@ class UnionOptions(BaseOptions): class Union(UnmountedType, BaseType): - ''' + """ Union Type Definition When a field can return one of a heterogeneous set of types, a Union type is used to describe what types are possible as well as providing a function to determine which type is actually used when the field is resolved. - ''' + """ + @classmethod def __init_subclass_with_meta__(cls, types=None, **options): assert ( - isinstance(types, (list, tuple)) and - len(types) > 0 - ), 'Must provide types for Union {name}.'.format(name=cls.__name__) + isinstance(types, (list, tuple)) and len(types) > 0 + ), "Must provide types for Union {name}.".format(name=cls.__name__) _meta = UnionOptions(cls) _meta.types = types @@ -33,14 +33,15 @@ class Union(UnmountedType, BaseType): @classmethod def get_type(cls): - ''' + """ This function is called when the unmounted type (Union instance) is mounted (as a Field, InputField or Argument) - ''' + """ return cls @classmethod def resolve_type(cls, instance, info): from .objecttype import ObjectType # NOQA + if isinstance(instance, ObjectType): return type(instance) diff --git a/graphene/types/unmountedtype.py b/graphene/types/unmountedtype.py index 9698795c..5bcdab55 100644 --- a/graphene/types/unmountedtype.py +++ b/graphene/types/unmountedtype.py @@ -2,7 +2,7 @@ from ..utils.orderedtype import OrderedType class UnmountedType(OrderedType): - ''' + """ This class acts a proxy for a Graphene Type, so it can be mounted dynamically as Field, InputField or Argument. @@ -13,7 +13,7 @@ class UnmountedType(OrderedType): It let you write >>> class MyObjectType(ObjectType): >>> my_field = String(description='Description here') - ''' + """ def __init__(self, *args, **kwargs): super(UnmountedType, self).__init__() @@ -21,42 +21,43 @@ class UnmountedType(OrderedType): self.kwargs = kwargs def get_type(self): - ''' + """ This function is called when the UnmountedType instance is mounted (as a Field, InputField or Argument) - ''' + """ raise NotImplementedError("get_type not implemented in {}".format(self)) def mount_as(self, _as): return _as.mounted(self) def Field(self): # noqa: N802 - ''' + """ Mount the UnmountedType as Field - ''' + """ from .field import Field + return self.mount_as(Field) def InputField(self): # noqa: N802 - ''' + """ Mount the UnmountedType as InputField - ''' + """ from .inputfield import InputField + return self.mount_as(InputField) def Argument(self): # noqa: N802 - ''' + """ Mount the UnmountedType as Argument - ''' + """ from .argument import Argument + return self.mount_as(Argument) def __eq__(self, other): - return ( - self is other or ( - isinstance(other, UnmountedType) and - self.get_type() == other.get_type() and - self.args == other.args and - self.kwargs == other.kwargs - ) + return self is other or ( + isinstance(other, UnmountedType) + and self.get_type() == other.get_type() + and self.args == other.args + and self.kwargs == other.kwargs ) diff --git a/graphene/types/utils.py b/graphene/types/utils.py index c4434199..b026355b 100644 --- a/graphene/types/utils.py +++ b/graphene/types/utils.py @@ -10,9 +10,9 @@ from .unmountedtype import UnmountedType def get_field_as(value, _as=None): - ''' + """ Get type mounted - ''' + """ if isinstance(value, MountedType): return value elif isinstance(value, UnmountedType): @@ -22,10 +22,10 @@ def get_field_as(value, _as=None): def yank_fields_from_attrs(attrs, _as=None, sort=True): - ''' + """ Extract all the fields in given attributes (dict) and return them ordered - ''' + """ fields_with_names = [] for attname, value in list(attrs.items()): field = get_field_as(value, _as) diff --git a/graphene/types/uuid.py b/graphene/types/uuid.py index 7686f682..abb8f110 100644 --- a/graphene/types/uuid.py +++ b/graphene/types/uuid.py @@ -8,13 +8,15 @@ from .scalars import Scalar class UUID(Scalar): - '''UUID''' + """UUID""" @staticmethod def serialize(uuid): if isinstance(uuid, str): uuid = _UUID(uuid) - assert isinstance(uuid, _UUID), "Expected UUID instance, received {}".format(uuid) + assert isinstance(uuid, _UUID), "Expected UUID instance, received {}".format( + uuid + ) return str(uuid) @staticmethod diff --git a/graphene/utils/annotate.py b/graphene/utils/annotate.py index 9abb8e06..43a26ef6 100644 --- a/graphene/utils/annotate.py +++ b/graphene/utils/annotate.py @@ -12,8 +12,10 @@ def annotate(_func=None, _trigger_warning=True, **annotations): ) if not _func: + def _func(f): return annotate(f, **annotations) + return _func func_signature = signature(_func) @@ -22,12 +24,9 @@ def annotate(_func=None, _trigger_warning=True, **annotations): for key, value in annotations.items(): assert key in func_signature.parameters, ( 'The key {key} is not a function parameter in the function "{func_name}".' - ).format( - key=key, - func_name=func_name(_func) - ) + ).format(key=key, func_name=func_name(_func)) - func_annotations = getattr(_func, '__annotations__', None) + func_annotations = getattr(_func, "__annotations__", None) if func_annotations is None: _func.__annotations__ = annotations else: diff --git a/graphene/utils/crunch.py b/graphene/utils/crunch.py index 16902e2b..57fcb77f 100644 --- a/graphene/utils/crunch.py +++ b/graphene/utils/crunch.py @@ -21,9 +21,7 @@ def flatten(data, index, values): if isinstance(data, (list, tuple)): flattened = [flatten(child, index, values) for child in data] elif isinstance(data, Mapping): - flattened = { - key: flatten(child, index, values) for key, child in data.items() - } + flattened = {key: flatten(child, index, values) for key, child in data.items()} else: flattened = data return insert(flattened, index, values) diff --git a/graphene/utils/deduplicator.py b/graphene/utils/deduplicator.py index fd5682b1..13c1cb16 100644 --- a/graphene/utils/deduplicator.py +++ b/graphene/utils/deduplicator.py @@ -7,15 +7,12 @@ def deflate(node, index=None, path=None): if path is None: path = [] - if node and 'id' in node and '__typename' in node: - route = ','.join(path) - cache_key = ':'.join([route, str(node['__typename']), str(node['id'])]) + if node and "id" in node and "__typename" in node: + route = ",".join(path) + cache_key = ":".join([route, str(node["__typename"]), str(node["id"])]) if index.get(cache_key) is True: - return { - '__typename': node['__typename'], - 'id': node['id'], - } + return {"__typename": node["__typename"], "id": node["id"]} else: index[cache_key] = True @@ -27,9 +24,7 @@ def deflate(node, index=None, path=None): new_path = path + [field_name] if isinstance(value, (list, tuple)): - result[field_name] = [ - deflate(child, index, new_path) for child in value - ] + result[field_name] = [deflate(child, index, new_path) for child in value] elif isinstance(value, Mapping): result[field_name] = deflate(value, index, new_path) else: diff --git a/graphene/utils/deprecated.py b/graphene/utils/deprecated.py index d00642f8..2f98d829 100644 --- a/graphene/utils/deprecated.py +++ b/graphene/utils/deprecated.py @@ -2,15 +2,11 @@ import functools import inspect import warnings -string_types = (type(b''), type(u'')) +string_types = (type(b""), type(u"")) def warn_deprecation(text): - warnings.warn( - text, - category=DeprecationWarning, - stacklevel=2 - ) + warnings.warn(text, category=DeprecationWarning, stacklevel=2) def deprecated(reason): @@ -39,9 +35,7 @@ def deprecated(reason): @functools.wraps(func1) def new_func1(*args, **kwargs): - warn_deprecation( - fmt1.format(name=func1.__name__, reason=reason), - ) + warn_deprecation(fmt1.format(name=func1.__name__, reason=reason)) return func1(*args, **kwargs) return new_func1 @@ -67,9 +61,7 @@ def deprecated(reason): @functools.wraps(func2) def new_func2(*args, **kwargs): - warn_deprecation( - fmt2.format(name=func2.__name__), - ) + warn_deprecation(fmt2.format(name=func2.__name__)) return func2(*args, **kwargs) return new_func2 diff --git a/graphene/utils/get_unbound_function.py b/graphene/utils/get_unbound_function.py index 64add00a..bd311e34 100644 --- a/graphene/utils/get_unbound_function.py +++ b/graphene/utils/get_unbound_function.py @@ -1,4 +1,4 @@ def get_unbound_function(func): - if not getattr(func, '__self__', True): + if not getattr(func, "__self__", True): return func.__func__ return func diff --git a/graphene/utils/module_loading.py b/graphene/utils/module_loading.py index f544cf24..25dc86ca 100644 --- a/graphene/utils/module_loading.py +++ b/graphene/utils/module_loading.py @@ -11,7 +11,7 @@ def import_string(dotted_path, dotted_attributes=None): attribute path. Raise ImportError if the import failed. """ try: - module_path, class_name = dotted_path.rsplit('.', 1) + module_path, class_name = dotted_path.rsplit(".", 1) except ValueError: raise ImportError("%s doesn't look like a module path" % dotted_path) @@ -20,14 +20,15 @@ def import_string(dotted_path, dotted_attributes=None): try: result = getattr(module, class_name) except AttributeError: - raise ImportError('Module "%s" does not define a "%s" attribute/class' % ( - module_path, class_name) + raise ImportError( + 'Module "%s" does not define a "%s" attribute/class' + % (module_path, class_name) ) if not dotted_attributes: return result else: - attributes = dotted_attributes.split('.') + attributes = dotted_attributes.split(".") traveled_attributes = [] try: for attribute in attributes: @@ -35,9 +36,10 @@ def import_string(dotted_path, dotted_attributes=None): result = getattr(result, attribute) return result except AttributeError: - raise ImportError('Module "%s" does not define a "%s" attribute inside attribute/class "%s"' % ( - module_path, '.'.join(traveled_attributes), class_name - )) + raise ImportError( + 'Module "%s" does not define a "%s" attribute inside attribute/class "%s"' + % (module_path, ".".join(traveled_attributes), class_name) + ) def lazy_import(dotted_path, dotted_attributes=None): diff --git a/graphene/utils/props.py b/graphene/utils/props.py index 5162720e..67fa8a4e 100644 --- a/graphene/utils/props.py +++ b/graphene/utils/props.py @@ -10,6 +10,4 @@ _all_vars = set(dir(_OldClass) + dir(_NewClass)) def props(x): - return { - key: value for key, value in vars(x).items() if key not in _all_vars - } + return {key: value for key, value in vars(x).items() if key not in _all_vars} diff --git a/graphene/utils/resolve_only_args.py b/graphene/utils/resolve_only_args.py index 7862dedd..009d17ac 100644 --- a/graphene/utils/resolve_only_args.py +++ b/graphene/utils/resolve_only_args.py @@ -3,8 +3,9 @@ from functools import wraps from .deprecated import deprecated -@deprecated('This function is deprecated') +@deprecated("This function is deprecated") def resolve_only_args(func): + @wraps(func) def wrapped_func(root, info, **args): return func(root, **args) diff --git a/graphene/utils/str_converters.py b/graphene/utils/str_converters.py index 6fcdfb7b..d8804038 100644 --- a/graphene/utils/str_converters.py +++ b/graphene/utils/str_converters.py @@ -4,18 +4,18 @@ import re # Adapted from this response in Stackoverflow # http://stackoverflow.com/a/19053800/1072990 def to_camel_case(snake_str): - components = snake_str.split('_') + components = snake_str.split("_") # We capitalize the first letter of each component except the first one # with the 'capitalize' method and join them together. - return components[0] + ''.join(x.capitalize() if x else '_' for x in components[1:]) + return components[0] + "".join(x.capitalize() if x else "_" for x in components[1:]) # From this response in Stackoverflow # http://stackoverflow.com/a/1176023/1072990 def to_snake_case(name): - s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name) - return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower() + s1 = re.sub("(.)([A-Z][a-z]+)", r"\1_\2", name) + return re.sub("([a-z0-9])([A-Z])", r"\1_\2", s1).lower() def to_const(string): - return re.sub('[\W|^]+', '_', string).upper() + return re.sub("[\W|^]+", "_", string).upper() diff --git a/graphene/utils/subclass_with_meta.py b/graphene/utils/subclass_with_meta.py index b0c8dee2..9905feb2 100644 --- a/graphene/utils/subclass_with_meta.py +++ b/graphene/utils/subclass_with_meta.py @@ -32,19 +32,22 @@ class SubclassWithMeta(six.with_metaclass(SubclassWithMeta_Meta)): _meta_props = props(_Meta) else: raise Exception( - "Meta have to be either a class or a dict. Received {}".format(_Meta)) + "Meta have to be either a class or a dict. Received {}".format( + _Meta + ) + ) delattr(cls, "Meta") options = dict(meta_options, **_meta_props) - abstract = options.pop('abstract', False) + abstract = options.pop("abstract", False) if abstract: assert not options, ( "Abstract types can only contain the abstract attribute. " "Received: abstract, {option_keys}" - ).format(option_keys=', '.join(options.keys())) + ).format(option_keys=", ".join(options.keys())) else: super_class = super(cls, cls) - if hasattr(super_class, '__init_subclass_with_meta__'): + if hasattr(super_class, "__init_subclass_with_meta__"): super_class.__init_subclass_with_meta__(**options) @classmethod diff --git a/graphene/utils/tests/test_annotate.py b/graphene/utils/tests/test_annotate.py index 259df3cb..1b7b4ce1 100644 --- a/graphene/utils/tests/test_annotate.py +++ b/graphene/utils/tests/test_annotate.py @@ -7,12 +7,7 @@ def func(a, b, *c, **d): pass -annotations = { - 'a': int, - 'b': str, - 'c': list, - 'd': dict -} +annotations = {"a": int, "b": str, "c": list, "d": dict} def func_with_annotations(a, b, *c, **d): @@ -36,4 +31,7 @@ def test_annotate_with_wront_params(): with pytest.raises(Exception) as exc_info: annotate(p=int, _trigger_warning=False)(func) - assert str(exc_info.value) == 'The key p is not a function parameter in the function "func".' + assert ( + str(exc_info.value) + == 'The key p is not a function parameter in the function "func".' + ) diff --git a/graphene/utils/tests/test_crunch.py b/graphene/utils/tests/test_crunch.py index 6dd396c6..9646a257 100644 --- a/graphene/utils/tests/test_crunch.py +++ b/graphene/utils/tests/test_crunch.py @@ -4,45 +4,55 @@ from collections import OrderedDict from ..crunch import crunch -@pytest.mark.parametrize("description,uncrunched,crunched", [ - ['number primitive', 0, [0]], - ['boolean primitive', True, [True]], - ['string primitive', "string", ["string"]], - ['empty array', [], [[]]], - ['single-item array', [None], [None, [0]]], - ['multi-primitive all distinct array', [None, 0, True, "string"], [None, 0, True, "string", [0, 1, 2, 3]]], - ['multi-primitive repeated array', [True, True, True, True], [True, [0, 0, 0, 0]]], - ['one-level nested array', [[1, 2, 3]], [1, 2, 3, [0, 1, 2], [3]]], - ['two-level nested array', [[[1, 2, 3]]], [1, 2, 3, [0, 1, 2], [3], [4]]], - ['empty object', {}, [{}]], - ['single-item object', {'a': None}, [None, {'a': 0}]], +@pytest.mark.parametrize( + "description,uncrunched,crunched", [ - 'multi-item all distinct object', - OrderedDict([('a', None), ('b', 0), ('c', True), ('d', 'string')]), - [None, 0, True, "string", {'a': 0, 'b': 1, 'c': 2, 'd': 3}] - ], - [ - 'multi-item repeated object', - OrderedDict([('a', True), ('b', True), ('c', True), ('d', True)]), - [True, {'a': 0, 'b': 0, 'c': 0, 'd': 0}] - ], - [ - 'complex array', + ["number primitive", 0, [0]], + ["boolean primitive", True, [True]], + ["string primitive", "string", ["string"]], + ["empty array", [], [[]]], + ["single-item array", [None], [None, [0]]], [ - OrderedDict([('a', True), ('b', [1, 2, 3])]), - [1, 2, 3] + "multi-primitive all distinct array", + [None, 0, True, "string"], + [None, 0, True, "string", [0, 1, 2, 3]], + ], + [ + "multi-primitive repeated array", + [True, True, True, True], + [True, [0, 0, 0, 0]], + ], + ["one-level nested array", [[1, 2, 3]], [1, 2, 3, [0, 1, 2], [3]]], + ["two-level nested array", [[[1, 2, 3]]], [1, 2, 3, [0, 1, 2], [3], [4]]], + ["empty object", {}, [{}]], + ["single-item object", {"a": None}, [None, {"a": 0}]], + [ + "multi-item all distinct object", + OrderedDict([("a", None), ("b", 0), ("c", True), ("d", "string")]), + [None, 0, True, "string", {"a": 0, "b": 1, "c": 2, "d": 3}], + ], + [ + "multi-item repeated object", + OrderedDict([("a", True), ("b", True), ("c", True), ("d", True)]), + [True, {"a": 0, "b": 0, "c": 0, "d": 0}], + ], + [ + "complex array", + [OrderedDict([("a", True), ("b", [1, 2, 3])]), [1, 2, 3]], + [True, 1, 2, 3, [1, 2, 3], {"a": 0, "b": 4}, [5, 4]], + ], + [ + "complex object", + OrderedDict( + [ + ("a", True), + ("b", [1, 2, 3]), + ("c", OrderedDict([("a", True), ("b", [1, 2, 3])])), + ] + ), + [True, 1, 2, 3, [1, 2, 3], {"a": 0, "b": 4}, {"a": 0, "b": 4, "c": 5}], ], - [True, 1, 2, 3, [1, 2, 3], {'a': 0, 'b': 4}, [5, 4]] ], - [ - 'complex object', - OrderedDict([ - ('a', True), - ('b', [1, 2, 3]), - ('c', OrderedDict([('a', True), ('b', [1, 2, 3])])) - ]), - [True, 1, 2, 3, [1, 2, 3], {'a': 0, 'b': 4}, {'a': 0, 'b': 4, 'c': 5}] - ], -]) +) def test_crunch(description, uncrunched, crunched): assert crunch(uncrunched) == crunched diff --git a/graphene/utils/tests/test_deduplicator.py b/graphene/utils/tests/test_deduplicator.py index d73fbfbe..d65f6fd0 100644 --- a/graphene/utils/tests/test_deduplicator.py +++ b/graphene/utils/tests/test_deduplicator.py @@ -7,179 +7,108 @@ from ..deduplicator import deflate def test_does_not_modify_object_without_typename_and_id(): - response = { - 'foo': 'bar', - } + response = {"foo": "bar"} deflated_response = deflate(response) - assert deflated_response == { - 'foo': 'bar', - } + assert deflated_response == {"foo": "bar"} def test_does_not_modify_first_instance_of_an_object(): response = { - 'data': [ - { - '__typename': 'foo', - 'id': 1, - 'name': 'foo' - }, - { - '__typename': 'foo', - 'id': 1, - 'name': 'foo' - } + "data": [ + {"__typename": "foo", "id": 1, "name": "foo"}, + {"__typename": "foo", "id": 1, "name": "foo"}, ] } deflated_response = deflate(response) assert deflated_response == { - 'data': [ - { - '__typename': 'foo', - 'id': 1, - 'name': 'foo' - }, - { - '__typename': 'foo', - 'id': 1 - } + "data": [ + {"__typename": "foo", "id": 1, "name": "foo"}, + {"__typename": "foo", "id": 1}, ] } def test_does_not_modify_first_instance_of_an_object_nested(): response = { - 'data': [ + "data": [ { - '__typename': 'foo', - 'bar1': { - '__typename': 'bar', - 'id': 1, - 'name': 'bar' - }, - 'bar2': { - '__typename': 'bar', - 'id': 1, - 'name': 'bar' - }, - 'id': 1 + "__typename": "foo", + "bar1": {"__typename": "bar", "id": 1, "name": "bar"}, + "bar2": {"__typename": "bar", "id": 1, "name": "bar"}, + "id": 1, }, { - '__typename': 'foo', - 'bar1': { - '__typename': 'bar', - 'id': 1, - 'name': 'bar' - }, - 'bar2': { - '__typename': 'bar', - 'id': 1, - 'name': 'bar' - }, - 'id': 2 - } + "__typename": "foo", + "bar1": {"__typename": "bar", "id": 1, "name": "bar"}, + "bar2": {"__typename": "bar", "id": 1, "name": "bar"}, + "id": 2, + }, ] } deflated_response = deflate(response) assert deflated_response == { - 'data': [ + "data": [ { - '__typename': 'foo', - 'bar1': { - '__typename': 'bar', - 'id': 1, - 'name': 'bar' - }, - 'bar2': { - '__typename': 'bar', - 'id': 1, - 'name': 'bar' - }, - 'id': 1 + "__typename": "foo", + "bar1": {"__typename": "bar", "id": 1, "name": "bar"}, + "bar2": {"__typename": "bar", "id": 1, "name": "bar"}, + "id": 1, }, { - '__typename': 'foo', - 'bar1': { - '__typename': 'bar', - 'id': 1 - }, - 'bar2': { - '__typename': 'bar', - 'id': 1 - }, - 'id': 2 - } + "__typename": "foo", + "bar1": {"__typename": "bar", "id": 1}, + "bar2": {"__typename": "bar", "id": 1}, + "id": 2, + }, ] } def test_does_not_modify_input(): response = { - 'data': [ - { - '__typename': 'foo', - 'id': 1, - 'name': 'foo' - }, - { - '__typename': 'foo', - 'id': 1, - 'name': 'foo' - } + "data": [ + {"__typename": "foo", "id": 1, "name": "foo"}, + {"__typename": "foo", "id": 1, "name": "foo"}, ] } deflate(response) assert response == { - 'data': [ - { - '__typename': 'foo', - 'id': 1, - 'name': 'foo' - }, - { - '__typename': 'foo', - 'id': 1, - 'name': 'foo' - } + "data": [ + {"__typename": "foo", "id": 1, "name": "foo"}, + {"__typename": "foo", "id": 1, "name": "foo"}, ] } TEST_DATA = { - 'events': [ - { - 'id': '568', - 'date': datetime.date(2017, 5, 19), - 'movie': '1198359', - }, - { - 'id': '234', - 'date': datetime.date(2017, 5, 20), - 'movie': '1198359', - }, + "events": [ + {"id": "568", "date": datetime.date(2017, 5, 19), "movie": "1198359"}, + {"id": "234", "date": datetime.date(2017, 5, 20), "movie": "1198359"}, ], - 'movies': { - '1198359': { - 'name': 'King Arthur: Legend of the Sword', - 'synopsis': ( + "movies": { + "1198359": { + "name": "King Arthur: Legend of the Sword", + "synopsis": ( "When the child Arthur's father is murdered, Vortigern, " "Arthur's uncle, seizes the crown. Robbed of his birthright and " "with no idea who he truly is..." ), - }, + } }, } def test_example_end_to_end(): + class Movie(graphene.ObjectType): + class Meta: interfaces = (relay.Node,) default_resolver = dict_resolver @@ -188,6 +117,7 @@ def test_example_end_to_end(): synopsis = graphene.String(required=True) class Event(graphene.ObjectType): + class Meta: interfaces = (relay.Node,) default_resolver = dict_resolver @@ -196,16 +126,13 @@ def test_example_end_to_end(): date = graphene.types.datetime.Date(required=True) def resolve_movie(event, info): - return TEST_DATA['movies'][event['movie']] + return TEST_DATA["movies"][event["movie"]] class Query(graphene.ObjectType): - events = graphene.List( - graphene.NonNull(Event), - required=True - ) + events = graphene.List(graphene.NonNull(Event), required=True) def resolve_events(_, info): - return TEST_DATA['events'] + return TEST_DATA["events"] schema = graphene.Schema(query=Query) query = """\ @@ -228,16 +155,16 @@ def test_example_end_to_end(): result.data = deflate(result.data) assert result.data == { - 'events': [ + "events": [ { - '__typename': 'Event', - 'id': 'RXZlbnQ6NTY4', - 'date': '2017-05-19', - 'movie': { - '__typename': 'Movie', - 'id': 'TW92aWU6Tm9uZQ==', - 'name': 'King Arthur: Legend of the Sword', - 'synopsis': ( + "__typename": "Event", + "id": "RXZlbnQ6NTY4", + "date": "2017-05-19", + "movie": { + "__typename": "Movie", + "id": "TW92aWU6Tm9uZQ==", + "name": "King Arthur: Legend of the Sword", + "synopsis": ( "When the child Arthur's father is murdered, Vortigern, " "Arthur's uncle, seizes the crown. Robbed of his birthright and " "with no idea who he truly is..." @@ -245,13 +172,10 @@ def test_example_end_to_end(): }, }, { - '__typename': 'Event', - 'id': 'RXZlbnQ6MjM0', - 'date': '2017-05-20', - 'movie': { - '__typename': 'Movie', - 'id': 'TW92aWU6Tm9uZQ==', - }, + "__typename": "Event", + "id": "RXZlbnQ6MjM0", + "date": "2017-05-20", + "movie": {"__typename": "Movie", "id": "TW92aWU6Tm9uZQ=="}, }, - ], + ] } diff --git a/graphene/utils/tests/test_deprecated.py b/graphene/utils/tests/test_deprecated.py index 16fca03b..7d407548 100644 --- a/graphene/utils/tests/test_deprecated.py +++ b/graphene/utils/tests/test_deprecated.py @@ -6,14 +6,16 @@ from ..deprecated import warn_deprecation def test_warn_deprecation(mocker): - mocker.patch.object(deprecated.warnings, 'warn') + mocker.patch.object(deprecated.warnings, "warn") warn_deprecation("OH!") - deprecated.warnings.warn.assert_called_with('OH!', stacklevel=2, category=DeprecationWarning) + deprecated.warnings.warn.assert_called_with( + "OH!", stacklevel=2, category=DeprecationWarning + ) def test_deprecated_decorator(mocker): - mocker.patch.object(deprecated, 'warn_deprecation') + mocker.patch.object(deprecated, "warn_deprecation") @deprecated_decorator def my_func(): @@ -21,11 +23,13 @@ def test_deprecated_decorator(mocker): result = my_func() assert result - deprecated.warn_deprecation.assert_called_with("Call to deprecated function my_func.") + deprecated.warn_deprecation.assert_called_with( + "Call to deprecated function my_func." + ) def test_deprecated_class(mocker): - mocker.patch.object(deprecated, 'warn_deprecation') + mocker.patch.object(deprecated, "warn_deprecation") @deprecated_decorator class X: @@ -37,7 +41,7 @@ def test_deprecated_class(mocker): def test_deprecated_decorator_text(mocker): - mocker.patch.object(deprecated, 'warn_deprecation') + mocker.patch.object(deprecated, "warn_deprecation") @deprecated_decorator("Deprecation text") def my_func(): @@ -45,11 +49,13 @@ def test_deprecated_decorator_text(mocker): result = my_func() assert result - deprecated.warn_deprecation.assert_called_with("Call to deprecated function my_func (Deprecation text).") + deprecated.warn_deprecation.assert_called_with( + "Call to deprecated function my_func (Deprecation text)." + ) def test_deprecated_class_text(mocker): - mocker.patch.object(deprecated, 'warn_deprecation') + mocker.patch.object(deprecated, "warn_deprecation") @deprecated_decorator("Deprecation text") class X: @@ -57,11 +63,13 @@ def test_deprecated_class_text(mocker): result = X() assert result - deprecated.warn_deprecation.assert_called_with("Call to deprecated class X (Deprecation text).") + deprecated.warn_deprecation.assert_called_with( + "Call to deprecated class X (Deprecation text)." + ) def test_deprecated_other_object(mocker): - mocker.patch.object(deprecated, 'warn_deprecation') + mocker.patch.object(deprecated, "warn_deprecation") with pytest.raises(TypeError): deprecated_decorator({}) diff --git a/graphene/utils/tests/test_module_loading.py b/graphene/utils/tests/test_module_loading.py index dd67ffe1..01e89bf3 100644 --- a/graphene/utils/tests/test_module_loading.py +++ b/graphene/utils/tests/test_module_loading.py @@ -6,52 +6,64 @@ from ..module_loading import import_string, lazy_import def test_import_string(): - MyString = import_string('graphene.String') + MyString = import_string("graphene.String") assert MyString == String - MyObjectTypeMeta = import_string('graphene.ObjectType', '__doc__') + MyObjectTypeMeta = import_string("graphene.ObjectType", "__doc__") assert MyObjectTypeMeta == ObjectType.__doc__ def test_import_string_module(): with raises(Exception) as exc_info: - import_string('graphenea') + import_string("graphenea") - assert str(exc_info.value) == 'graphenea doesn\'t look like a module path' + assert str(exc_info.value) == "graphenea doesn't look like a module path" def test_import_string_class(): with raises(Exception) as exc_info: - import_string('graphene.Stringa') + import_string("graphene.Stringa") - assert str(exc_info.value) == 'Module "graphene" does not define a "Stringa" attribute/class' + assert ( + str(exc_info.value) + == 'Module "graphene" does not define a "Stringa" attribute/class' + ) def test_import_string_attributes(): with raises(Exception) as exc_info: - import_string('graphene.String', 'length') + import_string("graphene.String", "length") - assert str(exc_info.value) == 'Module "graphene" does not define a "length" attribute inside attribute/class ' \ - '"String"' + assert ( + str(exc_info.value) + == 'Module "graphene" does not define a "length" attribute inside attribute/class ' + '"String"' + ) with raises(Exception) as exc_info: - import_string('graphene.ObjectType', '__class__.length') + import_string("graphene.ObjectType", "__class__.length") - assert str(exc_info.value) == 'Module "graphene" does not define a "__class__.length" attribute inside ' \ - 'attribute/class "ObjectType"' + assert ( + str(exc_info.value) + == 'Module "graphene" does not define a "__class__.length" attribute inside ' + 'attribute/class "ObjectType"' + ) with raises(Exception) as exc_info: - import_string('graphene.ObjectType', '__classa__.__base__') + import_string("graphene.ObjectType", "__classa__.__base__") - assert str(exc_info.value) == 'Module "graphene" does not define a "__classa__" attribute inside attribute/class ' \ - '"ObjectType"' + assert ( + str(exc_info.value) + == 'Module "graphene" does not define a "__classa__" attribute inside attribute/class ' + '"ObjectType"' + ) def test_lazy_import(): - f = lazy_import('graphene.String') + f = lazy_import("graphene.String") MyString = f() assert MyString == String - f = lazy_import('graphene.ObjectType', '__doc__') + f = lazy_import("graphene.ObjectType", "__doc__") MyObjectTypeMeta = f() assert MyObjectTypeMeta == ObjectType.__doc__ diff --git a/graphene/utils/tests/test_resolve_only_args.py b/graphene/utils/tests/test_resolve_only_args.py index 1dfd4789..4e44be9f 100644 --- a/graphene/utils/tests/test_resolve_only_args.py +++ b/graphene/utils/tests/test_resolve_only_args.py @@ -3,7 +3,7 @@ from ..resolve_only_args import resolve_only_args def test_resolve_only_args(mocker): - mocker.patch.object(deprecated, 'warn_deprecation') + mocker.patch.object(deprecated, "warn_deprecation") def resolver(root, **args): return root, args @@ -11,4 +11,4 @@ def test_resolve_only_args(mocker): wrapped_resolver = resolve_only_args(resolver) assert deprecated.warn_deprecation.called result = wrapped_resolver(1, 2, a=3) - assert result == (1, {'a': 3}) + assert result == (1, {"a": 3}) diff --git a/graphene/utils/tests/test_str_converters.py b/graphene/utils/tests/test_str_converters.py index 11f7e155..786149d9 100644 --- a/graphene/utils/tests/test_str_converters.py +++ b/graphene/utils/tests/test_str_converters.py @@ -3,21 +3,21 @@ from ..str_converters import to_camel_case, to_const, to_snake_case def test_snake_case(): - assert to_snake_case('snakesOnAPlane') == 'snakes_on_a_plane' - assert to_snake_case('SnakesOnAPlane') == 'snakes_on_a_plane' - assert to_snake_case('SnakesOnA_Plane') == 'snakes_on_a__plane' - assert to_snake_case('snakes_on_a_plane') == 'snakes_on_a_plane' - assert to_snake_case('snakes_on_a__plane') == 'snakes_on_a__plane' - assert to_snake_case('IPhoneHysteria') == 'i_phone_hysteria' - assert to_snake_case('iPhoneHysteria') == 'i_phone_hysteria' + assert to_snake_case("snakesOnAPlane") == "snakes_on_a_plane" + assert to_snake_case("SnakesOnAPlane") == "snakes_on_a_plane" + assert to_snake_case("SnakesOnA_Plane") == "snakes_on_a__plane" + assert to_snake_case("snakes_on_a_plane") == "snakes_on_a_plane" + assert to_snake_case("snakes_on_a__plane") == "snakes_on_a__plane" + assert to_snake_case("IPhoneHysteria") == "i_phone_hysteria" + assert to_snake_case("iPhoneHysteria") == "i_phone_hysteria" def test_camel_case(): - assert to_camel_case('snakes_on_a_plane') == 'snakesOnAPlane' - assert to_camel_case('snakes_on_a__plane') == 'snakesOnA_Plane' - assert to_camel_case('i_phone_hysteria') == 'iPhoneHysteria' - assert to_camel_case('field_i18n') == 'fieldI18n' + assert to_camel_case("snakes_on_a_plane") == "snakesOnAPlane" + assert to_camel_case("snakes_on_a__plane") == "snakesOnA_Plane" + assert to_camel_case("i_phone_hysteria") == "iPhoneHysteria" + assert to_camel_case("field_i18n") == "fieldI18n" def test_to_const(): - assert to_const('snakes $1. on a "#plane') == 'SNAKES_1_ON_A_PLANE' + assert to_const('snakes $1. on a "#plane') == "SNAKES_1_ON_A_PLANE" diff --git a/graphene/utils/tests/test_trim_docstring.py b/graphene/utils/tests/test_trim_docstring.py index 9695fad4..ab84d829 100644 --- a/graphene/utils/tests/test_trim_docstring.py +++ b/graphene/utils/tests/test_trim_docstring.py @@ -2,6 +2,7 @@ from ..trim_docstring import trim_docstring def test_trim_docstring(): + class WellDocumentedObject(object): """ This object is very well-documented. It has multiple lines in its @@ -10,9 +11,11 @@ def test_trim_docstring(): Multiple paragraphs too """ - assert (trim_docstring(WellDocumentedObject.__doc__) == - "This object is very well-documented. It has multiple lines in its\n" - "description.\n\nMultiple paragraphs too") + assert ( + trim_docstring(WellDocumentedObject.__doc__) + == "This object is very well-documented. It has multiple lines in its\n" + "description.\n\nMultiple paragraphs too" + ) class UndocumentedObject(object): pass diff --git a/setup.py b/setup.py index 46a9f427..5d6b414d 100644 --- a/setup.py +++ b/setup.py @@ -5,17 +5,17 @@ import sys from setuptools import find_packages, setup from setuptools.command.test import test as TestCommand -_version_re = re.compile(r'VERSION\s+=\s+(.*)') +_version_re = re.compile(r"VERSION\s+=\s+(.*)") -with open('graphene/__init__.py', 'rb') as f: - version = ast.literal_eval(_version_re.search( - f.read().decode('utf-8')).group(1)) +with open("graphene/__init__.py", "rb") as f: + version = ast.literal_eval(_version_re.search(f.read().decode("utf-8")).group(1)) path_copy = sys.path[:] -sys.path.append('graphene') +sys.path.append("graphene") try: from pyutils.version import get_version + version = get_version(version) except Exception: version = ".".join([str(v) for v in version]) @@ -24,7 +24,7 @@ sys.path[:] = path_copy class PyTest(TestCommand): - user_options = [('pytest-args=', 'a', "Arguments to pass to py.test")] + user_options = [("pytest-args=", "a", "Arguments to pass to py.test")] def initialize_options(self): TestCommand.initialize_options(self) @@ -38,71 +38,60 @@ class PyTest(TestCommand): def run_tests(self): # import here, cause outside the eggs aren't loaded import pytest + errno = pytest.main(self.pytest_args) sys.exit(errno) tests_require = [ - 'pytest', - 'pytest-benchmark', - 'pytest-cov', - 'pytest-mock', - 'snapshottest', - 'coveralls', - 'six', - 'mock', - 'pytz', - 'iso8601', + "pytest", + "pytest-benchmark", + "pytest-cov", + "pytest-mock", + "snapshottest", + "coveralls", + "six", + "mock", + "pytz", + "iso8601", ] setup( - name='graphene', + name="graphene", version=version, - - description='GraphQL Framework for Python', - long_description=open('README.rst').read(), - - url='https://github.com/graphql-python/graphene', - - author='Syrus Akbary', - author_email='me@syrusakbary.com', - - license='MIT', - + description="GraphQL Framework for Python", + long_description=open("README.rst").read(), + url="https://github.com/graphql-python/graphene", + author="Syrus Akbary", + author_email="me@syrusakbary.com", + license="MIT", classifiers=[ - 'Development Status :: 3 - Alpha', - 'Intended Audience :: Developers', - 'Topic :: Software Development :: Libraries', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: Implementation :: PyPy', + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "Topic :: Software Development :: Libraries", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.3", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: Implementation :: PyPy", ], - - keywords='api graphql protocol rest relay graphene', - - packages=find_packages(exclude=['tests', 'tests.*', 'examples']), - + keywords="api graphql protocol rest relay graphene", + packages=find_packages(exclude=["tests", "tests.*", "examples"]), install_requires=[ - 'six>=1.10.0,<2', - 'graphql-core>=2.0,<3', - 'graphql-relay>=0.4.5,<1', - 'promise>=2.1,<3', - 'aniso8601>=3,<4', + "six>=1.10.0,<2", + "graphql-core>=2.0,<3", + "graphql-relay>=0.4.5,<1", + "promise>=2.1,<3", + "aniso8601>=3,<4", ], tests_require=tests_require, extras_require={ - 'test': tests_require, - 'django': [ - 'graphene-django', - ], - 'sqlalchemy': [ - 'graphene-sqlalchemy', - ] + "test": tests_require, + "django": ["graphene-django"], + "sqlalchemy": ["graphene-sqlalchemy"], }, - cmdclass={'test': PyTest}, + cmdclass={"test": PyTest}, ) From 142f4a58d82635b03aec560322cc3d5f395e9910 Mon Sep 17 00:00:00 2001 From: Daniel Gallagher Date: Fri, 6 Jul 2018 14:03:15 -0700 Subject: [PATCH 45/45] Run black formatter via pre-commit on all files --- .pre-commit-config.yaml | 4 ++-- examples/complex_example.py | 1 - examples/starwars/schema.py | 2 -- examples/starwars_relay/schema.py | 2 -- graphene/pyutils/enum.py | 12 +++++------ graphene/pyutils/signature.py | 1 - graphene/relay/connection.py | 2 -- graphene/relay/mutation.py | 2 -- graphene/relay/node.py | 3 --- graphene/relay/tests/test_connection.py | 15 -------------- graphene/relay/tests/test_connection_query.py | 2 -- graphene/relay/tests/test_global_id.py | 3 --- graphene/relay/tests/test_mutation.py | 4 ---- graphene/relay/tests/test_node.py | 1 - graphene/relay/tests/test_node_custom.py | 3 --- graphene/test/__init__.py | 1 - graphene/tests/issues/test_313.py | 2 -- graphene/tests/issues/test_356.py | 2 -- graphene/tests/issues/test_425.py | 15 -------------- graphene/tests/issues/test_720.py | 2 -- graphene/types/abstracttype.py | 1 - graphene/types/argument.py | 1 - graphene/types/base.py | 1 - graphene/types/context.py | 1 - graphene/types/enum.py | 2 -- graphene/types/field.py | 1 - graphene/types/inputfield.py | 1 - graphene/types/inputobjecttype.py | 1 - graphene/types/mountedtype.py | 1 - graphene/types/tests/test_abstracttype.py | 2 -- graphene/types/tests/test_base.py | 4 ---- graphene/types/tests/test_definition.py | 11 ---------- graphene/types/tests/test_dynamic.py | 1 - graphene/types/tests/test_enum.py | 16 ++------------- graphene/types/tests/test_inputobjecttype.py | 11 ---------- graphene/types/tests/test_interface.py | 10 ---------- graphene/types/tests/test_mountedtype.py | 1 - graphene/types/tests/test_mutation.py | 10 ---------- graphene/types/tests/test_objecttype.py | 20 ------------------- graphene/types/tests/test_query.py | 20 ------------------- graphene/types/tests/test_scalar.py | 1 - graphene/types/tests/test_typemap.py | 16 +++++++-------- graphene/types/tests/test_union.py | 5 ----- graphene/types/typemap.py | 1 - graphene/utils/resolve_only_args.py | 1 - graphene/utils/subclass_with_meta.py | 1 + graphene/utils/tests/test_deduplicator.py | 3 --- graphene/utils/tests/test_trim_docstring.py | 1 - 48 files changed, 18 insertions(+), 206 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 153980eb..5f72385c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,11 +14,11 @@ repos: - --autofix - id: flake8 - repo: https://github.com/asottile/pyupgrade - rev: v1.2.0 + rev: v1.4.0 hooks: - id: pyupgrade - repo: https://github.com/ambv/black - rev: stable + rev: 18.6b4 hooks: - id: black language_version: python3.6 diff --git a/examples/complex_example.py b/examples/complex_example.py index 18ad89b9..3c2d77ba 100644 --- a/examples/complex_example.py +++ b/examples/complex_example.py @@ -22,7 +22,6 @@ class Query(graphene.ObjectType): class CreateAddress(graphene.Mutation): - class Arguments: geo = GeoInput(required=True) diff --git a/examples/starwars/schema.py b/examples/starwars/schema.py index b4182949..a0595734 100644 --- a/examples/starwars/schema.py +++ b/examples/starwars/schema.py @@ -21,7 +21,6 @@ class Character(graphene.Interface): class Human(graphene.ObjectType): - class Meta: interfaces = (Character,) @@ -29,7 +28,6 @@ class Human(graphene.ObjectType): class Droid(graphene.ObjectType): - class Meta: interfaces = (Character,) diff --git a/examples/starwars_relay/schema.py b/examples/starwars_relay/schema.py index f3ebb09d..3a1cd980 100644 --- a/examples/starwars_relay/schema.py +++ b/examples/starwars_relay/schema.py @@ -18,7 +18,6 @@ class Ship(graphene.ObjectType): class ShipConnection(relay.Connection): - class Meta: node = Ship @@ -44,7 +43,6 @@ class Faction(graphene.ObjectType): class IntroduceShip(relay.ClientIDMutation): - class Input: ship_name = graphene.String(required=True) faction_id = graphene.String(required=True) diff --git a/graphene/pyutils/enum.py b/graphene/pyutils/enum.py index 6ce91b23..84421e04 100644 --- a/graphene/pyutils/enum.py +++ b/graphene/pyutils/enum.py @@ -208,7 +208,7 @@ class EnumMeta(type): invalid_names = set(members) & {"mro"} if invalid_names: raise ValueError( - "Invalid enum member name(s): %s" % (", ".join(invalid_names),) + "Invalid enum member name(s): {}".format(", ".join(invalid_names)) ) # save attributes from super classes so we know if we can take @@ -682,7 +682,7 @@ def __new__(cls, value): for member in cls._member_map_.values(): if member.value == value: return member - raise ValueError("%s is not a valid %s" % (value, cls.__name__)) + raise ValueError("{} is not a valid {}".format(value, cls.__name__)) temp_enum_dict["__new__"] = __new__ @@ -690,7 +690,7 @@ del __new__ def __repr__(self): - return "<%s.%s: %r>" % (self.__class__.__name__, self._name_, self._value_) + return "<{}.{}: {!r}>".format(self.__class__.__name__, self._name_, self._value_) temp_enum_dict["__repr__"] = __repr__ @@ -698,7 +698,7 @@ del __repr__ def __str__(self): - return "%s.%s" % (self.__class__.__name__, self._name_) + return "{}.{}".format(self.__class__.__name__, self._name_) temp_enum_dict["__str__"] = __str__ @@ -907,9 +907,9 @@ def unique(enumeration): duplicates.append((name, member.name)) if duplicates: duplicate_names = ", ".join( - ["%s -> %s" % (alias, name) for (alias, name) in duplicates] + ["{} -> {}".format(alias, name) for (alias, name) in duplicates] ) raise ValueError( - "duplicate names found in %r: %s" % (enumeration, duplicate_names) + "duplicate names found in {!r}: {}".format(enumeration, duplicate_names) ) return enumeration diff --git a/graphene/pyutils/signature.py b/graphene/pyutils/signature.py index 43633f56..c66c2563 100644 --- a/graphene/pyutils/signature.py +++ b/graphene/pyutils/signature.py @@ -186,7 +186,6 @@ class _empty(object): class _ParameterKind(int): - def __new__(self, *args, **kwargs): obj = int.__new__(self, *args) obj._name = kwargs["name"] diff --git a/graphene/relay/connection.py b/graphene/relay/connection.py index 421ab502..f23849f2 100644 --- a/graphene/relay/connection.py +++ b/graphene/relay/connection.py @@ -40,7 +40,6 @@ class ConnectionOptions(ObjectTypeOptions): class Connection(ObjectType): - class Meta: abstract = True @@ -88,7 +87,6 @@ class Connection(ObjectType): class IterableConnectionField(Field): - def __init__(self, type, *args, **kwargs): kwargs.setdefault("before", String()) kwargs.setdefault("after", String()) diff --git a/graphene/relay/mutation.py b/graphene/relay/mutation.py index cce49d11..1b8b855e 100644 --- a/graphene/relay/mutation.py +++ b/graphene/relay/mutation.py @@ -8,7 +8,6 @@ from ..types.mutation import Mutation class ClientIDMutation(Mutation): - class Meta: abstract = True @@ -58,7 +57,6 @@ class ClientIDMutation(Mutation): @classmethod def mutate(cls, root, info, input): - def on_resolve(payload): try: payload.client_mutation_id = input.get("client_mutation_id") diff --git a/graphene/relay/node.py b/graphene/relay/node.py index ab8778bf..d9c4c0f6 100644 --- a/graphene/relay/node.py +++ b/graphene/relay/node.py @@ -27,7 +27,6 @@ def is_node(objecttype): class GlobalID(Field): - def __init__(self, node=None, parent_type=None, required=True, *args, **kwargs): super(GlobalID, self).__init__(ID, required=required, *args, **kwargs) self.node = node or Node @@ -49,7 +48,6 @@ class GlobalID(Field): class NodeField(Field): - def __init__(self, node, type=False, deprecation_reason=None, name=None, **kwargs): assert issubclass(node, Node), "NodeField can only operate in Nodes" self.node_type = node @@ -68,7 +66,6 @@ class NodeField(Field): class AbstractNode(Interface): - class Meta: abstract = True diff --git a/graphene/relay/tests/test_connection.py b/graphene/relay/tests/test_connection.py index f3dad969..061d6ec9 100644 --- a/graphene/relay/tests/test_connection.py +++ b/graphene/relay/tests/test_connection.py @@ -6,7 +6,6 @@ from ..node import Node class MyObject(ObjectType): - class Meta: interfaces = [Node] @@ -14,7 +13,6 @@ class MyObject(ObjectType): def test_connection(): - class MyObjectConnection(Connection): extra = String() @@ -41,12 +39,10 @@ def test_connection(): def test_connection_inherit_abstracttype(): - class BaseConnection(object): extra = String() class MyObjectConnection(BaseConnection, Connection): - class Meta: node = MyObject @@ -62,7 +58,6 @@ def test_connection_name(): extra = String() class MyObjectConnection(BaseConnection, Connection): - class Meta: node = MyObject name = custom_name @@ -71,9 +66,7 @@ def test_connection_name(): def test_edge(): - class MyObjectConnection(Connection): - class Meta: node = MyObject @@ -93,12 +86,10 @@ def test_edge(): def test_edge_with_bases(): - class BaseEdge(object): extra = String() class MyObjectConnection(Connection): - class Meta: node = MyObject @@ -129,9 +120,7 @@ def test_pageinfo(): def test_connectionfield(): - class MyObjectConnection(Connection): - class Meta: node = MyObject @@ -155,9 +144,7 @@ def test_connectionfield_node_deprecated(): def test_connectionfield_custom_args(): - class MyObjectConnection(Connection): - class Meta: node = MyObject @@ -174,9 +161,7 @@ def test_connectionfield_custom_args(): def test_connectionfield_required(): - class MyObjectConnection(Connection): - class Meta: node = MyObject diff --git a/graphene/relay/tests/test_connection_query.py b/graphene/relay/tests/test_connection_query.py index 12baa2d3..be6ee8c7 100644 --- a/graphene/relay/tests/test_connection_query.py +++ b/graphene/relay/tests/test_connection_query.py @@ -11,7 +11,6 @@ letter_chars = ["A", "B", "C", "D", "E"] class Letter(ObjectType): - class Meta: interfaces = (Node,) @@ -19,7 +18,6 @@ class Letter(ObjectType): class LetterConnection(Connection): - class Meta: node = Letter diff --git a/graphene/relay/tests/test_global_id.py b/graphene/relay/tests/test_global_id.py index 74fd6458..6d328f23 100644 --- a/graphene/relay/tests/test_global_id.py +++ b/graphene/relay/tests/test_global_id.py @@ -6,13 +6,11 @@ from ..node import GlobalID, Node class CustomNode(Node): - class Meta: name = "Node" class User(ObjectType): - class Meta: interfaces = [CustomNode] @@ -20,7 +18,6 @@ class User(ObjectType): class Info(object): - def __init__(self, parent_type): self.parent_type = GrapheneObjectType( graphene_type=parent_type, diff --git a/graphene/relay/tests/test_mutation.py b/graphene/relay/tests/test_mutation.py index ba51f4a2..b58a3ddf 100644 --- a/graphene/relay/tests/test_mutation.py +++ b/graphene/relay/tests/test_mutation.py @@ -27,7 +27,6 @@ class MyNode(ObjectType): class SaySomething(ClientIDMutation): - class Input: what = String() @@ -46,7 +45,6 @@ class FixedSaySomething(object): class SaySomethingFixed(ClientIDMutation): - class Input: what = String() @@ -58,7 +56,6 @@ class SaySomethingFixed(ClientIDMutation): class SaySomethingPromise(ClientIDMutation): - class Input: what = String() @@ -76,7 +73,6 @@ class MyEdge(ObjectType): class OtherMutation(ClientIDMutation): - class Input(SharedFields): additional_field = String() diff --git a/graphene/relay/tests/test_node.py b/graphene/relay/tests/test_node.py index 26fd73be..fbce1d54 100644 --- a/graphene/relay/tests/test_node.py +++ b/graphene/relay/tests/test_node.py @@ -16,7 +16,6 @@ class SharedNodeFields(object): class MyNode(ObjectType): - class Meta: interfaces = (Node,) diff --git a/graphene/relay/tests/test_node_custom.py b/graphene/relay/tests/test_node_custom.py index 59ecd23f..07e50a1b 100644 --- a/graphene/relay/tests/test_node_custom.py +++ b/graphene/relay/tests/test_node_custom.py @@ -6,7 +6,6 @@ from ..node import Node class CustomNode(Node): - class Meta: name = "Node" @@ -28,7 +27,6 @@ class BasePhoto(Interface): class User(ObjectType): - class Meta: interfaces = [CustomNode] @@ -36,7 +34,6 @@ class User(ObjectType): class Photo(ObjectType): - class Meta: interfaces = [CustomNode, BasePhoto] diff --git a/graphene/test/__init__.py b/graphene/test/__init__.py index ce10ac09..dab3b51b 100644 --- a/graphene/test/__init__.py +++ b/graphene/test/__init__.py @@ -27,7 +27,6 @@ def format_execution_result(execution_result, format_error): class Client(object): - def __init__(self, schema, format_error=None, **execute_options): assert isinstance(schema, Schema) self.schema = schema diff --git a/graphene/tests/issues/test_313.py b/graphene/tests/issues/test_313.py index ab607325..34dfef1a 100644 --- a/graphene/tests/issues/test_313.py +++ b/graphene/tests/issues/test_313.py @@ -16,13 +16,11 @@ class Error(graphene.ObjectType): class CreatePostResult(graphene.Union): - class Meta: types = [Success, Error] class CreatePost(graphene.Mutation): - class Input: text = graphene.String(required=True) diff --git a/graphene/tests/issues/test_356.py b/graphene/tests/issues/test_356.py index e7f4882b..4571aad8 100644 --- a/graphene/tests/issues/test_356.py +++ b/graphene/tests/issues/test_356.py @@ -15,13 +15,11 @@ class SomeTypeTwo(graphene.ObjectType): class MyUnion(graphene.Union): - class Meta: types = (SomeTypeOne, SomeTypeTwo) def test_issue(): - class Query(graphene.ObjectType): things = relay.ConnectionField(MyUnion) diff --git a/graphene/tests/issues/test_425.py b/graphene/tests/issues/test_425.py index 4f367380..50c18758 100644 --- a/graphene/tests/issues/test_425.py +++ b/graphene/tests/issues/test_425.py @@ -12,7 +12,6 @@ class SpecialOptions(ObjectTypeOptions): class SpecialObjectType(ObjectType): - @classmethod def __init_subclass_with_meta__(cls, other_attr="default", **options): _meta = SpecialOptions(cls) @@ -23,9 +22,7 @@ class SpecialObjectType(ObjectType): def test_special_objecttype_could_be_subclassed(): - class MyType(SpecialObjectType): - class Meta: other_attr = "yeah!" @@ -33,7 +30,6 @@ def test_special_objecttype_could_be_subclassed(): def test_special_objecttype_could_be_subclassed_default(): - class MyType(SpecialObjectType): pass @@ -41,7 +37,6 @@ def test_special_objecttype_could_be_subclassed_default(): def test_special_objecttype_inherit_meta_options(): - class MyType(SpecialObjectType): pass @@ -56,7 +51,6 @@ class SpecialInputObjectTypeOptions(ObjectTypeOptions): class SpecialInputObjectType(InputObjectType): - @classmethod def __init_subclass_with_meta__(cls, other_attr="default", **options): _meta = SpecialInputObjectTypeOptions(cls) @@ -67,9 +61,7 @@ class SpecialInputObjectType(InputObjectType): def test_special_inputobjecttype_could_be_subclassed(): - class MyInputObjectType(SpecialInputObjectType): - class Meta: other_attr = "yeah!" @@ -77,7 +69,6 @@ def test_special_inputobjecttype_could_be_subclassed(): def test_special_inputobjecttype_could_be_subclassed_default(): - class MyInputObjectType(SpecialInputObjectType): pass @@ -85,7 +76,6 @@ def test_special_inputobjecttype_could_be_subclassed_default(): def test_special_inputobjecttype_inherit_meta_options(): - class MyInputObjectType(SpecialInputObjectType): pass @@ -98,7 +88,6 @@ class SpecialEnumOptions(EnumOptions): class SpecialEnum(Enum): - @classmethod def __init_subclass_with_meta__(cls, other_attr="default", **options): _meta = SpecialEnumOptions(cls) @@ -107,9 +96,7 @@ class SpecialEnum(Enum): def test_special_enum_could_be_subclassed(): - class MyEnum(SpecialEnum): - class Meta: other_attr = "yeah!" @@ -117,7 +104,6 @@ def test_special_enum_could_be_subclassed(): def test_special_enum_could_be_subclassed_default(): - class MyEnum(SpecialEnum): pass @@ -125,7 +111,6 @@ def test_special_enum_could_be_subclassed_default(): def test_special_enum_inherit_meta_options(): - class MyEnum(SpecialEnum): pass diff --git a/graphene/tests/issues/test_720.py b/graphene/tests/issues/test_720.py index 8ac611ee..ea961b25 100644 --- a/graphene/tests/issues/test_720.py +++ b/graphene/tests/issues/test_720.py @@ -7,7 +7,6 @@ import graphene class MyInputClass(graphene.InputObjectType): - @classmethod def __init_subclass_with_meta__( cls, container=None, _meta=None, fields=None, **options @@ -21,7 +20,6 @@ class MyInputClass(graphene.InputObjectType): class MyInput(MyInputClass): - class Meta: fields = dict(x=graphene.Field(graphene.Int)) diff --git a/graphene/types/abstracttype.py b/graphene/types/abstracttype.py index 9d84d819..4eeb7f9c 100644 --- a/graphene/types/abstracttype.py +++ b/graphene/types/abstracttype.py @@ -3,7 +3,6 @@ from ..utils.subclass_with_meta import SubclassWithMeta class AbstractType(SubclassWithMeta): - def __init_subclass__(cls, *args, **kwargs): warn_deprecation( "Abstract type is deprecated, please use normal object inheritance instead.\n" diff --git a/graphene/types/argument.py b/graphene/types/argument.py index 20ea84b7..9c75bcee 100644 --- a/graphene/types/argument.py +++ b/graphene/types/argument.py @@ -8,7 +8,6 @@ from .utils import get_type class Argument(MountedType): - def __init__( self, type, diff --git a/graphene/types/base.py b/graphene/types/base.py index 3c37b8dd..aa97ed22 100644 --- a/graphene/types/base.py +++ b/graphene/types/base.py @@ -25,7 +25,6 @@ class BaseOptions(object): class BaseType(SubclassWithMeta): - @classmethod def create_type(cls, class_name, **options): return type(class_name, (cls,), {"Meta": options}) diff --git a/graphene/types/context.py b/graphene/types/context.py index dba51958..bac2073c 100644 --- a/graphene/types/context.py +++ b/graphene/types/context.py @@ -1,5 +1,4 @@ class Context(object): - def __init__(self, **params): for key, value in params.items(): setattr(self, key, value) diff --git a/graphene/types/enum.py b/graphene/types/enum.py index 96a322ad..6e6bab8f 100644 --- a/graphene/types/enum.py +++ b/graphene/types/enum.py @@ -24,7 +24,6 @@ class EnumOptions(BaseOptions): class EnumMeta(SubclassWithMeta_Meta): - def __new__(cls, name, bases, classdict, **options): enum_members = OrderedDict(classdict, __eq__=eq_enum) # We remove the Meta attribute from the class to not collide @@ -63,7 +62,6 @@ class EnumMeta(SubclassWithMeta_Meta): class Enum(six.with_metaclass(EnumMeta, UnmountedType, BaseType)): - @classmethod def __init_subclass_with_meta__(cls, enum=None, _meta=None, **options): if not _meta: diff --git a/graphene/types/field.py b/graphene/types/field.py index 5db5530e..a1428632 100644 --- a/graphene/types/field.py +++ b/graphene/types/field.py @@ -19,7 +19,6 @@ def source_resolver(source, root, info, **args): class Field(MountedType): - def __init__( self, type, diff --git a/graphene/types/inputfield.py b/graphene/types/inputfield.py index df6285b5..cdfea114 100644 --- a/graphene/types/inputfield.py +++ b/graphene/types/inputfield.py @@ -4,7 +4,6 @@ from .utils import get_type class InputField(MountedType): - def __init__( self, type, diff --git a/graphene/types/inputobjecttype.py b/graphene/types/inputobjecttype.py index dc6e0048..8116a827 100644 --- a/graphene/types/inputobjecttype.py +++ b/graphene/types/inputobjecttype.py @@ -17,7 +17,6 @@ class InputObjectTypeOptions(BaseOptions): class InputObjectTypeContainer(dict, BaseType): - class Meta: abstract = True diff --git a/graphene/types/mountedtype.py b/graphene/types/mountedtype.py index 47c828b9..6d0c8cf8 100644 --- a/graphene/types/mountedtype.py +++ b/graphene/types/mountedtype.py @@ -3,7 +3,6 @@ from .unmountedtype import UnmountedType class MountedType(OrderedType): - @classmethod def mounted(cls, unmounted): # noqa: N802 """ diff --git a/graphene/types/tests/test_abstracttype.py b/graphene/types/tests/test_abstracttype.py index 6fee3b11..41470383 100644 --- a/graphene/types/tests/test_abstracttype.py +++ b/graphene/types/tests/test_abstracttype.py @@ -10,7 +10,6 @@ class MyType(ObjectType): class MyScalar(UnmountedType): - def get_type(self): return MyType @@ -25,7 +24,6 @@ def test_abstract_objecttype_warn_deprecation(mocker): def test_generate_objecttype_inherit_abstracttype(): - class MyAbstractType(AbstractType): field1 = MyScalar() diff --git a/graphene/types/tests/test_base.py b/graphene/types/tests/test_base.py index d42d54fb..2f70903c 100644 --- a/graphene/types/tests/test_base.py +++ b/graphene/types/tests/test_base.py @@ -6,7 +6,6 @@ class CustomOptions(BaseOptions): class CustomType(BaseType): - @classmethod def __init_subclass_with_meta__(cls, **options): _meta = CustomOptions(cls) @@ -14,7 +13,6 @@ class CustomType(BaseType): def test_basetype(): - class MyBaseType(CustomType): pass @@ -24,7 +22,6 @@ def test_basetype(): def test_basetype_nones(): - class MyBaseType(CustomType): """Documentation""" @@ -38,7 +35,6 @@ def test_basetype_nones(): def test_basetype_custom(): - class MyBaseType(CustomType): """Documentation""" diff --git a/graphene/types/tests/test_definition.py b/graphene/types/tests/test_definition.py index 2cff3002..347de9c9 100644 --- a/graphene/types/tests/test_definition.py +++ b/graphene/types/tests/test_definition.py @@ -56,7 +56,6 @@ class MyInterface(Interface): class MyUnion(Union): - class Meta: types = (Article,) @@ -116,7 +115,6 @@ def test_defines_a_subscription_schema(): def test_includes_nested_input_objects_in_the_map(): - class NestedInputObject(InputObjectType): value = String() @@ -135,12 +133,10 @@ def test_includes_nested_input_objects_in_the_map(): def test_includes_interfaces_thunk_subtypes_in_the_type_map(): - class SomeInterface(Interface): f = Int() class SomeSubtype(ObjectType): - class Meta: interfaces = (SomeInterface,) @@ -153,7 +149,6 @@ def test_includes_interfaces_thunk_subtypes_in_the_type_map(): def test_includes_types_in_union(): - class SomeType(ObjectType): a = String() @@ -161,7 +156,6 @@ def test_includes_types_in_union(): b = String() class MyUnion(Union): - class Meta: types = (SomeType, OtherType) @@ -175,7 +169,6 @@ def test_includes_types_in_union(): def test_maps_enum(): - class SomeType(ObjectType): a = String() @@ -183,7 +176,6 @@ def test_maps_enum(): b = String() class MyUnion(Union): - class Meta: types = (SomeType, OtherType) @@ -197,12 +189,10 @@ def test_maps_enum(): def test_includes_interfaces_subtypes_in_the_type_map(): - class SomeInterface(Interface): f = Int() class SomeSubtype(ObjectType): - class Meta: interfaces = (SomeInterface,) @@ -293,7 +283,6 @@ def test_stringifies_simple_types(): def test_does_not_mutate_passed_field_definitions(): - class CommonFields(object): field1 = String() field2 = String(id=String()) diff --git a/graphene/types/tests/test_dynamic.py b/graphene/types/tests/test_dynamic.py index f2c4c627..3b5f7a3b 100644 --- a/graphene/types/tests/test_dynamic.py +++ b/graphene/types/tests/test_dynamic.py @@ -30,7 +30,6 @@ def test_list_non_null(): def test_partial(): - def __type(_type): return _type diff --git a/graphene/types/tests/test_enum.py b/graphene/types/tests/test_enum.py index 081ccc62..6086f54c 100644 --- a/graphene/types/tests/test_enum.py +++ b/graphene/types/tests/test_enum.py @@ -8,9 +8,9 @@ from ..schema import ObjectType, Schema def test_enum_construction(): - class RGB(Enum): """Description""" + RED = 1 GREEN = 2 BLUE = 3 @@ -32,9 +32,7 @@ def test_enum_construction(): def test_enum_construction_meta(): - class RGB(Enum): - class Meta: name = "RGBEnum" description = "Description" @@ -65,7 +63,6 @@ def test_enum_from_builtin_enum(): def test_enum_from_builtin_enum_accepts_lambda_description(): - def custom_description(value): if not value: return "StarWars Episodes" @@ -125,6 +122,7 @@ def test_enum_from_python3_enum_uses_enum_doc(): class Color(PyEnum): """This is the description""" + RED = 1 GREEN = 2 BLUE = 3 @@ -139,7 +137,6 @@ def test_enum_from_python3_enum_uses_enum_doc(): def test_enum_value_from_class(): - class RGB(Enum): RED = 1 GREEN = 2 @@ -151,7 +148,6 @@ def test_enum_value_from_class(): def test_enum_value_as_unmounted_field(): - class RGB(Enum): RED = 1 GREEN = 2 @@ -164,7 +160,6 @@ def test_enum_value_as_unmounted_field(): def test_enum_value_as_unmounted_inputfield(): - class RGB(Enum): RED = 1 GREEN = 2 @@ -177,7 +172,6 @@ def test_enum_value_as_unmounted_inputfield(): def test_enum_value_as_unmounted_argument(): - class RGB(Enum): RED = 1 GREEN = 2 @@ -190,7 +184,6 @@ def test_enum_value_as_unmounted_argument(): def test_enum_can_be_compared(): - class RGB(Enum): RED = 1 GREEN = 2 @@ -202,7 +195,6 @@ def test_enum_can_be_compared(): def test_enum_can_be_initialzied(): - class RGB(Enum): RED = 1 GREEN = 2 @@ -214,7 +206,6 @@ def test_enum_can_be_initialzied(): def test_enum_can_retrieve_members(): - class RGB(Enum): RED = 1 GREEN = 2 @@ -226,7 +217,6 @@ def test_enum_can_retrieve_members(): def test_enum_to_enum_comparison_should_differ(): - class RGB1(Enum): RED = 1 GREEN = 2 @@ -243,9 +233,7 @@ def test_enum_to_enum_comparison_should_differ(): def test_enum_skip_meta_from_members(): - class RGB1(Enum): - class Meta: name = "RGB" diff --git a/graphene/types/tests/test_inputobjecttype.py b/graphene/types/tests/test_inputobjecttype.py index 0100cf42..d565ff40 100644 --- a/graphene/types/tests/test_inputobjecttype.py +++ b/graphene/types/tests/test_inputobjecttype.py @@ -14,13 +14,11 @@ class MyType(object): class MyScalar(UnmountedType): - def get_type(self): return MyType def test_generate_inputobjecttype(): - class MyInputObjectType(InputObjectType): """Documentation""" @@ -30,9 +28,7 @@ def test_generate_inputobjecttype(): def test_generate_inputobjecttype_with_meta(): - class MyInputObjectType(InputObjectType): - class Meta: name = "MyOtherInputObjectType" description = "Documentation" @@ -42,7 +38,6 @@ def test_generate_inputobjecttype_with_meta(): def test_generate_inputobjecttype_with_fields(): - class MyInputObjectType(InputObjectType): field = Field(MyType) @@ -50,7 +45,6 @@ def test_generate_inputobjecttype_with_fields(): def test_ordered_fields_in_inputobjecttype(): - class MyInputObjectType(InputObjectType): b = InputField(MyType) a = InputField(MyType) @@ -61,7 +55,6 @@ def test_ordered_fields_in_inputobjecttype(): def test_generate_inputobjecttype_unmountedtype(): - class MyInputObjectType(InputObjectType): field = MyScalar(MyType) @@ -70,7 +63,6 @@ def test_generate_inputobjecttype_unmountedtype(): def test_generate_inputobjecttype_as_argument(): - class MyInputObjectType(InputObjectType): field = MyScalar() @@ -87,7 +79,6 @@ def test_generate_inputobjecttype_as_argument(): def test_generate_inputobjecttype_inherit_abstracttype(): - class MyAbstractType(object): field1 = MyScalar(MyType) @@ -102,7 +93,6 @@ def test_generate_inputobjecttype_inherit_abstracttype(): def test_generate_inputobjecttype_inherit_abstracttype_reversed(): - class MyAbstractType(object): field1 = MyScalar(MyType) @@ -117,7 +107,6 @@ def test_generate_inputobjecttype_inherit_abstracttype_reversed(): def test_inputobjecttype_of_input(): - class Child(InputObjectType): first_name = String() last_name = String() diff --git a/graphene/types/tests/test_interface.py b/graphene/types/tests/test_interface.py index 4657b437..b524296b 100644 --- a/graphene/types/tests/test_interface.py +++ b/graphene/types/tests/test_interface.py @@ -8,13 +8,11 @@ class MyType(object): class MyScalar(UnmountedType): - def get_type(self): return MyType def test_generate_interface(): - class MyInterface(Interface): """Documentation""" @@ -24,9 +22,7 @@ def test_generate_interface(): def test_generate_interface_with_meta(): - class MyInterface(Interface): - class Meta: name = "MyOtherInterface" description = "Documentation" @@ -36,7 +32,6 @@ def test_generate_interface_with_meta(): def test_generate_interface_with_fields(): - class MyInterface(Interface): field = Field(MyType) @@ -44,7 +39,6 @@ def test_generate_interface_with_fields(): def test_ordered_fields_in_interface(): - class MyInterface(Interface): b = Field(MyType) a = Field(MyType) @@ -55,7 +49,6 @@ def test_ordered_fields_in_interface(): def test_generate_interface_unmountedtype(): - class MyInterface(Interface): field = MyScalar() @@ -64,7 +57,6 @@ def test_generate_interface_unmountedtype(): def test_generate_interface_inherit_abstracttype(): - class MyAbstractType(object): field1 = MyScalar() @@ -76,7 +68,6 @@ def test_generate_interface_inherit_abstracttype(): def test_generate_interface_inherit_interface(): - class MyBaseInterface(Interface): field1 = MyScalar() @@ -89,7 +80,6 @@ def test_generate_interface_inherit_interface(): def test_generate_interface_inherit_abstracttype_reversed(): - class MyAbstractType(object): field1 = MyScalar() diff --git a/graphene/types/tests/test_mountedtype.py b/graphene/types/tests/test_mountedtype.py index c510aee4..787bee56 100644 --- a/graphene/types/tests/test_mountedtype.py +++ b/graphene/types/tests/test_mountedtype.py @@ -4,7 +4,6 @@ from ..scalars import String class CustomField(Field): - def __init__(self, *args, **kwargs): self.metadata = kwargs.pop("metadata", None) super(CustomField, self).__init__(*args, **kwargs) diff --git a/graphene/types/tests/test_mutation.py b/graphene/types/tests/test_mutation.py index 6268192a..3ecefe2f 100644 --- a/graphene/types/tests/test_mutation.py +++ b/graphene/types/tests/test_mutation.py @@ -10,7 +10,6 @@ from ..structures import NonNull def test_generate_mutation_no_args(): - class MyMutation(Mutation): """Documentation""" @@ -25,9 +24,7 @@ def test_generate_mutation_no_args(): def test_generate_mutation_with_meta(): - class MyMutation(Mutation): - class Meta: name = "MyOtherMutation" description = "Documentation" @@ -51,12 +48,10 @@ def test_mutation_raises_exception_if_no_mutate(): def test_mutation_custom_output_type(): - class User(ObjectType): name = String() class CreateUser(Mutation): - class Arguments: name = String() @@ -74,9 +69,7 @@ def test_mutation_custom_output_type(): def test_mutation_execution(): - class CreateUser(Mutation): - class Arguments: name = String() dynamic = Dynamic(lambda: String()) @@ -109,7 +102,6 @@ def test_mutation_execution(): def test_mutation_no_fields_output(): - class CreateUser(Mutation): name = String() @@ -136,9 +128,7 @@ def test_mutation_no_fields_output(): def test_mutation_allow_to_have_custom_args(): - class CreateUser(Mutation): - class Arguments: name = String() diff --git a/graphene/types/tests/test_objecttype.py b/graphene/types/tests/test_objecttype.py index 4c6fabd4..2acb578f 100644 --- a/graphene/types/tests/test_objecttype.py +++ b/graphene/types/tests/test_objecttype.py @@ -23,7 +23,6 @@ class MyInterface(Interface): class ContainerWithInterface(ObjectType): - class Meta: interfaces = (MyInterface,) @@ -32,13 +31,11 @@ class ContainerWithInterface(ObjectType): class MyScalar(UnmountedType): - def get_type(self): return MyType def test_generate_objecttype(): - class MyObjectType(ObjectType): """Documentation""" @@ -53,9 +50,7 @@ def test_generate_objecttype(): def test_generate_objecttype_with_meta(): - class MyObjectType(ObjectType): - class Meta: name = "MyOtherObjectType" description = "Documentation" @@ -67,7 +62,6 @@ def test_generate_objecttype_with_meta(): def test_generate_lazy_objecttype(): - class MyObjectType(ObjectType): example = Field(lambda: InnerObjectType, required=True) @@ -81,7 +75,6 @@ def test_generate_lazy_objecttype(): def test_generate_objecttype_with_fields(): - class MyObjectType(ObjectType): field = Field(MyType) @@ -89,7 +82,6 @@ def test_generate_objecttype_with_fields(): def test_generate_objecttype_with_private_attributes(): - class MyObjectType(ObjectType): _private_state = None @@ -104,7 +96,6 @@ def test_generate_objecttype_with_private_attributes(): def test_ordered_fields_in_objecttype(): - class MyObjectType(ObjectType): b = Field(MyType) a = Field(MyType) @@ -115,7 +106,6 @@ def test_ordered_fields_in_objecttype(): def test_generate_objecttype_inherit_abstracttype(): - class MyAbstractType(object): field1 = MyScalar() @@ -130,7 +120,6 @@ def test_generate_objecttype_inherit_abstracttype(): def test_generate_objecttype_inherit_abstracttype_reversed(): - class MyAbstractType(object): field1 = MyScalar() @@ -145,7 +134,6 @@ def test_generate_objecttype_inherit_abstracttype_reversed(): def test_generate_objecttype_unmountedtype(): - class MyObjectType(ObjectType): field = MyScalar() @@ -205,14 +193,12 @@ def test_objecttype_as_container_invalid_kwargs(): def test_objecttype_container_benchmark(benchmark): - @benchmark def create_objecttype(): Container(field1="field1", field2="field2") def test_generate_objecttype_description(): - class MyObjectType(ObjectType): """ Documentation @@ -224,9 +210,7 @@ def test_generate_objecttype_description(): def test_objecttype_with_possible_types(): - class MyObjectType(ObjectType): - class Meta: possible_types = (dict,) @@ -237,7 +221,6 @@ def test_objecttype_with_possible_types_and_is_type_of_should_raise(): with pytest.raises(AssertionError) as excinfo: class MyObjectType(ObjectType): - class Meta: possible_types = (dict,) @@ -252,7 +235,6 @@ def test_objecttype_with_possible_types_and_is_type_of_should_raise(): def test_objecttype_no_fields_output(): - class User(ObjectType): name = String() @@ -276,9 +258,7 @@ def test_objecttype_no_fields_output(): def test_abstract_objecttype_can_str(): - class MyObjectType(ObjectType): - class Meta: abstract = True diff --git a/graphene/types/tests/test_query.py b/graphene/types/tests/test_query.py index 0535e4e7..9f693a52 100644 --- a/graphene/types/tests/test_query.py +++ b/graphene/types/tests/test_query.py @@ -17,7 +17,6 @@ from ..union import Union def test_query(): - class Query(ObjectType): hello = String(resolver=lambda *_: "World") @@ -29,7 +28,6 @@ def test_query(): def test_query_source(): - class Root(object): _hello = "World" @@ -47,7 +45,6 @@ def test_query_source(): def test_query_union(): - class one_object(object): pass @@ -69,7 +66,6 @@ def test_query_union(): return isinstance(root, two_object) class MyUnion(Union): - class Meta: types = (One, Two) @@ -87,7 +83,6 @@ def test_query_union(): def test_query_interface(): - class one_object(object): pass @@ -98,7 +93,6 @@ def test_query_interface(): base = String() class One(ObjectType): - class Meta: interfaces = (MyInterface,) @@ -109,7 +103,6 @@ def test_query_interface(): return isinstance(root, one_object) class Two(ObjectType): - class Meta: interfaces = (MyInterface,) @@ -135,7 +128,6 @@ def test_query_interface(): def test_query_dynamic(): - class Query(ObjectType): hello = Dynamic(lambda: String(resolver=lambda *_: "World")) hellos = Dynamic(lambda: List(String, resolver=lambda *_: ["Worlds"])) @@ -153,7 +145,6 @@ def test_query_dynamic(): def test_query_default_value(): - class MyType(ObjectType): field = String() @@ -168,7 +159,6 @@ def test_query_default_value(): def test_query_wrong_default_value(): - class MyType(ObjectType): field = String() @@ -191,7 +181,6 @@ def test_query_wrong_default_value(): def test_query_default_value_ignored_by_resolver(): - class MyType(ObjectType): field = String() @@ -210,7 +199,6 @@ def test_query_default_value_ignored_by_resolver(): def test_query_resolve_function(): - class Query(ObjectType): hello = String() @@ -225,7 +213,6 @@ def test_query_resolve_function(): def test_query_arguments(): - class Query(ObjectType): test = String(a_str=String(), a_int=Int()) @@ -251,7 +238,6 @@ def test_query_arguments(): def test_query_input_field(): - class Input(InputObjectType): a_field = String() recursive_field = InputField(lambda: Input) @@ -282,7 +268,6 @@ def test_query_input_field(): def test_query_middlewares(): - class Query(ObjectType): hello = String() other = String() @@ -307,9 +292,7 @@ def test_query_middlewares(): def test_objecttype_on_instances(): - class Ship: - def __init__(self, name): self.name = name @@ -369,7 +352,6 @@ def test_big_list_query_compiled_query_benchmark(benchmark): def test_big_list_of_containers_query_benchmark(benchmark): - class Container(ObjectType): x = Int() @@ -390,7 +372,6 @@ def test_big_list_of_containers_query_benchmark(benchmark): def test_big_list_of_containers_multiple_fields_query_benchmark(benchmark): - class Container(ObjectType): x = Int() y = Int() @@ -420,7 +401,6 @@ def test_big_list_of_containers_multiple_fields_query_benchmark(benchmark): def test_big_list_of_containers_multiple_fields_custom_resolvers_query_benchmark( benchmark ): - class Container(ObjectType): x = Int() y = Int() diff --git a/graphene/types/tests/test_scalar.py b/graphene/types/tests/test_scalar.py index fb20980d..1ec986cd 100644 --- a/graphene/types/tests/test_scalar.py +++ b/graphene/types/tests/test_scalar.py @@ -3,7 +3,6 @@ from ..scalars import Scalar def test_scalar(): - class JSONScalar(Scalar): """Documentation""" diff --git a/graphene/types/tests/test_typemap.py b/graphene/types/tests/test_typemap.py index 0f60986b..f713726f 100644 --- a/graphene/types/tests/test_typemap.py +++ b/graphene/types/tests/test_typemap.py @@ -24,9 +24,9 @@ from ..typemap import TypeMap, resolve_type def test_enum(): - class MyEnum(Enum): """Description""" + foo = 1 bar = 2 @@ -58,9 +58,9 @@ def test_enum(): def test_objecttype(): - class MyObjectType(ObjectType): """Description""" + foo = String( bar=String(description="Argument description", default_value="x"), description="Field description", @@ -94,9 +94,9 @@ def test_objecttype(): def test_dynamic_objecttype(): - class MyObjectType(ObjectType): """Description""" + bar = Dynamic(lambda: Field(String)) own = Field(lambda: MyObjectType) @@ -112,9 +112,9 @@ def test_dynamic_objecttype(): def test_interface(): - class MyInterface(Interface): """Description""" + foo = String( bar=String(description="Argument description", default_value="x"), description="Field description", @@ -151,7 +151,6 @@ def test_interface(): def test_inputobject(): - class OtherObjectType(InputObjectType): thingy = NonNull(Int) @@ -161,6 +160,7 @@ def test_inputobject(): class MyInputObjectType(InputObjectType): """Description""" + foo_bar = String(description="Field description") bar = String(name="gizmo") baz = NonNull(MyInnerObjectType) @@ -210,9 +210,9 @@ def test_inputobject(): def test_objecttype_camelcase(): - class MyObjectType(ObjectType): """Description""" + foo_bar = String(bar_foo=String()) typemap = TypeMap([MyObjectType]) @@ -232,9 +232,9 @@ def test_objecttype_camelcase(): def test_objecttype_camelcase_disabled(): - class MyObjectType(ObjectType): """Description""" + foo_bar = String(bar_foo=String()) typemap = TypeMap([MyObjectType], auto_camelcase=False) @@ -254,7 +254,6 @@ def test_objecttype_camelcase_disabled(): def test_objecttype_with_possible_types(): - class MyObjectType(ObjectType): """Description""" @@ -271,7 +270,6 @@ def test_objecttype_with_possible_types(): def test_resolve_type_with_missing_type(): - class MyObjectType(ObjectType): foo_bar = String() diff --git a/graphene/types/tests/test_union.py b/graphene/types/tests/test_union.py index 8d46b00b..256c7d95 100644 --- a/graphene/types/tests/test_union.py +++ b/graphene/types/tests/test_union.py @@ -15,7 +15,6 @@ class MyObjectType2(ObjectType): def test_generate_union(): - class MyUnion(Union): """Documentation""" @@ -28,9 +27,7 @@ def test_generate_union(): def test_generate_union_with_meta(): - class MyUnion(Union): - class Meta: name = "MyOtherUnion" description = "Documentation" @@ -50,9 +47,7 @@ def test_generate_union_with_no_types(): def test_union_can_be_mounted(): - class MyUnion(Union): - class Meta: types = (MyObjectType1, MyObjectType2) diff --git a/graphene/types/typemap.py b/graphene/types/typemap.py index cb44175a..dce04445 100644 --- a/graphene/types/typemap.py +++ b/graphene/types/typemap.py @@ -74,7 +74,6 @@ def is_type_of_from_possible_types(possible_types, root, info): class TypeMap(GraphQLTypeMap): - def __init__(self, types, auto_camelcase=True, schema=None): self.auto_camelcase = auto_camelcase self.schema = schema diff --git a/graphene/utils/resolve_only_args.py b/graphene/utils/resolve_only_args.py index 009d17ac..5efff2ed 100644 --- a/graphene/utils/resolve_only_args.py +++ b/graphene/utils/resolve_only_args.py @@ -5,7 +5,6 @@ from .deprecated import deprecated @deprecated("This function is deprecated") def resolve_only_args(func): - @wraps(func) def wrapped_func(root, info, **args): return func(root, **args) diff --git a/graphene/utils/subclass_with_meta.py b/graphene/utils/subclass_with_meta.py index 9905feb2..01fc5375 100644 --- a/graphene/utils/subclass_with_meta.py +++ b/graphene/utils/subclass_with_meta.py @@ -20,6 +20,7 @@ class SubclassWithMeta_Meta(InitSubclassMeta): class SubclassWithMeta(six.with_metaclass(SubclassWithMeta_Meta)): """This class improves __init_subclass__ to receive automatically the options from meta""" + # We will only have the metaclass in Python 2 def __init_subclass__(cls, **meta_options): """This method just terminates the super() chain""" diff --git a/graphene/utils/tests/test_deduplicator.py b/graphene/utils/tests/test_deduplicator.py index d65f6fd0..604ae438 100644 --- a/graphene/utils/tests/test_deduplicator.py +++ b/graphene/utils/tests/test_deduplicator.py @@ -106,9 +106,7 @@ TEST_DATA = { def test_example_end_to_end(): - class Movie(graphene.ObjectType): - class Meta: interfaces = (relay.Node,) default_resolver = dict_resolver @@ -117,7 +115,6 @@ def test_example_end_to_end(): synopsis = graphene.String(required=True) class Event(graphene.ObjectType): - class Meta: interfaces = (relay.Node,) default_resolver = dict_resolver diff --git a/graphene/utils/tests/test_trim_docstring.py b/graphene/utils/tests/test_trim_docstring.py index ab84d829..704d3997 100644 --- a/graphene/utils/tests/test_trim_docstring.py +++ b/graphene/utils/tests/test_trim_docstring.py @@ -2,7 +2,6 @@ from ..trim_docstring import trim_docstring def test_trim_docstring(): - class WellDocumentedObject(object): """ This object is very well-documented. It has multiple lines in its