Repository: graphql-python/graphene
Pull request #746 (2018-05-28 21:42:09)

Add flake8 pre-commit hook and manually edit files to pass flake8 validation
Add flake8 pre-commit hook and manually edit files to pass flake8 validation


Patch:
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 085f7fa..156d038 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/README.md b/README.md
index 2288f34..3d972fd 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/UPGRADE-v2.0.md b/UPGRADE-v2.0.md
index 5dc7615..32b28d8 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
diff --git a/docs/conf.py b/docs/conf.py
index ccb5305..b25a36d 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/graphene/relay/node.py b/graphene/relay/node.py
index 6596757..5c787ff 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:
diff --git a/graphene/types/inputobjecttype.py b/graphene/types/inputobjecttype.py
index dbfccc4..b84fc0f 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
diff --git a/graphene/utils/deprecated.py b/graphene/utils/deprecated.py
index f70b2e7..d00642f 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):
diff --git a/tox.ini b/tox.ini
index cf538bb..3c2860c 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


Test patch:
diff --git a/graphene/relay/tests/test_connection_query.py b/graphene/relay/tests/test_connection_query.py
index b8150e6..0f266a5 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/relay/tests/test_node.py b/graphene/relay/tests/test_node.py
index 10dc5d9..df44fcb 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}
 
 
diff --git a/graphene/tests/issues/test_313.py b/graphene/tests/issues/test_313.py
index 9df6c17..e524a85 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 8eeaed1..9d8fc77 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():
-    with pytest.raises(Exception) as exc_info:
-        class Query(graphene.ObjectType):
-            things = relay.ConnectionField(MyUnion)
+    class Query(graphene.ObjectType):
+        things = relay.ConnectionField(MyUnion)
 
-        schema = graphene.Schema(query=Query)
+    with pytest.raises(Exception) as exc_info:
+        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 cc77e73..525e0b7 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/tests/issues/test_720.py b/graphene/tests/issues/test_720.py
new file mode 100644
index 0000000..8cd99bd
--- /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/tests/test_abstracttype.py b/graphene/types/tests/test_abstracttype.py
index 73144be..6ad35b7 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 744c9e2..bc7b6e1 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 6399f69..cd555ad 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 80c1d3c..35e8c78 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 af9168c..d3cd2c3 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 d35d555..231abba 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 c413397..7bdde00 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 94af960..7d441bf 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 446fbbf..259df3c 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 0af0676..16fca03 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 11a6bbd..1dfd478 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)