Skip to content

Commit

Permalink
Drop all python 2, drf<3.10, django<2.2 support shims
Browse files Browse the repository at this point in the history
  • Loading branch information
axnsan12 committed Oct 25, 2020
1 parent 23d81e2 commit 64ceb91
Show file tree
Hide file tree
Showing 21 changed files with 78 additions and 231 deletions.
3 changes: 2 additions & 1 deletion CONTRIBUTING.rst
Expand Up @@ -95,7 +95,8 @@ You want to contribute some code? Great! Here are a few steps to get you started

#. **Your code must pass all the required travis jobs before it is merged**

As of now, this consists of running on Python 2.7, 3.5, 3.6 and 3.7, and building the docs succesfully.
As of now, this consists of running on the supported Python, Django, DRF version matrix (see README),
and building the docs succesfully.

******************
Maintainer's notes
Expand Down
1 change: 0 additions & 1 deletion requirements/base.txt
Expand Up @@ -2,7 +2,6 @@ coreapi>=2.3.3
coreschema>=0.0.4
ruamel.yaml>=0.15.34
inflection>=0.3.1
six>=1.10.0
uritemplate>=3.0.0
packaging

Expand Down
1 change: 0 additions & 1 deletion requirements/dev.txt
Expand Up @@ -4,4 +4,3 @@
-r lint.txt

tox-battery>=0.5
django-oauth-toolkit
5 changes: 3 additions & 2 deletions requirements/testproj.txt
@@ -1,9 +1,10 @@
# test project requirements
Pillow>=4.3.0
django-filter>=1.1.0,<2.0; python_version == "2.7"
django-filter>=1.1.0; python_version >= "3.5"
django-filter>=2.4.0
djangorestframework-camel-case>=1.1.2
djangorestframework-recursive>=0.1.2
dj-database-url>=0.4.2
user_agents>=1.1.0
django-cors-headers
django-oauth-toolkit>=1.3.0

10 changes: 4 additions & 6 deletions src/drf_yasg/codecs.py
@@ -1,5 +1,3 @@
from six import binary_type, raise_from, text_type

import copy
import json
import logging
Expand All @@ -24,7 +22,7 @@ def _validate_flex(spec):
try:
validate_flex(spec)
except ValidationError as ex:
raise_from(SwaggerValidationError(str(ex)), ex)
raise SwaggerValidationError(str(ex)) from ex


def _validate_swagger_spec_validator(spec):
Expand All @@ -33,7 +31,7 @@ def _validate_swagger_spec_validator(spec):
try:
validate_ssv(spec)
except SSVErr as ex:
raise_from(SwaggerValidationError(str(ex)), ex)
raise SwaggerValidationError(str(ex)) from ex


#:
Expand Down Expand Up @@ -182,8 +180,8 @@ def represent_text(self, text):
return self.represent_scalar('tag:yaml.org,2002:str', text)


SaneYamlDumper.add_representer(binary_type, SaneYamlDumper.represent_text)
SaneYamlDumper.add_representer(text_type, SaneYamlDumper.represent_text)
SaneYamlDumper.add_representer(bytes, SaneYamlDumper.represent_text)
SaneYamlDumper.add_representer(str, SaneYamlDumper.represent_text)
SaneYamlDumper.add_representer(OrderedDict, SaneYamlDumper.represent_odict)
SaneYamlDumper.add_multi_representer(OrderedDict, SaneYamlDumper.represent_odict)

Expand Down
12 changes: 2 additions & 10 deletions src/drf_yasg/generators.py
Expand Up @@ -3,14 +3,14 @@
import re
from collections import OrderedDict, defaultdict

import rest_framework
import uritemplate
from coreapi.compat import urlparse
from django.urls import URLPattern, URLResolver
from packaging.version import Version
from rest_framework import versioning
from rest_framework.schemas import SchemaGenerator
from rest_framework.schemas.generators import EndpointEnumerator as _EndpointEnumerator
from rest_framework.schemas.generators import endpoint_ordering, get_pk_name
from rest_framework.schemas.utils import get_pk_description
from rest_framework.settings import api_settings

from . import openapi
Expand All @@ -20,14 +20,6 @@
from .openapi import ReferenceResolver, SwaggerDict
from .utils import force_real_str, get_consumes, get_produces

if Version(rest_framework.__version__) < Version('3.10'):
from rest_framework.schemas.generators import SchemaGenerator
from rest_framework.schemas.inspectors import get_pk_description
else:
from rest_framework.schemas import SchemaGenerator
from rest_framework.schemas.utils import get_pk_description


logger = logging.getLogger(__name__)

PATH_PARAMETER_RE = re.compile(r'{(?P<parameter>\w+)}')
Expand Down
12 changes: 2 additions & 10 deletions src/drf_yasg/inspectors/base.py
Expand Up @@ -18,16 +18,8 @@ def is_callable_method(cls_or_instance, method_name):
# bound classmethod or instance method
return method, True

try:
# inspect.getattr_static was added in python 3.2
from inspect import getattr_static

# on python 3, both unbound instance methods (i.e. getattr(cls, mth)) and static methods are plain functions
# getattr_static allows us to check the type of the method descriptor; for `@staticmethod` this is staticmethod
return method, isinstance(getattr_static(cls_or_instance, method_name, None), staticmethod)
except ImportError:
# python 2 still has unbound methods, so ismethod <=> !staticmethod TODO: remove when dropping python 2.7
return method, not inspect.ismethod(method)
from inspect import getattr_static
return method, isinstance(getattr_static(cls_or_instance, method_name, None), staticmethod)


def call_view_method(view, method_name, fallback_attr=None, default=None):
Expand Down
61 changes: 24 additions & 37 deletions src/drf_yasg/inspectors/field.py
@@ -1,10 +1,10 @@
import inspect
import logging
import operator
import sys
from collections import OrderedDict

import datetime
import typing
import uuid
from decimal import Decimal
from django.core import validators
Expand All @@ -19,11 +19,6 @@
)
from .base import FieldInspector, NotHandled, SerializerInspector, call_view_method

try:
import typing
except ImportError:
typing = None

try:
from inspect import signature as inspect_signature
except ImportError:
Expand Down Expand Up @@ -490,42 +485,34 @@ def hint_class_issubclass(hint_class, check_class):
(datetime.date, (openapi.TYPE_STRING, openapi.FORMAT_DATE)),
]

if sys.version_info < (3, 0):
# noinspection PyUnresolvedReferences
hinting_type_info.append((unicode, (openapi.TYPE_STRING, None))) # noqa: F821

if typing:
if hasattr(typing, 'get_args'):
typing_get_args = typing.get_args
else:
def typing_get_args(tp):
return getattr(tp, '__args__', ())
if hasattr(typing, 'get_args'):
# python >=3.8
typing_get_args = typing.get_args
else:
# python <3.8
def typing_get_args(tp):
return getattr(tp, '__args__', ())

def inspect_collection_hint_class(hint_class):
args = typing_get_args(hint_class)
child_class = args[0] if args else str
child_type_info = get_basic_type_info_from_hint(child_class) or {'type': openapi.TYPE_STRING}

return OrderedDict([
('type', openapi.TYPE_ARRAY),
('items', openapi.Items(**child_type_info)),
])
def inspect_collection_hint_class(hint_class):
args = typing_get_args(hint_class)
child_class = args[0] if args else str
child_type_info = get_basic_type_info_from_hint(child_class) or {'type': openapi.TYPE_STRING}

hinting_type_info.append(((typing.Sequence, typing.AbstractSet), inspect_collection_hint_class))
return OrderedDict([
('type', openapi.TYPE_ARRAY),
('items', openapi.Items(**child_type_info)),
])


hinting_type_info.append(((typing.Sequence, typing.AbstractSet), inspect_collection_hint_class))


def _get_union_types(hint_class):
if typing:
origin_type = get_origin_type(hint_class)
if origin_type is typing.Union:
return hint_class.__args__
try:
# python 3.5.2 and lower compatibility
if issubclass(origin_type, typing.Union):
return hint_class.__union_params__
except TypeError:
pass
return None
origin_type = get_origin_type(hint_class)
if origin_type is typing.Union:
return hint_class.__args__


def get_basic_type_info_from_hint(hint_class):
Expand All @@ -539,7 +526,7 @@ def get_basic_type_info_from_hint(hint_class):
"""
union_types = _get_union_types(hint_class)

if typing and union_types:
if union_types:
# Optional is implemented as Union[T, None]
if len(union_types) == 2 and isinstance(None, union_types[1]):
result = get_basic_type_info_from_hint(union_types[0])
Expand Down Expand Up @@ -612,7 +599,7 @@ def field_to_swagger_object(self, field, swagger_object_type, use_references, **
serializer.read_only = True

return self.probe_field_inspectors(serializer, swagger_object_type, use_references, read_only=True)
elif typing and inspect_signature:
elif inspect_signature:
# look for Python 3.5+ style type hinting of the return value
hint_class = inspect_signature(method).return_annotation

Expand Down
8 changes: 2 additions & 6 deletions src/drf_yasg/management/commands/generate_swagger.py
Expand Up @@ -154,10 +154,6 @@ def handle(self, output_file, overwrite, format, api_url, mock, api_version, use
if output_file == '-':
self.write_schema(schema, self.stdout, format)
else:
# normally this would be easily done with open(mode='x'/'w'),
# but python 2 is a pain in the ass as usual
# TODO: simplify when dropping support for python 2.7
flags = os.O_CREAT | os.O_WRONLY
flags = flags | (os.O_TRUNC if overwrite else os.O_EXCL)
with os.fdopen(os.open(output_file, flags), "w") as stream:
flags = "w" if overwrite else "x"
with open(output_file, flags) as stream:
self.write_schema(schema, stream, format)
4 changes: 1 addition & 3 deletions src/drf_yasg/openapi.py
@@ -1,5 +1,3 @@
import six

import collections
import logging
import re
Expand Down Expand Up @@ -150,7 +148,7 @@ def _as_odict(obj, memo):
for attr, val in items:
result[attr] = SwaggerDict._as_odict(val, memo)
return result
elif isinstance(obj, six.string_types):
elif isinstance(obj, str):
return force_real_str(obj)
elif isinstance(obj, collections_abc.Iterable) and not isinstance(obj, collections_abc.Iterator):
return type(obj)(SwaggerDict._as_odict(elem, memo) for elem in obj)
Expand Down
4 changes: 1 addition & 3 deletions src/drf_yasg/renderers.py
@@ -1,5 +1,3 @@
import six

from django.shortcuts import resolve_url
from django.template.loader import render_to_string
from django.utils.encoding import force_str
Expand Down Expand Up @@ -89,7 +87,7 @@ def resolve_url(self, to):
return None

args, kwargs = None, None
if not isinstance(to, six.string_types):
if not isinstance(to, str):
if len(to) > 2:
to, args, kwargs = to
elif len(to) == 2:
Expand Down
2 changes: 1 addition & 1 deletion testproj/people/urls.py
Expand Up @@ -21,6 +21,6 @@
path('', person_list, name='people-list'),
path('<int:pk>', person_detail, name='person-detail'),

path('<int:person>/identity$', identity_detail,
path('<int:person>/identity', identity_detail,
name='person-identity'),
)
8 changes: 1 addition & 7 deletions testproj/snippets/serializers.py
@@ -1,16 +1,10 @@
import rest_framework
from decimal import Decimal
from django.contrib.auth import get_user_model
from packaging.version import Version
from django.core.validators import MaxLengthValidator, MinValueValidator
from rest_framework import serializers

from snippets.models import LANGUAGE_CHOICES, STYLE_CHOICES, Snippet, SnippetViewer

if Version(rest_framework.__version__) < Version('3.10'):
from rest_framework.compat import MaxLengthValidator, MinValueValidator
else:
from django.core.validators import MaxLengthValidator, MinValueValidator


class LanguageSerializer(serializers.Serializer):
name = serializers.ChoiceField(
Expand Down
2 changes: 1 addition & 1 deletion testproj/todo/urls.py
Expand Up @@ -14,6 +14,6 @@
urlpatterns = router.urls

urlpatterns += [
path(r'<int:todo_id>/yetanothers/<int:yetanother_id>/$',
path(r'<int:todo_id>/yetanothers/<int:yetanother_id>/',
views.NestedTodoView.as_view(), ),
]
File renamed without changes.
81 changes: 0 additions & 81 deletions testproj/users/method_serializers_without_typing.py

This file was deleted.

0 comments on commit 64ceb91

Please sign in to comment.