diff --git a/.travis.yml b/.travis.yml index a8375ee93..07ee59fc0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,19 +1,21 @@ language: python -sudo: false +sudo: required +dist: xenial python: - 2.7 - 3.4 - 3.5 - 3.6 +- 3.7 install: - | if [ "$TEST_TYPE" = build ]; then pip install -e .[test] - pip install psycopg2 # Required for Django postgres fields testing + pip install psycopg2==2.8.2 # Required for Django postgres fields testing pip install django==$DJANGO_VERSION python setup.py develop elif [ "$TEST_TYPE" = lint ]; then - pip install flake8 + pip install flake8==3.7.7 fi script: - | @@ -45,10 +47,16 @@ matrix: env: TEST_TYPE=build DJANGO_VERSION=2.1 - python: '3.6' env: TEST_TYPE=build DJANGO_VERSION=2.1 + - python: '3.6' + env: TEST_TYPE=build DJANGO_VERSION=2.2 + - python: '3.7' + env: TEST_TYPE=build DJANGO_VERSION=2.2 - python: '2.7' env: TEST_TYPE=lint - python: '3.6' env: TEST_TYPE=lint + - python: '3.7' + env: TEST_TYPE=lint deploy: provider: pypi user: syrusakbary diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4a650d6cc..f9428e978 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -31,6 +31,19 @@ After developing, the full test suite can be evaluated by running: make tests ``` +## Opening Pull Requests + +Please fork the project and open a pull request against the master branch. + +This will trigger a series of test and lint checks. + +We advise that you format and run lint locally before doing this to save time: + +```sh +make format +make lint +``` + ## Documentation The [documentation](http://docs.graphene-python.org/projects/django/en/latest/) is generated using the excellent [Sphinx](http://www.sphinx-doc.org/) and a custom theme. diff --git a/Makefile b/Makefile index 5c174acb2..061ad4e7f 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,11 @@ dev-setup: - pip install -e ".[test]" + pip install -e ".[dev]" tests: - py.test graphene_django --cov=graphene_django -vv \ No newline at end of file + py.test graphene_django --cov=graphene_django -vv + +format: + black graphene_django + +lint: + flake8 graphene_django diff --git a/README.md b/README.md index fffa1d3f8..d2fe4b6c4 100644 --- a/README.md +++ b/README.md @@ -96,4 +96,4 @@ To learn more check out the following [examples](examples/): ## Contributing -See [CONTRIBUTING.md](contributing.md) \ No newline at end of file +See [CONTRIBUTING.md](CONTRIBUTING.md) \ No newline at end of file diff --git a/graphene_django/compat.py b/graphene_django/compat.py index 4a51de800..59fab304e 100644 --- a/graphene_django/compat.py +++ b/graphene_django/compat.py @@ -5,7 +5,11 @@ class MissingType(object): try: # Postgres fields are only available in Django with psycopg2 installed # and we cannot have psycopg2 on PyPy - from django.contrib.postgres.fields import (ArrayField, HStoreField, - JSONField, RangeField) + from django.contrib.postgres.fields import ( + ArrayField, + HStoreField, + JSONField, + RangeField, + ) except ImportError: ArrayField, HStoreField, JSONField, RangeField = (MissingType,) * 4 diff --git a/graphene_django/debug/sql/types.py b/graphene_django/debug/sql/types.py index 850ced489..eeef4823f 100644 --- a/graphene_django/debug/sql/types.py +++ b/graphene_django/debug/sql/types.py @@ -3,9 +3,7 @@ class DjangoDebugSQL(ObjectType): class Meta: - description = ( - "Represents a single database query made to a Django managed DB." - ) + description = "Represents a single database query made to a Django managed DB." vendor = String( required=True, @@ -14,37 +12,26 @@ class Meta: ), ) alias = String( - required=True, - description="The Django database alias (e.g. 'default').", + required=True, description="The Django database alias (e.g. 'default')." ) sql = String(description="The actual SQL sent to this database.") duration = Float( - required=True, - description="Duration of this database query in seconds.", + required=True, description="Duration of this database query in seconds." ) raw_sql = String( - required=True, - description="The raw SQL of this query, without params.", + required=True, description="The raw SQL of this query, without params." ) params = String( - required=True, - description="JSON encoded database query parameters.", - ) - start_time = Float( - required=True, - description="Start time of this database query.", - ) - stop_time = Float( - required=True, - description="Stop time of this database query.", + required=True, description="JSON encoded database query parameters." ) + start_time = Float(required=True, description="Start time of this database query.") + stop_time = Float(required=True, description="Stop time of this database query.") is_slow = Boolean( required=True, description="Whether this database query took more than 10 seconds.", ) is_select = Boolean( - required=True, - description="Whether this database query was a SELECT.", + required=True, description="Whether this database query was a SELECT." ) # Postgres diff --git a/graphene_django/debug/types.py b/graphene_django/debug/types.py index cda572552..1cd816d4d 100644 --- a/graphene_django/debug/types.py +++ b/graphene_django/debug/types.py @@ -7,7 +7,4 @@ class DjangoDebug(ObjectType): class Meta: description = "Debugging information for the current query." - sql = List( - DjangoDebugSQL, - description="Executed SQL queries for this API query.", - ) + sql = List(DjangoDebugSQL, description="Executed SQL queries for this API query.") diff --git a/graphene_django/filter/filterset.py b/graphene_django/filter/filterset.py index 405908368..7676ea85b 100644 --- a/graphene_django/filter/filterset.py +++ b/graphene_django/filter/filterset.py @@ -45,8 +45,7 @@ class GrapheneFilterSetMixin(BaseFilterSet): FILTER_DEFAULTS = dict( itertools.chain( - FILTER_FOR_DBFIELD_DEFAULTS.items(), - GRAPHENE_FILTER_SET_OVERRIDES.items() + FILTER_FOR_DBFIELD_DEFAULTS.items(), GRAPHENE_FILTER_SET_OVERRIDES.items() ) ) @@ -59,7 +58,6 @@ class GrapheneFilterSetMixin(BaseFilterSet): from django.utils.text import capfirst class GrapheneFilterSetMixinPython2(GrapheneFilterSetMixin): - @classmethod def filter_for_reverse_field(cls, f, name): """Handles retrieving filters for reverse relationships diff --git a/graphene_django/forms/tests/test_mutation.py b/graphene_django/forms/tests/test_mutation.py index df0ffd5ee..543e89e62 100644 --- a/graphene_django/forms/tests/test_mutation.py +++ b/graphene_django/forms/tests/test_mutation.py @@ -13,7 +13,7 @@ class MyForm(forms.Form): class PetForm(forms.ModelForm): class Meta: model = Pet - fields = '__all__' + fields = "__all__" def test_needs_form_class(): @@ -66,7 +66,7 @@ def test_exclude_fields_input_meta_fields(self): class PetMutation(DjangoModelFormMutation): class Meta: form_class = PetForm - exclude_fields = ['id'] + exclude_fields = ["id"] self.assertEqual(PetMutation._meta.model, Pet) self.assertEqual(PetMutation._meta.return_field_name, "pet") @@ -102,7 +102,9 @@ class Meta: pet = Pet.objects.create(name="Axel", age=10) - result = PetMutation.mutate_and_get_payload(None, None, id=pet.pk, name="Mia", age=10) + result = PetMutation.mutate_and_get_payload( + None, None, id=pet.pk, name="Mia", age=10 + ) self.assertEqual(Pet.objects.count(), 1) pet.refresh_from_db() @@ -132,7 +134,6 @@ class Meta: # A pet was not created self.assertEqual(Pet.objects.count(), 0) - fields_w_error = [e.field for e in result.errors] self.assertEqual(len(result.errors), 2) self.assertIn("name", fields_w_error) diff --git a/graphene_django/management/commands/graphql_schema.py b/graphene_django/management/commands/graphql_schema.py index d7f83daae..9f8689e60 100644 --- a/graphene_django/management/commands/graphql_schema.py +++ b/graphene_django/management/commands/graphql_schema.py @@ -64,7 +64,7 @@ def handle(self, *args, **options): indent = options.get("indent") schema_dict = {"data": schema.introspect()} - if out == '-': + if out == "-": self.stdout.write(json.dumps(schema_dict, indent=indent, sort_keys=True)) else: self.save_file(out, schema_dict, indent) diff --git a/graphene_django/tests/base_test.py b/graphene_django/tests/base_test.py index 471dffe0b..84e1dc5ef 100644 --- a/graphene_django/tests/base_test.py +++ b/graphene_django/tests/base_test.py @@ -11,7 +11,7 @@ class GraphQLTestCase(TestCase): """ # URL to graphql endpoint - GRAPHQL_URL = '/graphql/' + GRAPHQL_URL = "/graphql/" # Here you need to set your graphql schema for the tests GRAPHQL_SCHEMA = None @@ -20,7 +20,9 @@ def setUpClass(cls): super(GraphQLTestCase, cls).setUpClass() if not cls.GRAPHQL_SCHEMA: - raise AttributeError('Variable GRAPHQL_SCHEMA not defined in GraphQLTestCase.') + raise AttributeError( + "Variable GRAPHQL_SCHEMA not defined in GraphQLTestCase." + ) cls._client = Client(cls.GRAPHQL_SCHEMA) @@ -37,14 +39,15 @@ def query(self, query, op_name=None, input_data=None): Returns: Response object from client """ - body = {'query': query} + body = {"query": query} if op_name: - body['operation_name'] = op_name + body["operation_name"] = op_name if input_data: - body['variables'] = {'input': input_data} + body["variables"] = {"input": input_data} - resp = self._client.post(self.GRAPHQL_URL, json.dumps(body), - content_type='application/json') + resp = self._client.post( + self.GRAPHQL_URL, json.dumps(body), content_type="application/json" + ) return resp def assertResponseNoErrors(self, resp): @@ -55,7 +58,7 @@ def assertResponseNoErrors(self, resp): """ content = json.loads(resp.content) self.assertEqual(resp.status_code, 200) - self.assertNotIn('errors', list(content.keys())) + self.assertNotIn("errors", list(content.keys())) def assertResponseHasErrors(self, resp): """ @@ -63,4 +66,4 @@ def assertResponseHasErrors(self, resp): :resp HttpResponse: Response """ content = json.loads(resp.content) - self.assertIn('errors', list(content.keys())) + self.assertIn("errors", list(content.keys())) diff --git a/graphene_django/tests/test_command.py b/graphene_django/tests/test_command.py index fa78aec73..dbabafa33 100644 --- a/graphene_django/tests/test_command.py +++ b/graphene_django/tests/test_command.py @@ -10,14 +10,18 @@ def test_generate_file_on_call_graphql_schema(savefile_mock, settings): assert "Successfully dumped GraphQL schema to schema.json" in out.getvalue() -@patch('json.dump') +@patch("json.dump") def test_files_are_canonical(dump_mock): open_mock = mock_open() - with patch('graphene_django.management.commands.graphql_schema.open', open_mock): - management.call_command('graphql_schema', schema='') + with patch("graphene_django.management.commands.graphql_schema.open", open_mock): + management.call_command("graphql_schema", schema="") open_mock.assert_called_once() dump_mock.assert_called_once() - assert dump_mock.call_args[1]["sort_keys"], "json.mock() should be used to sort the output" - assert dump_mock.call_args[1]["indent"] > 0, "output should be pretty-printed by default" + assert dump_mock.call_args[1][ + "sort_keys" + ], "json.mock() should be used to sort the output" + assert ( + dump_mock.call_args[1]["indent"] > 0 + ), "output should be pretty-printed by default" diff --git a/graphene_django/tests/test_converter.py b/graphene_django/tests/test_converter.py index eac585166..bb176b343 100644 --- a/graphene_django/tests/test_converter.py +++ b/graphene_django/tests/test_converter.py @@ -241,8 +241,7 @@ class A(DjangoObjectType): class Meta: model = Article - graphene_field = convert_django_field(Reporter.articles.rel, - A._meta.registry) + graphene_field = convert_django_field(Reporter.articles.rel, A._meta.registry) assert isinstance(graphene_field, graphene.Dynamic) dynamic_field = graphene_field.get_type() assert isinstance(dynamic_field, graphene.Field) @@ -255,8 +254,7 @@ class A(DjangoObjectType): class Meta: model = FilmDetails - graphene_field = convert_django_field(Film.details.related, - A._meta.registry) + graphene_field = convert_django_field(Film.details.related, A._meta.registry) assert isinstance(graphene_field, graphene.Dynamic) dynamic_field = graphene_field.get_type() assert isinstance(dynamic_field, graphene.Field) diff --git a/graphene_django/views.py b/graphene_django/views.py index 9a530de93..0b840f97f 100644 --- a/graphene_django/views.py +++ b/graphene_django/views.py @@ -126,8 +126,7 @@ def dispatch(self, request, *args, **kwargs): if show_graphiql: return self.render_graphiql( - request, - graphiql_version=self.graphiql_version, + request, graphiql_version=self.graphiql_version ) if self.batch: diff --git a/setup.py b/setup.py index 3431cd506..e622a718b 100644 --- a/setup.py +++ b/setup.py @@ -24,6 +24,12 @@ "pytest-django>=3.3.2", ] + rest_framework_require + +dev_requires = [ + "black==19.3b0", + "flake8==3.7.7", +] + tests_require + setup( name="graphene-django", version=version, @@ -58,7 +64,7 @@ setup_requires=["pytest-runner"], tests_require=tests_require, rest_framework_require=rest_framework_require, - extras_require={"test": tests_require, "rest_framework": rest_framework_require}, + extras_require={"test": tests_require, "rest_framework": rest_framework_require, "dev": dev_requires}, include_package_data=True, zip_safe=False, platforms="any",