mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-08-08 06:14:47 +03:00
Merge tomchristie:master into kammala:fix-type-annotations
This commit is contained in:
commit
5b5e9f4533
|
@ -1,5 +1,5 @@
|
||||||
[settings]
|
[settings]
|
||||||
skip=.tox
|
skip=.tox,tests/compat/compat_py35.py
|
||||||
atomic=true
|
atomic=true
|
||||||
multi_line_output=5
|
multi_line_output=5
|
||||||
known_standard_library=types
|
known_standard_library=types
|
||||||
|
|
|
@ -7,6 +7,7 @@ versions of Django/Python, and compatibility wrappers around optional packages.
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import inspect
|
import inspect
|
||||||
|
import sys
|
||||||
|
|
||||||
import django
|
import django
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
|
@ -206,11 +207,34 @@ if six.PY3:
|
||||||
SHORT_SEPARATORS = (',', ':')
|
SHORT_SEPARATORS = (',', ':')
|
||||||
LONG_SEPARATORS = (', ', ': ')
|
LONG_SEPARATORS = (', ', ': ')
|
||||||
INDENT_SEPARATORS = (',', ': ')
|
INDENT_SEPARATORS = (',', ': ')
|
||||||
|
|
||||||
else:
|
else:
|
||||||
SHORT_SEPARATORS = (b',', b':')
|
SHORT_SEPARATORS = (b',', b':')
|
||||||
LONG_SEPARATORS = (b', ', b': ')
|
LONG_SEPARATORS = (b', ', b': ')
|
||||||
INDENT_SEPARATORS = (b',', b': ')
|
INDENT_SEPARATORS = (b',', b': ')
|
||||||
|
|
||||||
|
|
||||||
|
def is_simple_callable(obj):
|
||||||
|
"""
|
||||||
|
True if the object is a callable that takes no arguments.
|
||||||
|
"""
|
||||||
|
|
||||||
|
function = inspect.isfunction(obj)
|
||||||
|
method = inspect.ismethod(obj)
|
||||||
|
|
||||||
|
if not (function or method):
|
||||||
|
return False
|
||||||
|
if sys.version_info >= (3, 3):
|
||||||
|
signature = inspect.signature(obj)
|
||||||
|
defaults = [p for p in signature.parameters.values() if p.default is not inspect.Parameter.empty]
|
||||||
|
return len(signature.parameters) <= len(defaults)
|
||||||
|
else:
|
||||||
|
function = inspect.isfunction(obj)
|
||||||
|
args, _, _, defaults = inspect.getargspec(obj)
|
||||||
|
len_args = len(args) if function else len(args) - 1
|
||||||
|
len_defaults = len(defaults) if defaults else 0
|
||||||
|
return len_args <= len_defaults
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# DecimalValidator is unavailable in Django < 1.9
|
# DecimalValidator is unavailable in Django < 1.9
|
||||||
from django.core.validators import DecimalValidator
|
from django.core.validators import DecimalValidator
|
||||||
|
|
|
@ -31,7 +31,7 @@ from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from rest_framework import ISO_8601
|
from rest_framework import ISO_8601
|
||||||
from rest_framework.compat import (
|
from rest_framework.compat import (
|
||||||
get_remote_field, unicode_repr, unicode_to_repr, value_from_object
|
get_remote_field, is_simple_callable, unicode_repr, unicode_to_repr, value_from_object
|
||||||
)
|
)
|
||||||
from rest_framework.exceptions import ValidationError
|
from rest_framework.exceptions import ValidationError
|
||||||
from rest_framework.settings import api_settings
|
from rest_framework.settings import api_settings
|
||||||
|
@ -48,22 +48,6 @@ class empty:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def is_simple_callable(obj):
|
|
||||||
"""
|
|
||||||
True if the object is a callable that takes no arguments.
|
|
||||||
"""
|
|
||||||
function = inspect.isfunction(obj)
|
|
||||||
method = inspect.ismethod(obj)
|
|
||||||
|
|
||||||
if not (function or method):
|
|
||||||
return False
|
|
||||||
|
|
||||||
args, _, _, defaults = inspect.getargspec(obj)
|
|
||||||
len_args = len(args) if function else len(args) - 1
|
|
||||||
len_defaults = len(defaults) if defaults else 0
|
|
||||||
return len_args <= len_defaults
|
|
||||||
|
|
||||||
|
|
||||||
def get_attribute(instance, attrs):
|
def get_attribute(instance, attrs):
|
||||||
"""
|
"""
|
||||||
Similar to Python's built in `getattr(instance, attr)`,
|
Similar to Python's built in `getattr(instance, attr)`,
|
||||||
|
|
|
@ -14,9 +14,8 @@ from django.utils.encoding import smart_text
|
||||||
from django.utils.six.moves.urllib import parse as urlparse
|
from django.utils.six.moves.urllib import parse as urlparse
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from rest_framework.fields import (
|
from rest_framework.compat import is_simple_callable
|
||||||
Field, empty, get_attribute, is_simple_callable, iter_options
|
from rest_framework.fields import Field, empty, get_attribute, iter_options
|
||||||
)
|
|
||||||
from rest_framework.reverse import reverse
|
from rest_framework.reverse import reverse
|
||||||
from rest_framework.utils import html
|
from rest_framework.utils import html
|
||||||
|
|
||||||
|
|
0
tests/compat/__init__.py
Normal file
0
tests/compat/__init__.py
Normal file
21
tests/compat/compat_py35.py
Normal file
21
tests/compat/compat_py35.py
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
# for now, linting is done by python2.7, so for that file it should be disabled.
|
||||||
|
# flake8: noqa
|
||||||
|
|
||||||
|
|
||||||
|
class FunctionSimplicityCheckPy35Mixin:
|
||||||
|
def get_good_cases(self):
|
||||||
|
def annotated_simple() -> int:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def annotated_defaults(x: int = 0) -> int:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def kwonly_defaults(*, x=0):
|
||||||
|
pass
|
||||||
|
return super().get_good_cases() + (annotated_simple, annotated_defaults, kwonly_defaults)
|
||||||
|
|
||||||
|
def get_bad_cases(self):
|
||||||
|
def kwonly(*, x):
|
||||||
|
pass
|
||||||
|
|
||||||
|
return super().get_bad_cases() + (kwonly,)
|
52
tests/test_compat.py
Normal file
52
tests/test_compat.py
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from rest_framework.compat import is_simple_callable
|
||||||
|
|
||||||
|
|
||||||
|
class TestFunctionSimplicityCheck:
|
||||||
|
def get_good_cases(self):
|
||||||
|
def simple():
|
||||||
|
pass
|
||||||
|
|
||||||
|
def simple_with_default(x=0):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class SimpleMethods(object):
|
||||||
|
def simple(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def simple_with_default(self, x=0):
|
||||||
|
pass
|
||||||
|
|
||||||
|
return simple, simple_with_default, SimpleMethods().simple, SimpleMethods().simple_with_default
|
||||||
|
|
||||||
|
def get_bad_cases(self):
|
||||||
|
def positional(x):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def many_positional_and_defaults(x, y, z=0):
|
||||||
|
pass
|
||||||
|
|
||||||
|
nofunc = 0
|
||||||
|
|
||||||
|
class Callable:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return positional, many_positional_and_defaults, nofunc, Callable
|
||||||
|
|
||||||
|
def test_good_cases(self):
|
||||||
|
for case in self.get_good_cases():
|
||||||
|
assert is_simple_callable(case)
|
||||||
|
|
||||||
|
def test_bad_cases(self):
|
||||||
|
for case in self.get_bad_cases():
|
||||||
|
assert not is_simple_callable(case)
|
||||||
|
|
||||||
|
|
||||||
|
if sys.version_info >= (3, 5):
|
||||||
|
from tests.compat.compat_py35 import FunctionSimplicityCheckPy35Mixin
|
||||||
|
|
||||||
|
class TestFunctionSimplicityCheckPy35(FunctionSimplicityCheckPy35Mixin, TestFunctionSimplicityCheck):
|
||||||
|
pass
|
Loading…
Reference in New Issue
Block a user