diff --git a/rest_framework/fields.py b/rest_framework/fields.py index e48285005f..f75fcfe055 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -54,12 +54,17 @@ def is_simple_callable(obj): """ True if the object is a callable that takes no arguments. """ - if not callable(obj): + if not (inspect.isfunction(obj) or inspect.ismethod(obj)): return False sig = inspect.signature(obj) params = sig.parameters.values() - return all(param.default != param.empty for param in params) + return all( + param.kind == param.VAR_POSITIONAL or + param.kind == param.VAR_KEYWORD or + param.default != param.empty + for param in params + ) else: def is_simple_callable(obj): diff --git a/tests/test_fields.py b/tests/test_fields.py index 6fea249bac..92030e3ca9 100644 --- a/tests/test_fields.py +++ b/tests/test_fields.py @@ -37,6 +37,9 @@ def valid(self): def valid_kwargs(self, param='value'): pass + def valid_vargs_kwargs(self, *args, **kwargs): + pass + def invalid(self, param): pass @@ -45,11 +48,13 @@ def invalid(self, param): # unbound methods assert not is_simple_callable(Foo.valid) assert not is_simple_callable(Foo.valid_kwargs) + assert not is_simple_callable(Foo.valid_vargs_kwargs) assert not is_simple_callable(Foo.invalid) # bound methods assert is_simple_callable(Foo().valid) assert is_simple_callable(Foo().valid_kwargs) + assert is_simple_callable(Foo().valid_vargs_kwargs) assert not is_simple_callable(Foo().invalid) def test_function(self): @@ -59,13 +64,31 @@ def simple(): def valid(param='value', param2='value'): pass + def valid_vargs_kwargs(*args, **kwargs): + pass + def invalid(param, param2='value'): pass assert is_simple_callable(simple) assert is_simple_callable(valid) + assert is_simple_callable(valid_vargs_kwargs) assert not is_simple_callable(invalid) + def test_4602_regression(self): + from django.db import models + + class ChoiceModel(models.Model): + choice_field = models.CharField( + max_length=1, default='a', + choices=(('a', 'A'), ('b', 'B')), + ) + + class Meta: + app_label = 'tests' + + assert is_simple_callable(ChoiceModel().get_choice_field_display) + @unittest.skipUnless(typings, 'requires python 3.5') def test_type_annotation(self): # The annotation will otherwise raise a syntax error in python < 3.5
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: