From 4e23c3ccf6d07159bd69ddf08fa3988171387a51 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Sat, 17 Sep 2016 17:09:56 -0700 Subject: [PATCH] Improved python syntax and sorts (pep8). Improved Readme --- .coveragerc | 2 + README.md | 52 +++++++++++-------- django_test_settings.py | 4 +- .../cookbook/cookbook/ingredients/schema.py | 2 +- examples/cookbook/cookbook/schema.py | 4 +- examples/starwars/schema.py | 10 ++-- graphene_django/converter.py | 14 ++--- graphene_django/debug/middleware.py | 3 +- graphene_django/debug/types.py | 3 +- graphene_django/fields.py | 4 +- graphene_django/filter/fields.py | 1 + graphene_django/filter/filterset.py | 3 +- graphene_django/filter/tests/test_fields.py | 2 +- graphene_django/filter/utils.py | 3 +- graphene_django/form_converter.py | 3 +- .../management/commands/graphql_schema.py | 4 +- graphene_django/registry.py | 9 +++- graphene_django/tests/schema.py | 2 +- graphene_django/tests/test_converter.py | 13 +++-- graphene_django/tests/test_form_converter.py | 2 +- graphene_django/tests/test_query.py | 3 +- graphene_django/tests/test_schema.py | 15 ++++-- graphene_django/tests/test_types.py | 12 ++--- graphene_django/types.py | 13 +++-- graphene_django/utils.py | 7 ++- graphene_django/views.py | 1 + setup.cfg | 10 ++++ 27 files changed, 132 insertions(+), 69 deletions(-) create mode 100644 .coveragerc diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..6c334f8 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,2 @@ +[run] +omit = */tests/*,graphene_django/debug/sql/* diff --git a/README.md b/README.md index e1bc881..e4461dd 100644 --- a/README.md +++ b/README.md @@ -3,20 +3,10 @@ Please read [UPGRADE-v1.0.md](https://github.com/graphql-python/graphene/blob/ma --- -# ![Graphene Logo](http://graphene-python.org/favicon.png) [Graphene-Django](http://graphene-python.org) [![Build Status](https://travis-ci.org/graphql-python/graphene-django.svg?branch=master)](https://travis-ci.org/graphql-python/graphene-django) [![PyPI version](https://badge.fury.io/py/graphene-django.svg)](https://badge.fury.io/py/graphene-django) [![Coverage Status](https://coveralls.io/repos/graphql-python/graphene-django/badge.svg?branch=master&service=github)](https://coveralls.io/github/graphql-python/graphene-django?branch=master) +# ![Graphene Logo](http://graphene-python.org/favicon.png) Graphene-Django [![Build Status](https://travis-ci.org/graphql-python/graphene-django.svg?branch=master)](https://travis-ci.org/graphql-python/graphene-django) [![PyPI version](https://badge.fury.io/py/graphene-django.svg)](https://badge.fury.io/py/graphene-django) [![Coverage Status](https://coveralls.io/repos/graphql-python/graphene-django/badge.svg?branch=master&service=github)](https://coveralls.io/github/graphql-python/graphene-django?branch=master) -[Graphene](http://graphene-python.org) is a Python library for building GraphQL schemas/types fast and easily. - -- **Easy to use:** Graphene helps you use GraphQL in Python without effort. -- **Relay:** Graphene has builtin support for Relay -- **Django:** Automatic *Django model* mapping to Graphene Types. Check a fully working [Django](http://github.com/graphql-python/swapi-graphene) implementation - -Graphene also supports *SQLAlchemy*! - -*What is supported in this Python version?* **Everything**: Interfaces, ObjectTypes, Scalars, Unions and Relay (Nodes, Connections), in addition to queries, mutations and subscriptions. - -**NEW**!: [Try graphene online](http://graphene-python.org/playground/) +A [Django](https://www.djangoproject.com/) integration for [Graphene](http://graphene-python.org/). ## Installation @@ -28,30 +18,50 @@ pip install "graphene-django>=1.0.dev" ## Examples -Here is one example for get you started: +Here is a simple Django model: ```python from django.db import models -from graphene_django import DjangoObjectType class UserModel(models.Model): name = models.CharField(max_length=100) last_name = models.CharField(max_length=100) +``` + +To create a GraphQL schema for it you simply have to write the following: + +```python +from graphene_django import DjangoObjectType class User(DjangoObjectType): class Meta: - # This type will transform all the UserModel fields - # into Graphene fields automatically model = UserModel - # An extra field in the User Type - full_name = graphene.String() +class Query(graphene.ObjectType): + users = graphene.List(User) - def resolve_full_name(self, args, context, info): - return "{} {}".format(self.name, self.last_name) + @graphene.resolve_only_args + def resolve_users(self): + return UserModel.objects.all() + +schema = graphene.Schema(query=QueryRoot) ``` -If you want to learn even more, you can also check the following [examples](examples/): +Then you can simply query the schema: + +```python +query = ''' + query { + users { + name, + lastName + } + } +''' +result = schema.execute(query) +``` + +To learn more check out the following [examples](examples/): * **Schema with Filtering**: [Cookbook example](examples/cookbook) * **Relay Schema**: [Starwars Relay example](examples/starwars) diff --git a/django_test_settings.py b/django_test_settings.py index 12efbf6..e8cb7a2 100644 --- a/django_test_settings.py +++ b/django_test_settings.py @@ -1,4 +1,6 @@ -import sys, os +import sys +import os + ROOT_PATH = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, ROOT_PATH + '/examples/') diff --git a/examples/cookbook/cookbook/ingredients/schema.py b/examples/cookbook/cookbook/ingredients/schema.py index 64353e3..f79ac0b 100644 --- a/examples/cookbook/cookbook/ingredients/schema.py +++ b/examples/cookbook/cookbook/ingredients/schema.py @@ -1,5 +1,5 @@ from cookbook.ingredients.models import Category, Ingredient -from graphene import ObjectType, Field, AbstractType, Node +from graphene import AbstractType, Field, Node from graphene_django.filter import DjangoFilterConnectionField from graphene_django.types import DjangoObjectType diff --git a/examples/cookbook/cookbook/schema.py b/examples/cookbook/cookbook/schema.py index 0b89bcf..d6bb3ac 100644 --- a/examples/cookbook/cookbook/schema.py +++ b/examples/cookbook/cookbook/schema.py @@ -1,8 +1,10 @@ -import graphene import cookbook.ingredients.schema +import graphene + # print cookbook.ingredients.schema.Query._meta.graphql_type.get_fields()['allIngredients'].args + class Query(cookbook.ingredients.schema.Query, graphene.ObjectType): pass diff --git a/examples/starwars/schema.py b/examples/starwars/schema.py index b401447..e2127de 100644 --- a/examples/starwars/schema.py +++ b/examples/starwars/schema.py @@ -1,14 +1,12 @@ import graphene -from graphene import relay, resolve_only_args, Schema +from graphene import Schema, relay, resolve_only_args from graphene_django import DjangoObjectType from .data import (create_ship, get_empire, get_faction, get_rebels, get_ship, get_ships) -from .models import ( - Character as CharacterModel, - Faction as FactionModel, - Ship as ShipModel -) +from .models import Character as CharacterModel +from .models import Faction as FactionModel +from .models import Ship as ShipModel class Ship(DjangoObjectType): diff --git a/graphene_django/converter.py b/graphene_django/converter.py index dc1eb88..9d6b28b 100644 --- a/graphene_django/converter.py +++ b/graphene_django/converter.py @@ -1,16 +1,17 @@ from django.db import models from django.utils.encoding import force_text -from graphene import Enum, List, ID, Boolean, Float, Int, String, Field, NonNull, Field, Dynamic -from graphene.types.json import JSONString -from graphene.types.datetime import DateTime -from graphene.utils.str_converters import to_const +from graphene import (ID, Boolean, Dynamic, Enum, Field, Float, Int, List, + NonNull, String) from graphene.relay import is_node +from graphene.types.datetime import DateTime +from graphene.types.json import JSONString +from graphene.utils.str_converters import to_const from .compat import (ArrayField, HStoreField, JSONField, RangeField, RelatedObject, UUIDField) -from .utils import get_related_model, import_single_dispatch from .fields import get_connection_field +from .utils import get_related_model, import_single_dispatch singledispatch = import_single_dispatch() @@ -37,9 +38,10 @@ def convert_django_field_with_choices(field, registry=None): name = '{}{}'.format(meta.object_name, field.name.capitalize()) choices = list(get_choices(choices)) named_choices = [(c[0], c[1]) for c in choices] - named_choices_descriptions = {c[0]:c[2] for c in choices} + named_choices_descriptions = {c[0]: c[2] for c in choices} class EnumWithDescriptionsType(object): + @property def description(self): return named_choices_descriptions[self.name] diff --git a/graphene_django/debug/middleware.py b/graphene_django/debug/middleware.py index 9479fd1..acd8524 100644 --- a/graphene_django/debug/middleware.py +++ b/graphene_django/debug/middleware.py @@ -1,6 +1,7 @@ -from promise import Promise from django.db import connections +from promise import Promise + from .sql.tracking import unwrap_cursor, wrap_cursor from .types import DjangoDebug diff --git a/graphene_django/debug/types.py b/graphene_django/debug/types.py index 891fe38..0d3701d 100644 --- a/graphene_django/debug/types.py +++ b/graphene_django/debug/types.py @@ -1,4 +1,5 @@ -from graphene import ObjectType, List +from graphene import List, ObjectType + from .sql.types import DjangoDebugSQL diff --git a/graphene_django/fields.py b/graphene_django/fields.py index b23a4b6..df9e230 100644 --- a/graphene_django/fields.py +++ b/graphene_django/fields.py @@ -1,9 +1,11 @@ from functools import partial from django.db.models.query import QuerySet + from graphene.relay import ConnectionField, PageInfo from graphql_relay.connection.arrayconnection import connection_from_list_slice -from .utils import maybe_queryset, DJANGO_FILTER_INSTALLED + +from .utils import DJANGO_FILTER_INSTALLED, maybe_queryset class DjangoConnectionField(ConnectionField): diff --git a/graphene_django/filter/fields.py b/graphene_django/filter/fields.py index f4f84e2..bd4b44d 100644 --- a/graphene_django/filter/fields.py +++ b/graphene_django/filter/fields.py @@ -1,4 +1,5 @@ from functools import partial + from ..fields import DjangoConnectionField from .utils import get_filtering_args_from_filterset, get_filterset_class diff --git a/graphene_django/filter/filterset.py b/graphene_django/filter/filterset.py index 7aa4031..42b6ff1 100644 --- a/graphene_django/filter/filterset.py +++ b/graphene_django/filter/filterset.py @@ -5,9 +5,10 @@ from django.utils.text import capfirst from django_filters import Filter, MultipleChoiceFilter from django_filters.filterset import FilterSet, FilterSetMetaclass -from ..forms import GlobalIDFormField, GlobalIDMultipleChoiceField from graphql_relay.node.node import from_global_id +from ..forms import GlobalIDFormField, GlobalIDMultipleChoiceField + class GlobalIDFilter(Filter): field_class = GlobalIDFormField diff --git a/graphene_django/filter/tests/test_fields.py b/graphene_django/filter/tests/test_fields.py index 4735ee0..a4cad62 100644 --- a/graphene_django/filter/tests/test_fields.py +++ b/graphene_django/filter/tests/test_fields.py @@ -2,7 +2,7 @@ from datetime import datetime import pytest -from graphene import ObjectType, Schema, Field +from graphene import Field, ObjectType, Schema from graphene.relay import Node from graphene_django import DjangoObjectType from graphene_django.forms import (GlobalIDFormField, diff --git a/graphene_django/filter/utils.py b/graphene_django/filter/utils.py index 86a34f2..30562d2 100644 --- a/graphene_django/filter/utils.py +++ b/graphene_django/filter/utils.py @@ -1,6 +1,7 @@ import six -from graphene import Argument, String +from graphene import String + from .filterset import custom_filterset_factory, setup_filterset diff --git a/graphene_django/form_converter.py b/graphene_django/form_converter.py index 2ddb912..8778881 100644 --- a/graphene_django/form_converter.py +++ b/graphene_django/form_converter.py @@ -1,7 +1,8 @@ from django import forms from django.forms.fields import BaseTemporalField -from graphene import ID, Boolean, Float, Int, String, List +from graphene import ID, Boolean, Float, Int, List, String + from .forms import GlobalIDFormField, GlobalIDMultipleChoiceField from .utils import import_single_dispatch diff --git a/graphene_django/management/commands/graphql_schema.py b/graphene_django/management/commands/graphql_schema.py index 07b802d..307246b 100644 --- a/graphene_django/management/commands/graphql_schema.py +++ b/graphene_django/management/commands/graphql_schema.py @@ -67,6 +67,6 @@ class Command(CommandArguments): self.save_file(out, schema_dict) style = getattr(self, 'style', None) - SUCCESS = getattr(style, 'SUCCESS', lambda x: x) + success = getattr(style, 'SUCCESS', lambda x: x) - self.stdout.write(SUCCESS('Successfully dumped GraphQL schema to %s' % out)) + self.stdout.write(success('Successfully dumped GraphQL schema to %s' % out)) diff --git a/graphene_django/registry.py b/graphene_django/registry.py index 464e826..488fbb2 100644 --- a/graphene_django/registry.py +++ b/graphene_django/registry.py @@ -1,13 +1,18 @@ class Registry(object): + def __init__(self): self._registry = {} self._registry_models = {} def register(self, cls): from .types import DjangoObjectType - assert issubclass(cls, DjangoObjectType), 'Only DjangoObjectTypes can be registered, received "{}"'.format(cls.__name__) + assert issubclass( + cls, DjangoObjectType), 'Only DjangoObjectTypes can be registered, received "{}"'.format( + cls.__name__) assert cls._meta.registry == self, 'Registry for a Model have to match.' - # assert self.get_type_for_model(cls._meta.model) == cls, 'Multiple DjangoObjectTypes registered for "{}"'.format(cls._meta.model) + # assert self.get_type_for_model(cls._meta.model) == cls, ( + # 'Multiple DjangoObjectTypes registered for "{}"'.format(cls._meta.model) + # ) self._registry[cls._meta.model] = cls def get_type_for_model(self, model): diff --git a/graphene_django/tests/schema.py b/graphene_django/tests/schema.py index 5584149..6f6f158 100644 --- a/graphene_django/tests/schema.py +++ b/graphene_django/tests/schema.py @@ -1,7 +1,7 @@ import graphene from graphene import Schema, relay -from ..types import DjangoObjectType +from ..types import DjangoObjectType from .models import Article, Reporter diff --git a/graphene_django/tests/test_converter.py b/graphene_django/tests/test_converter.py index ee1553c..0c50477 100644 --- a/graphene_django/tests/test_converter.py +++ b/graphene_django/tests/test_converter.py @@ -4,17 +4,20 @@ from django.utils.translation import ugettext_lazy as _ from py.test import raises import graphene -from graphene.relay import Node, ConnectionField +from graphene.relay import ConnectionField, Node from graphene.types.datetime import DateTime from graphene.types.json import JSONString -# from graphene.core.types.custom_scalars import DateTime, JSONString from ..compat import (ArrayField, HStoreField, JSONField, MissingType, RangeField) from ..converter import convert_django_field, convert_django_field_with_choices from ..registry import Registry -from .models import Article, Reporter, Film, FilmDetails, Pet from ..types import DjangoObjectType +from .models import Article, Film, FilmDetails, Reporter + + +# from graphene.core.types.custom_scalars import DateTime, JSONString + def assert_conversion(django_field, graphene_field, *args, **kwargs): @@ -166,6 +169,7 @@ def test_should_manytomany_convert_connectionorlist(): def test_should_manytomany_convert_connectionorlist_list(): class A(DjangoObjectType): + class Meta: model = Reporter @@ -179,6 +183,7 @@ def test_should_manytomany_convert_connectionorlist_list(): def test_should_manytomany_convert_connectionorlist_connection(): class A(DjangoObjectType): + class Meta: model = Reporter interfaces = (Node, ) @@ -196,6 +201,7 @@ def test_should_manytoone_convert_connectionorlist(): getattr(Reporter.articles, 'related') class A(DjangoObjectType): + class Meta: model = Article @@ -213,6 +219,7 @@ def test_should_onetoone_reverse_convert_model(): getattr(Film.details, 'related') class A(DjangoObjectType): + class Meta: model = FilmDetails diff --git a/graphene_django/tests/test_form_converter.py b/graphene_django/tests/test_form_converter.py index 661e73a..dc5f39b 100644 --- a/graphene_django/tests/test_form_converter.py +++ b/graphene_django/tests/test_form_converter.py @@ -2,9 +2,9 @@ from django import forms from py.test import raises import graphene -from ..form_converter import convert_form_field from graphene import ID, List, NonNull +from ..form_converter import convert_form_field from .models import Reporter diff --git a/graphene_django/tests/test_query.py b/graphene_django/tests/test_query.py index 80a45e9..326d4d5 100644 --- a/graphene_django/tests/test_query.py +++ b/graphene_django/tests/test_query.py @@ -8,9 +8,8 @@ import graphene from graphene.relay import Node from ..compat import MissingType, RangeField -from ..types import DjangoObjectType from ..fields import DjangoConnectionField -from ..registry import reset_global_registry, get_global_registry +from ..types import DjangoObjectType from .models import Article, Reporter pytestmark = pytest.mark.django_db diff --git a/graphene_django/tests/test_schema.py b/graphene_django/tests/test_schema.py index d5af9c3..a3a2307 100644 --- a/graphene_django/tests/test_schema.py +++ b/graphene_django/tests/test_schema.py @@ -1,8 +1,7 @@ from py.test import raises -from ..types import DjangoObjectType from ..registry import Registry - +from ..types import DjangoObjectType from .models import Reporter @@ -24,10 +23,20 @@ def test_should_raise_if_model_is_invalid(): def test_should_map_fields_correctly(): class ReporterType2(DjangoObjectType): + class Meta: model = Reporter registry = Registry() - assert list(ReporterType2._meta.fields.keys()) == ['id', 'first_name', 'last_name', 'email', 'pets', 'a_choice', 'articles', 'films'] + assert list( + ReporterType2._meta.fields.keys()) == [ + 'id', + 'first_name', + 'last_name', + 'email', + 'pets', + 'a_choice', + 'articles', + 'films'] def test_should_map_only_few_fields(): diff --git a/graphene_django/tests/test_types.py b/graphene_django/tests/test_types.py index ecc2225..ed9f1df 100644 --- a/graphene_django/tests/test_types.py +++ b/graphene_django/tests/test_types.py @@ -1,12 +1,12 @@ -from graphql.type import GraphQLObjectType from mock import patch -from graphene import ObjectType, Field, Int, ID, Schema, Interface -from graphene.relay import Node, ConnectionField -from ..types import DjangoObjectType +from graphene import Interface, ObjectType, Schema +from graphene.relay import Node -from .models import Article as ArticleModel, Reporter as ReporterModel -from ..registry import reset_global_registry, Registry +from ..registry import reset_global_registry +from ..types import DjangoObjectType +from .models import Article as ArticleModel +from .models import Reporter as ReporterModel reset_global_registry() diff --git a/graphene_django/types.py b/graphene_django/types.py index 91e7173..ef464d1 100644 --- a/graphene_django/types.py +++ b/graphene_django/types.py @@ -2,14 +2,16 @@ from collections import OrderedDict import six -from graphene import ObjectType, Field +from graphene import Field, ObjectType from graphene.types.objecttype import ObjectTypeMeta -from .converter import convert_django_field_with_choices from graphene.types.options import Options -from .utils import get_model_fields, is_valid_django_model, DJANGO_FILTER_INSTALLED -from .registry import Registry, get_global_registry +from graphene.types.utils import merge, yank_fields_from_attrs from graphene.utils.is_base_type import is_base_type -from graphene.types.utils import yank_fields_from_attrs, merge + +from .converter import convert_django_field_with_choices +from .registry import Registry, get_global_registry +from .utils import (DJANGO_FILTER_INSTALLED, get_model_fields, + is_valid_django_model) def construct_fields(options): @@ -95,6 +97,7 @@ class DjangoObjectTypeMeta(ObjectTypeMeta): class DjangoObjectType(six.with_metaclass(DjangoObjectTypeMeta, ObjectType)): + @classmethod def is_type_of(cls, root, context, info): if isinstance(root, cls): diff --git a/graphene_django/utils.py b/graphene_django/utils.py index a7c37b0..a58db3e 100644 --- a/graphene_django/utils.py +++ b/graphene_django/utils.py @@ -1,12 +1,17 @@ import inspect + from django.db import models from django.db.models.manager import Manager +from .compat import RelatedObject + + # from graphene.utils import LazyList + + class LazyList(object): pass -from .compat import RelatedObject try: import django_filters # noqa diff --git a/graphene_django/views.py b/graphene_django/views.py index cc8b2b6..1cbfadd 100644 --- a/graphene_django/views.py +++ b/graphene_django/views.py @@ -2,6 +2,7 @@ from graphql_django_view import GraphQLView as BaseGraphQLView class GraphQLView(BaseGraphQLView): + def __init__(self, schema, **kwargs): super(GraphQLView, self).__init__( schema=schema, diff --git a/setup.cfg b/setup.cfg index 83ffeec..d1d6da9 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,2 +1,12 @@ [tool:pytest] DJANGO_SETTINGS_MODULE = django_test_settings + +[flake8] +exclude = setup.py,docs/*,examples/*,tests,graphene_django/debug/sql/* +max-line-length = 120 + +[coverage:run] +omit = */tests/* + +[isort] +known_first_party=graphene,graphene_django