mirror of
https://github.com/graphql-python/graphene-django.git
synced 2024-11-26 03:24:07 +03:00
Merge pull request #623 from graphql-python/black
Introduce Black formatting, additional tests
This commit is contained in:
commit
9a43f65b44
14
.travis.yml
14
.travis.yml
|
@ -1,19 +1,21 @@
|
||||||
language: python
|
language: python
|
||||||
sudo: false
|
sudo: required
|
||||||
|
dist: xenial
|
||||||
python:
|
python:
|
||||||
- 2.7
|
- 2.7
|
||||||
- 3.4
|
- 3.4
|
||||||
- 3.5
|
- 3.5
|
||||||
- 3.6
|
- 3.6
|
||||||
|
- 3.7
|
||||||
install:
|
install:
|
||||||
- |
|
- |
|
||||||
if [ "$TEST_TYPE" = build ]; then
|
if [ "$TEST_TYPE" = build ]; then
|
||||||
pip install -e .[test]
|
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
|
pip install django==$DJANGO_VERSION
|
||||||
python setup.py develop
|
python setup.py develop
|
||||||
elif [ "$TEST_TYPE" = lint ]; then
|
elif [ "$TEST_TYPE" = lint ]; then
|
||||||
pip install flake8
|
pip install flake8==3.7.7
|
||||||
fi
|
fi
|
||||||
script:
|
script:
|
||||||
- |
|
- |
|
||||||
|
@ -45,10 +47,16 @@ matrix:
|
||||||
env: TEST_TYPE=build DJANGO_VERSION=2.1
|
env: TEST_TYPE=build DJANGO_VERSION=2.1
|
||||||
- python: '3.6'
|
- python: '3.6'
|
||||||
env: TEST_TYPE=build DJANGO_VERSION=2.1
|
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'
|
- python: '2.7'
|
||||||
env: TEST_TYPE=lint
|
env: TEST_TYPE=lint
|
||||||
- python: '3.6'
|
- python: '3.6'
|
||||||
env: TEST_TYPE=lint
|
env: TEST_TYPE=lint
|
||||||
|
- python: '3.7'
|
||||||
|
env: TEST_TYPE=lint
|
||||||
deploy:
|
deploy:
|
||||||
provider: pypi
|
provider: pypi
|
||||||
user: syrusakbary
|
user: syrusakbary
|
||||||
|
|
|
@ -31,6 +31,19 @@ After developing, the full test suite can be evaluated by running:
|
||||||
make tests
|
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
|
## 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.
|
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.
|
||||||
|
|
10
Makefile
10
Makefile
|
@ -1,5 +1,11 @@
|
||||||
dev-setup:
|
dev-setup:
|
||||||
pip install -e ".[test]"
|
pip install -e ".[dev]"
|
||||||
|
|
||||||
tests:
|
tests:
|
||||||
py.test graphene_django --cov=graphene_django -vv
|
py.test graphene_django --cov=graphene_django -vv
|
||||||
|
|
||||||
|
format:
|
||||||
|
black graphene_django
|
||||||
|
|
||||||
|
lint:
|
||||||
|
flake8 graphene_django
|
||||||
|
|
|
@ -96,4 +96,4 @@ To learn more check out the following [examples](examples/):
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
See [CONTRIBUTING.md](contributing.md)
|
See [CONTRIBUTING.md](CONTRIBUTING.md)
|
|
@ -5,7 +5,11 @@ class MissingType(object):
|
||||||
try:
|
try:
|
||||||
# Postgres fields are only available in Django with psycopg2 installed
|
# Postgres fields are only available in Django with psycopg2 installed
|
||||||
# and we cannot have psycopg2 on PyPy
|
# and we cannot have psycopg2 on PyPy
|
||||||
from django.contrib.postgres.fields import (ArrayField, HStoreField,
|
from django.contrib.postgres.fields import (
|
||||||
JSONField, RangeField)
|
ArrayField,
|
||||||
|
HStoreField,
|
||||||
|
JSONField,
|
||||||
|
RangeField,
|
||||||
|
)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
ArrayField, HStoreField, JSONField, RangeField = (MissingType,) * 4
|
ArrayField, HStoreField, JSONField, RangeField = (MissingType,) * 4
|
||||||
|
|
|
@ -3,9 +3,7 @@ from graphene import Boolean, Float, ObjectType, String
|
||||||
|
|
||||||
class DjangoDebugSQL(ObjectType):
|
class DjangoDebugSQL(ObjectType):
|
||||||
class Meta:
|
class Meta:
|
||||||
description = (
|
description = "Represents a single database query made to a Django managed DB."
|
||||||
"Represents a single database query made to a Django managed DB."
|
|
||||||
)
|
|
||||||
|
|
||||||
vendor = String(
|
vendor = String(
|
||||||
required=True,
|
required=True,
|
||||||
|
@ -14,37 +12,26 @@ class DjangoDebugSQL(ObjectType):
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
alias = String(
|
alias = String(
|
||||||
required=True,
|
required=True, description="The Django database alias (e.g. 'default')."
|
||||||
description="The Django database alias (e.g. 'default').",
|
|
||||||
)
|
)
|
||||||
sql = String(description="The actual SQL sent to this database.")
|
sql = String(description="The actual SQL sent to this database.")
|
||||||
duration = Float(
|
duration = Float(
|
||||||
required=True,
|
required=True, description="Duration of this database query in seconds."
|
||||||
description="Duration of this database query in seconds.",
|
|
||||||
)
|
)
|
||||||
raw_sql = String(
|
raw_sql = String(
|
||||||
required=True,
|
required=True, description="The raw SQL of this query, without params."
|
||||||
description="The raw SQL of this query, without params.",
|
|
||||||
)
|
)
|
||||||
params = String(
|
params = String(
|
||||||
required=True,
|
required=True, description="JSON encoded database query parameters."
|
||||||
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.",
|
|
||||||
)
|
)
|
||||||
|
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(
|
is_slow = Boolean(
|
||||||
required=True,
|
required=True,
|
||||||
description="Whether this database query took more than 10 seconds.",
|
description="Whether this database query took more than 10 seconds.",
|
||||||
)
|
)
|
||||||
is_select = Boolean(
|
is_select = Boolean(
|
||||||
required=True,
|
required=True, description="Whether this database query was a SELECT."
|
||||||
description="Whether this database query was a SELECT.",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Postgres
|
# Postgres
|
||||||
|
|
|
@ -7,7 +7,4 @@ class DjangoDebug(ObjectType):
|
||||||
class Meta:
|
class Meta:
|
||||||
description = "Debugging information for the current query."
|
description = "Debugging information for the current query."
|
||||||
|
|
||||||
sql = List(
|
sql = List(DjangoDebugSQL, description="Executed SQL queries for this API query.")
|
||||||
DjangoDebugSQL,
|
|
||||||
description="Executed SQL queries for this API query.",
|
|
||||||
)
|
|
||||||
|
|
|
@ -45,8 +45,7 @@ class GrapheneFilterSetMixin(BaseFilterSet):
|
||||||
|
|
||||||
FILTER_DEFAULTS = dict(
|
FILTER_DEFAULTS = dict(
|
||||||
itertools.chain(
|
itertools.chain(
|
||||||
FILTER_FOR_DBFIELD_DEFAULTS.items(),
|
FILTER_FOR_DBFIELD_DEFAULTS.items(), GRAPHENE_FILTER_SET_OVERRIDES.items()
|
||||||
GRAPHENE_FILTER_SET_OVERRIDES.items()
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -59,7 +58,6 @@ if VERSION[0] < 2:
|
||||||
from django.utils.text import capfirst
|
from django.utils.text import capfirst
|
||||||
|
|
||||||
class GrapheneFilterSetMixinPython2(GrapheneFilterSetMixin):
|
class GrapheneFilterSetMixinPython2(GrapheneFilterSetMixin):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def filter_for_reverse_field(cls, f, name):
|
def filter_for_reverse_field(cls, f, name):
|
||||||
"""Handles retrieving filters for reverse relationships
|
"""Handles retrieving filters for reverse relationships
|
||||||
|
|
|
@ -13,7 +13,7 @@ class MyForm(forms.Form):
|
||||||
class PetForm(forms.ModelForm):
|
class PetForm(forms.ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Pet
|
model = Pet
|
||||||
fields = '__all__'
|
fields = "__all__"
|
||||||
|
|
||||||
|
|
||||||
def test_needs_form_class():
|
def test_needs_form_class():
|
||||||
|
@ -66,7 +66,7 @@ class ModelFormMutationTests(TestCase):
|
||||||
class PetMutation(DjangoModelFormMutation):
|
class PetMutation(DjangoModelFormMutation):
|
||||||
class Meta:
|
class Meta:
|
||||||
form_class = PetForm
|
form_class = PetForm
|
||||||
exclude_fields = ['id']
|
exclude_fields = ["id"]
|
||||||
|
|
||||||
self.assertEqual(PetMutation._meta.model, Pet)
|
self.assertEqual(PetMutation._meta.model, Pet)
|
||||||
self.assertEqual(PetMutation._meta.return_field_name, "pet")
|
self.assertEqual(PetMutation._meta.return_field_name, "pet")
|
||||||
|
@ -102,7 +102,9 @@ class ModelFormMutationTests(TestCase):
|
||||||
|
|
||||||
pet = Pet.objects.create(name="Axel", age=10)
|
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)
|
self.assertEqual(Pet.objects.count(), 1)
|
||||||
pet.refresh_from_db()
|
pet.refresh_from_db()
|
||||||
|
@ -132,7 +134,6 @@ class ModelFormMutationTests(TestCase):
|
||||||
# A pet was not created
|
# A pet was not created
|
||||||
self.assertEqual(Pet.objects.count(), 0)
|
self.assertEqual(Pet.objects.count(), 0)
|
||||||
|
|
||||||
|
|
||||||
fields_w_error = [e.field for e in result.errors]
|
fields_w_error = [e.field for e in result.errors]
|
||||||
self.assertEqual(len(result.errors), 2)
|
self.assertEqual(len(result.errors), 2)
|
||||||
self.assertIn("name", fields_w_error)
|
self.assertIn("name", fields_w_error)
|
||||||
|
|
|
@ -64,7 +64,7 @@ class Command(CommandArguments):
|
||||||
|
|
||||||
indent = options.get("indent")
|
indent = options.get("indent")
|
||||||
schema_dict = {"data": schema.introspect()}
|
schema_dict = {"data": schema.introspect()}
|
||||||
if out == '-':
|
if out == "-":
|
||||||
self.stdout.write(json.dumps(schema_dict, indent=indent, sort_keys=True))
|
self.stdout.write(json.dumps(schema_dict, indent=indent, sort_keys=True))
|
||||||
else:
|
else:
|
||||||
self.save_file(out, schema_dict, indent)
|
self.save_file(out, schema_dict, indent)
|
||||||
|
|
|
@ -11,7 +11,7 @@ class GraphQLTestCase(TestCase):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# URL to graphql endpoint
|
# URL to graphql endpoint
|
||||||
GRAPHQL_URL = '/graphql/'
|
GRAPHQL_URL = "/graphql/"
|
||||||
# Here you need to set your graphql schema for the tests
|
# Here you need to set your graphql schema for the tests
|
||||||
GRAPHQL_SCHEMA = None
|
GRAPHQL_SCHEMA = None
|
||||||
|
|
||||||
|
@ -20,7 +20,9 @@ class GraphQLTestCase(TestCase):
|
||||||
super(GraphQLTestCase, cls).setUpClass()
|
super(GraphQLTestCase, cls).setUpClass()
|
||||||
|
|
||||||
if not cls.GRAPHQL_SCHEMA:
|
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)
|
cls._client = Client(cls.GRAPHQL_SCHEMA)
|
||||||
|
|
||||||
|
@ -37,14 +39,15 @@ class GraphQLTestCase(TestCase):
|
||||||
Returns:
|
Returns:
|
||||||
Response object from client
|
Response object from client
|
||||||
"""
|
"""
|
||||||
body = {'query': query}
|
body = {"query": query}
|
||||||
if op_name:
|
if op_name:
|
||||||
body['operation_name'] = op_name
|
body["operation_name"] = op_name
|
||||||
if input_data:
|
if input_data:
|
||||||
body['variables'] = {'input': input_data}
|
body["variables"] = {"input": input_data}
|
||||||
|
|
||||||
resp = self._client.post(self.GRAPHQL_URL, json.dumps(body),
|
resp = self._client.post(
|
||||||
content_type='application/json')
|
self.GRAPHQL_URL, json.dumps(body), content_type="application/json"
|
||||||
|
)
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
def assertResponseNoErrors(self, resp):
|
def assertResponseNoErrors(self, resp):
|
||||||
|
@ -55,7 +58,7 @@ class GraphQLTestCase(TestCase):
|
||||||
"""
|
"""
|
||||||
content = json.loads(resp.content)
|
content = json.loads(resp.content)
|
||||||
self.assertEqual(resp.status_code, 200)
|
self.assertEqual(resp.status_code, 200)
|
||||||
self.assertNotIn('errors', list(content.keys()))
|
self.assertNotIn("errors", list(content.keys()))
|
||||||
|
|
||||||
def assertResponseHasErrors(self, resp):
|
def assertResponseHasErrors(self, resp):
|
||||||
"""
|
"""
|
||||||
|
@ -63,4 +66,4 @@ class GraphQLTestCase(TestCase):
|
||||||
:resp HttpResponse: Response
|
:resp HttpResponse: Response
|
||||||
"""
|
"""
|
||||||
content = json.loads(resp.content)
|
content = json.loads(resp.content)
|
||||||
self.assertIn('errors', list(content.keys()))
|
self.assertIn("errors", list(content.keys()))
|
||||||
|
|
|
@ -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()
|
assert "Successfully dumped GraphQL schema to schema.json" in out.getvalue()
|
||||||
|
|
||||||
|
|
||||||
@patch('json.dump')
|
@patch("json.dump")
|
||||||
def test_files_are_canonical(dump_mock):
|
def test_files_are_canonical(dump_mock):
|
||||||
open_mock = mock_open()
|
open_mock = mock_open()
|
||||||
with patch('graphene_django.management.commands.graphql_schema.open', open_mock):
|
with patch("graphene_django.management.commands.graphql_schema.open", open_mock):
|
||||||
management.call_command('graphql_schema', schema='')
|
management.call_command("graphql_schema", schema="")
|
||||||
|
|
||||||
open_mock.assert_called_once()
|
open_mock.assert_called_once()
|
||||||
|
|
||||||
dump_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][
|
||||||
assert dump_mock.call_args[1]["indent"] > 0, "output should be pretty-printed by default"
|
"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"
|
||||||
|
|
|
@ -241,8 +241,7 @@ def test_should_manytoone_convert_connectionorlist():
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Article
|
model = Article
|
||||||
|
|
||||||
graphene_field = convert_django_field(Reporter.articles.rel,
|
graphene_field = convert_django_field(Reporter.articles.rel, A._meta.registry)
|
||||||
A._meta.registry)
|
|
||||||
assert isinstance(graphene_field, graphene.Dynamic)
|
assert isinstance(graphene_field, graphene.Dynamic)
|
||||||
dynamic_field = graphene_field.get_type()
|
dynamic_field = graphene_field.get_type()
|
||||||
assert isinstance(dynamic_field, graphene.Field)
|
assert isinstance(dynamic_field, graphene.Field)
|
||||||
|
@ -255,8 +254,7 @@ def test_should_onetoone_reverse_convert_model():
|
||||||
class Meta:
|
class Meta:
|
||||||
model = FilmDetails
|
model = FilmDetails
|
||||||
|
|
||||||
graphene_field = convert_django_field(Film.details.related,
|
graphene_field = convert_django_field(Film.details.related, A._meta.registry)
|
||||||
A._meta.registry)
|
|
||||||
assert isinstance(graphene_field, graphene.Dynamic)
|
assert isinstance(graphene_field, graphene.Dynamic)
|
||||||
dynamic_field = graphene_field.get_type()
|
dynamic_field = graphene_field.get_type()
|
||||||
assert isinstance(dynamic_field, graphene.Field)
|
assert isinstance(dynamic_field, graphene.Field)
|
||||||
|
|
|
@ -126,8 +126,7 @@ class GraphQLView(View):
|
||||||
|
|
||||||
if show_graphiql:
|
if show_graphiql:
|
||||||
return self.render_graphiql(
|
return self.render_graphiql(
|
||||||
request,
|
request, graphiql_version=self.graphiql_version
|
||||||
graphiql_version=self.graphiql_version,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.batch:
|
if self.batch:
|
||||||
|
|
8
setup.py
8
setup.py
|
@ -24,6 +24,12 @@ tests_require = [
|
||||||
"pytest-django>=3.3.2",
|
"pytest-django>=3.3.2",
|
||||||
] + rest_framework_require
|
] + rest_framework_require
|
||||||
|
|
||||||
|
|
||||||
|
dev_requires = [
|
||||||
|
"black==19.3b0",
|
||||||
|
"flake8==3.7.7",
|
||||||
|
] + tests_require
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="graphene-django",
|
name="graphene-django",
|
||||||
version=version,
|
version=version,
|
||||||
|
@ -58,7 +64,7 @@ setup(
|
||||||
setup_requires=["pytest-runner"],
|
setup_requires=["pytest-runner"],
|
||||||
tests_require=tests_require,
|
tests_require=tests_require,
|
||||||
rest_framework_require=rest_framework_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,
|
include_package_data=True,
|
||||||
zip_safe=False,
|
zip_safe=False,
|
||||||
platforms="any",
|
platforms="any",
|
||||||
|
|
Loading…
Reference in New Issue
Block a user