mirror of
https://github.com/graphql-python/graphene-django.git
synced 2024-11-22 01:27:01 +03:00
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.
This commit is contained in:
parent
b84f61afab
commit
dd0d6ef28f
37
.travis.yml
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
|
||||
|
|
|
@ -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
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.",
|
||||
|
|
|
@ -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``.
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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,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
|
||||
|
|
|
@ -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
|
||||
"""
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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__"
|
||||
|
||||
|
|
|
@ -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",
|
||||
]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
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
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…
Reference in New Issue
Block a user