Browse Source

Python 3 (#904)

* Remove Python 2 support

* Upgrade Python & Django versions

* Remove unsupported Django versions
* Remove unsupported Python versions
* Add Python 3.8

* Drop support for django-filter < 2

* Update LoginRequiredMixin doc link

* Remove redundant import

* Resolve RemovedInDjango40Warning warnings

* gql/graphene-django/graphene_django/tests/test_converter.py:175:
RemovedInDjango40Warning: django.utils.translation.ugettext_lazy() is
deprecated in favor of django.utils.translation.gettext_lazy().

* graphene-django/graphene_django/utils/utils.py:28:
RemovedInDjango40Warning: force_text() is deprecated in favor of
force_str().

* No need to use unicode strings with Python3

* Remove singledispatch dependency

singledispatch is inluded with Python >= 3.4, no need for external
package.
pull/940/head
Ülgen Sarıkavak 2 years ago committed by GitHub
parent
commit
dd0d6ef28f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 37
      .travis.yml
  2. 2
      docs/authorization.rst
  3. 16
      docs/conf.py
  4. 3
      docs/filtering.rst
  5. 5
      graphene_django/converter.py
  6. 3
      graphene_django/debug/sql/tracking.py
  7. 1
      graphene_django/fields.py
  8. 32
      graphene_django/filter/filterset.py
  9. 4
      graphene_django/filter/utils.py
  10. 6
      graphene_django/forms/converter.py
  11. 5
      graphene_django/rest_framework/serializer_converter.py
  12. 3
      graphene_django/settings.py
  13. 6
      graphene_django/tests/models.py
  14. 2
      graphene_django/tests/test_command.py
  15. 2
      graphene_django/tests/test_converter.py
  16. 5
      graphene_django/types.py
  17. 2
      graphene_django/utils/__init__.py
  18. 32
      graphene_django/utils/utils.py
  19. 5
      graphene_django/views.py
  20. 14
      setup.py
  21. 13
      tox.ini

37
.travis.yml

@ -5,10 +5,10 @@ dist: xenial
install:
- pip install tox tox-travis
script:
script:
- tox
after_success:
after_success:
- pip install coveralls
- coveralls
@ -24,24 +24,8 @@ jobs:
- env: DJANGO=master
include:
- python: 2.7
env: DJANGO=1.11
- python: 3.5
env: DJANGO=1.11
- python: 3.5
env: DJANGO=2.0
- python: 3.5
env: DJANGO=2.1
- python: 3.5
env: DJANGO=2.2
- python: 3.6
env: DJANGO=1.11
- python: 3.6
env: DJANGO=2.0
- python: 3.6
env: DJANGO=2.1
- python: 3.6
env: DJANGO=2.2
- python: 3.6
@ -51,10 +35,6 @@ jobs:
- python: 3.7
env: DJANGO=1.11
- python: 3.7
env: DJANGO=2.0
- python: 3.7
env: DJANGO=2.1
- python: 3.7
env: DJANGO=2.2
- python: 3.7
@ -62,12 +42,21 @@ jobs:
- python: 3.7
env: DJANGO=master
- python: 3.7
- python: 3.8
env: DJANGO=1.11
- python: 3.8
env: DJANGO=2.2
- python: 3.8
env: DJANGO=3.0
- python: 3.8
env: DJANGO=master
- python: 3.8
env: TOXENV=black,flake8
- stage: deploy
script: skip
python: 3.7
python: 3.8
after_success: true
deploy:
provider: pypi

2
docs/authorization.rst

@ -184,4 +184,4 @@ For Django 2.0 and above:
path('graphql', PrivateGraphQLView.as_view(graphiql=True, schema=schema)),
]
.. _LoginRequiredMixin: https://docs.djangoproject.com/en/1.10/topics/auth/default/#the-loginrequired-mixin
.. _LoginRequiredMixin: https://docs.djangoproject.com/en/dev/topics/auth/default/#the-loginrequired-mixin

16
docs/conf.py

@ -60,18 +60,18 @@ source_suffix = ".rst"
master_doc = "index"
# General information about the project.
project = u"Graphene Django"
copyright = u"Graphene 2017"
author = u"Syrus Akbary"
project = "Graphene Django"
copyright = "Graphene 2017"
author = "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 = "1.0"
# The full version, including alpha/beta/rc tags.
release = u"1.0.dev"
release = "1.0.dev"
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@ -276,7 +276,7 @@ latex_elements = {
# (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", "Graphene Documentation", "Syrus Akbary", "manual")
]
# The name of an image file (relative to this directory) to place at the top of
@ -317,7 +317,7 @@ latex_documents = [
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, "graphene_django", u"Graphene Django Documentation", [author], 1)
(master_doc, "graphene_django", "Graphene Django Documentation", [author], 1)
]
# If true, show URL addresses after external links.
@ -334,7 +334,7 @@ texinfo_documents = [
(
master_doc,
"Graphene-Django",
u"Graphene Django Documentation",
"Graphene Django Documentation",
author,
"Graphene Django",
"One line description of project.",

3
docs/filtering.rst

@ -2,8 +2,7 @@ Filtering
=========
Graphene integrates with
`django-filter <https://django-filter.readthedocs.io/en/master/>`__ (2.x for
Python 3 or 1.x for Python 2) to provide filtering of results. See the `usage
`django-filter <https://django-filter.readthedocs.io/en/master/>`__ to provide filtering of results. See the `usage
documentation <https://django-filter.readthedocs.io/en/master/guide/usage.html#the-filter>`__
for details on the format for ``filter_fields``.

5
graphene_django/converter.py

@ -1,4 +1,6 @@
from collections import OrderedDict
from functools import singledispatch
from django.db import models
from django.utils.encoding import force_str
from django.utils.module_loading import import_string
@ -26,9 +28,6 @@ from graphql import assert_valid_name
from .settings import graphene_settings
from .compat import ArrayField, HStoreField, JSONField, RangeField
from .fields import DjangoListField, DjangoConnectionField
from .utils import import_single_dispatch
singledispatch = import_single_dispatch()
def convert_choice_name(name):

3
graphene_django/debug/sql/tracking.py

@ -5,7 +5,6 @@ import json
from threading import local
from time import time
import six
from django.utils.encoding import force_str
from .types import DjangoDebugSQL
@ -77,7 +76,7 @@ class NormalCursorWrapper(object):
self.logger = logger
def _quote_expr(self, element):
if isinstance(element, six.string_types):
if isinstance(element, str):
return "'%s'" % force_str(element).replace("'", "''")
else:
return repr(element)

1
graphene_django/fields.py

@ -1,6 +1,5 @@
from functools import partial
import six
from django.db.models.query import QuerySet
from graphql_relay.connection.arrayconnection import connection_from_list_slice
from promise import Promise

32
graphene_django/filter/filterset.py

@ -1,7 +1,7 @@
import itertools
from django.db import models
from django_filters import Filter, MultipleChoiceFilter, VERSION
from django_filters import Filter, MultipleChoiceFilter
from django_filters.filterset import BaseFilterSet, FilterSet
from django_filters.filterset import FILTER_FOR_DBFIELD_DEFAULTS
@ -50,36 +50,6 @@ class GrapheneFilterSetMixin(BaseFilterSet):
)
# To support a Django 1.11 + Python 2.7 combination django-filter must be
# < 2.x.x. To support the earlier version of django-filter, the
# filter_for_reverse_field method must be present on GrapheneFilterSetMixin and
# must not be present for later versions of django-filter.
if VERSION[0] < 2:
from django.utils.text import capfirst
class GrapheneFilterSetMixinPython2(GrapheneFilterSetMixin):
@classmethod
def filter_for_reverse_field(cls, f, name):
"""Handles retrieving filters for reverse relationships
We override the default implementation so that we can handle
Global IDs (the default implementation expects database
primary keys)
"""
try:
rel = f.field.remote_field
except AttributeError:
rel = f.field.rel
default = {"name": name, "label": capfirst(rel.related_name)}
if rel.multiple:
# For to-many relationships
return GlobalIDMultipleChoiceFilter(**default)
else:
# For to-one relationships
return GlobalIDFilter(**default)
GrapheneFilterSetMixin = GrapheneFilterSetMixinPython2
def setup_filterset(filterset_class):
""" Wrap a provided filterset in Graphene-specific functionality
"""

4
graphene_django/filter/utils.py

@ -1,5 +1,3 @@
import six
from django_filters.utils import get_model_field
from .filterset import custom_filterset_factory, setup_filterset
@ -13,7 +11,7 @@ def get_filtering_args_from_filterset(filterset_class, type):
args = {}
model = filterset_class._meta.model
for name, filter_field in six.iteritems(filterset_class.base_filters):
for name, filter_field in filterset_class.base_filters.items():
form_field = None
if name in filterset_class.declared_filters:

6
graphene_django/forms/converter.py

@ -1,13 +1,11 @@
from functools import singledispatch
from django import forms
from django.core.exceptions import ImproperlyConfigured
from graphene import ID, Boolean, Float, Int, List, String, UUID, Date, DateTime, Time
from .forms import GlobalIDFormField, GlobalIDMultipleChoiceField
from ..utils import import_single_dispatch
singledispatch = import_single_dispatch()
@singledispatch

5
graphene_django/rest_framework/serializer_converter.py

@ -1,3 +1,5 @@
from functools import singledispatch
from django.core.exceptions import ImproperlyConfigured
from rest_framework import serializers
@ -5,11 +7,8 @@ import graphene
from ..registry import get_global_registry
from ..converter import convert_choices_to_named_enum_with_descriptions
from ..utils import import_single_dispatch
from .types import DictType
singledispatch = import_single_dispatch()
@singledispatch
def get_graphene_type_from_serializer_field(field):

3
graphene_django/settings.py

@ -13,7 +13,6 @@ back to the defaults.
"""
from __future__ import unicode_literals
import six
from django.conf import settings
from django.test.signals import setting_changed
@ -55,7 +54,7 @@ def perform_import(val, setting_name):
"""
if val is None:
return None
elif isinstance(val, six.string_types):
elif isinstance(val, str):
return import_from_string(val, setting_name)
elif isinstance(val, (list, tuple)):
return [import_from_string(item, setting_name) for item in val]

6
graphene_django/tests/models.py

@ -1,7 +1,7 @@
from __future__ import absolute_import
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
CHOICES = ((1, "this"), (2, _("that")))
@ -46,7 +46,7 @@ class Reporter(models.Model):
"Reporter Type",
null=True,
blank=True,
choices=[(1, u"Regular"), (2, u"CNN Reporter")],
choices=[(1, "Regular"), (2, "CNN Reporter")],
)
def __str__(self): # __unicode__ on Python 2
@ -105,7 +105,7 @@ class Article(models.Model):
"Importance",
null=True,
blank=True,
choices=[(1, u"Very important"), (2, u"Not as important")],
choices=[(1, "Very important"), (2, "Not as important")],
)
def __str__(self): # __unicode__ on Python 2

2
graphene_django/tests/test_command.py

@ -1,8 +1,8 @@
from textwrap import dedent
from django.core import management
from io import StringIO
from mock import mock_open, patch
from six import StringIO
from graphene import ObjectType, Schema, String

2
graphene_django/tests/test_converter.py

@ -1,7 +1,7 @@
import pytest
from collections import namedtuple
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import gettext_lazy as _
from graphene import NonNull
from py.test import raises

5
graphene_django/types.py

@ -1,7 +1,7 @@
import warnings
from collections import OrderedDict
from typing import Type
import six
from django.db.models import Model
from django.utils.functional import SimpleLazyObject
@ -21,9 +21,6 @@ from .utils import (
is_valid_django_model,
)
if six.PY3:
from typing import Type
ALL_FIELDS = "__all__"

2
graphene_django/utils/__init__.py

@ -4,7 +4,6 @@ from .utils import (
camelize,
get_model_fields,
get_reverse_fields,
import_single_dispatch,
is_valid_django_model,
maybe_queryset,
)
@ -16,6 +15,5 @@ __all__ = [
"get_model_fields",
"camelize",
"is_valid_django_model",
"import_single_dispatch",
"GraphQLTestCase",
]

32
graphene_django/utils/utils.py

@ -1,9 +1,8 @@
import inspect
import six
from django.db import models
from django.db.models.manager import Manager
from django.utils.encoding import force_text
from django.utils.encoding import force_str
from django.utils.functional import Promise
from graphene.utils.str_converters import to_camel_case
@ -26,14 +25,14 @@ def isiterable(value):
def _camelize_django_str(s):
if isinstance(s, Promise):
s = force_text(s)
return to_camel_case(s) if isinstance(s, six.string_types) else s
s = force_str(s)
return to_camel_case(s) if isinstance(s, str) else s
def camelize(data):
if isinstance(data, dict):
return {_camelize_django_str(k): camelize(v) for k, v in data.items()}
if isiterable(data) and not isinstance(data, (six.string_types, Promise)):
if isiterable(data) and not isinstance(data, (str, Promise)):
return [camelize(d) for d in data]
return data
@ -77,26 +76,3 @@ def get_model_fields(model):
def is_valid_django_model(model):
return inspect.isclass(model) and issubclass(model, models.Model)
def import_single_dispatch():
try:
from functools import singledispatch
except ImportError:
singledispatch = None
if not singledispatch:
try:
from singledispatch import singledispatch
except ImportError:
pass
if not singledispatch:
raise Exception(
"It seems your python version does not include "
"functools.singledispatch. Please install the 'singledispatch' "
"package. More information here: "
"https://pypi.python.org/pypi/singledispatch"
)
return singledispatch

5
graphene_django/views.py

@ -2,7 +2,6 @@ import inspect
import json
import re
import six
from django.http import HttpResponse, HttpResponseNotAllowed
from django.http.response import HttpResponseBadRequest
from django.shortcuts import render
@ -314,7 +313,7 @@ class GraphQLView(View):
variables = request.GET.get("variables") or data.get("variables")
id = request.GET.get("id") or data.get("id")
if variables and isinstance(variables, six.text_type):
if variables and isinstance(variables, str):
try:
variables = json.loads(variables)
except Exception:
@ -331,7 +330,7 @@ class GraphQLView(View):
if isinstance(error, GraphQLError):
return format_graphql_error(error)
return {"message": six.text_type(error)}
return {"message": str(error)}
@staticmethod
def get_content_type(request):

14
setup.py

@ -1,5 +1,4 @@
from setuptools import find_packages, setup
import sys
import ast
import re
@ -19,8 +18,7 @@ tests_require = [
"coveralls",
"mock",
"pytz",
"django-filter<2;python_version<'3'",
"django-filter>=2;python_version>='3'",
"django-filter>=2",
"pytest-django>=3.3.2",
] + rest_framework_require
@ -45,22 +43,18 @@ setup(
"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.4",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: Implementation :: PyPy",
],
keywords="api graphql protocol rest relay graphene",
packages=find_packages(exclude=["tests"]),
install_requires=[
"six>=1.10.0",
"graphene>=2.1.7,<3",
"graphql-core>=2.1.0,<3",
"Django>=1.11",
"singledispatch>=3.4.0.3",
"Django>=1.11,!=2.0.*,!=2.1.*",
"promise>=2.1",
],
setup_requires=["pytest-runner"],

13
tox.ini

@ -1,14 +1,11 @@
[tox]
envlist =
py{27,35,36,37}-django{111,20,21,22,master},
py{36,37}-django30,
py{36,37,38}-django{111,django22,django30,master},
black,flake8
[travis:env]
DJANGO =
1.11: django111
2.0: django20
2.1: django21
2.2: django22
3.0: django30
master: djangomaster
@ -20,23 +17,21 @@ setenv =
DJANGO_SETTINGS_MODULE=django_test_settings
deps =
-e.[test]
psycopg2
psycopg2-binary
django111: Django>=1.11,<2.0
django20: Django>=2.0,<2.1
django21: Django>=2.1,<2.2
django22: Django>=2.2,<3.0
django30: Django>=3.0a1,<3.1
djangomaster: https://github.com/django/django/archive/master.zip
commands = {posargs:py.test --cov=graphene_django graphene_django examples}
[testenv:black]
basepython = python3.7
basepython = python3.8
deps = -e.[dev]
commands =
black --exclude "/migrations/" graphene_django examples setup.py --check
[testenv:flake8]
basepython = python3.7
basepython = python3.8
deps = -e.[dev]
commands =
flake8 graphene_django examples

Loading…
Cancel
Save