Django 1.10 support. (#4158)

* Added TEMPLATES setting to tests
* Remove deprecated view-string in URL conf
* Replace 'urls = ...' in test classes with override_settings('ROOT_URLCONF=...')
* Refactor UsingURLPatterns to use override_settings(ROOT_URLCONF=...) style
* Get model managers and names in a version-compatible manner.
* Apply override_settings to a TestCase, not a mixin class
* Use '.callback' property instead of private attributes when inspecting urlpatterns
* Pass 'user' to template explicitly
* Correct sorting of import statements.
* Remove unused TEMPLATE_LOADERS setting, in favor of TEMPLATES.
* Remove code style issue
* BaseFilter test requires a concrete model
* Resolve tox.ini issues
* Resolve isort differences between local and tox environments
This commit is contained in:
Tom Christie 2016-06-01 15:31:00 +01:00
parent fe2aede18d
commit 994e1ba927
24 changed files with 114 additions and 123 deletions

View File

@ -58,6 +58,23 @@ def distinct(queryset, base):
return queryset.distinct() return queryset.distinct()
def get_names_and_managers(options):
if django.VERSION >= (1, 10):
# Django 1.10 onwards provides a `.managers` property on the Options.
return [
(manager.name, manager)
for manager
in options.managers
]
# For Django 1.8 and 1.9, use the three-tuple information provided
# by .concrete_managers and .abstract_managers
return [
(manager_info[1], manager_info[2])
for manager_info
in (options.concrete_managers + options.abstract_managers)
]
# contrib.postgres only supported from 1.8 onwards. # contrib.postgres only supported from 1.8 onwards.
try: try:
from django.contrib.postgres import fields as postgres_fields from django.contrib.postgres import fields as postgres_fields

View File

@ -635,6 +635,7 @@ class BrowsableAPIRenderer(BaseRenderer):
'view': view, 'view': view,
'request': request, 'request': request,
'response': response, 'response': response,
'user': request.user,
'description': self.get_description(view, response.status_code), 'description': self.get_description(view, response.status_code),
'name': self.get_name(view), 'name': self.get_name(view),
'version': VERSION, 'version': VERSION,

View File

@ -24,7 +24,7 @@ def apply_suffix_patterns(urlpatterns, suffix_pattern, suffix_required):
else: else:
# Regular URL pattern # Regular URL pattern
regex = urlpattern.regex.pattern.rstrip('$').rstrip('/') + suffix_pattern regex = urlpattern.regex.pattern.rstrip('$').rstrip('/') + suffix_pattern
view = urlpattern._callback or urlpattern._callback_str view = urlpattern.callback
kwargs = urlpattern.default_args kwargs = urlpattern.default_args
name = urlpattern.name name = urlpattern.name
# Add in both the existing and the new urlpattern # Add in both the existing and the new urlpattern

View File

@ -10,15 +10,15 @@ from django.db import models
from django.utils.encoding import force_text from django.utils.encoding import force_text
from django.utils.functional import Promise from django.utils.functional import Promise
from rest_framework.compat import unicode_repr from rest_framework.compat import get_names_and_managers, unicode_repr
def manager_repr(value): def manager_repr(value):
model = value.model model = value.model
opts = model._meta opts = model._meta
for _, name, manager in opts.concrete_managers + opts.abstract_managers: for manager_name, manager_instance in get_names_and_managers(opts):
if manager == value: if manager_instance == value:
return '%s.%s.all()' % (model._meta.object_name, name) return '%s.%s.all()' % (model._meta.object_name, manager_name)
return repr(value) return repr(value)

View File

@ -14,7 +14,7 @@ PYTEST_ARGS = {
FLAKE8_ARGS = ['rest_framework', 'tests', '--ignore=E501'] FLAKE8_ARGS = ['rest_framework', 'tests', '--ignore=E501']
ISORT_ARGS = ['--recursive', '--check-only', 'rest_framework', 'tests'] ISORT_ARGS = ['--recursive', '--check-only', '-p', 'tests', 'rest_framework', 'tests']
sys.path.append(os.path.dirname(__file__)) sys.path.append(os.path.dirname(__file__))

View File

@ -1,16 +1,14 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.test import TestCase from django.test import TestCase, override_settings
from rest_framework.test import APIClient from rest_framework.test import APIClient
@override_settings(ROOT_URLCONF='tests.browsable_api.auth_urls')
class DropdownWithAuthTests(TestCase): class DropdownWithAuthTests(TestCase):
"""Tests correct dropdown behaviour with Auth views enabled.""" """Tests correct dropdown behaviour with Auth views enabled."""
urls = 'tests.browsable_api.auth_urls'
def setUp(self): def setUp(self):
self.client = APIClient(enforce_csrf_checks=True) self.client = APIClient(enforce_csrf_checks=True)
self.username = 'john' self.username = 'john'
@ -40,11 +38,9 @@ class DropdownWithAuthTests(TestCase):
self.assertContains(response, '>Log in<') self.assertContains(response, '>Log in<')
@override_settings(ROOT_URLCONF='tests.browsable_api.no_auth_urls')
class NoDropdownWithoutAuthTests(TestCase): class NoDropdownWithoutAuthTests(TestCase):
"""Tests correct dropdown behaviour with Auth views NOT enabled.""" """Tests correct dropdown behaviour with Auth views NOT enabled."""
urls = 'tests.browsable_api.no_auth_urls'
def setUp(self): def setUp(self):
self.client = APIClient(enforce_csrf_checks=True) self.client = APIClient(enforce_csrf_checks=True)
self.username = 'john' self.username = 'john'

View File

@ -6,9 +6,8 @@ from rest_framework.views import APIView
class MockView(APIView): class MockView(APIView):
authentication_classes = (authentication.SessionAuthentication,) authentication_classes = (authentication.SessionAuthentication,)
renderer_classes = (renderers.BrowsableAPIRenderer,) renderer_classes = (renderers.BrowsableAPIRenderer, renderers.JSONRenderer)
def get(self, request): def get(self, request):
return Response({'a': 1, 'b': 2, 'c': 3}) return Response({'a': 1, 'b': 2, 'c': 3})

View File

@ -3,18 +3,24 @@ def pytest_configure():
settings.configure( settings.configure(
DEBUG_PROPAGATE_EXCEPTIONS=True, DEBUG_PROPAGATE_EXCEPTIONS=True,
DATABASES={'default': {'ENGINE': 'django.db.backends.sqlite3', DATABASES={
'NAME': ':memory:'}}, 'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': ':memory:'
}
},
SITE_ID=1, SITE_ID=1,
SECRET_KEY='not very secret in tests', SECRET_KEY='not very secret in tests',
USE_I18N=True, USE_I18N=True,
USE_L10N=True, USE_L10N=True,
STATIC_URL='/static/', STATIC_URL='/static/',
ROOT_URLCONF='tests.urls', ROOT_URLCONF='tests.urls',
TEMPLATE_LOADERS=( TEMPLATES=[
'django.template.loaders.filesystem.Loader', {
'django.template.loaders.app_directories.Loader', 'BACKEND': 'django.template.backends.django.DjangoTemplates',
), 'APP_DIRS': True,
},
],
MIDDLEWARE_CLASSES=( MIDDLEWARE_CLASSES=(
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
@ -27,7 +33,6 @@ def pytest_configure():
'django.contrib.sessions', 'django.contrib.sessions',
'django.contrib.sites', 'django.contrib.sites',
'django.contrib.staticfiles', 'django.contrib.staticfiles',
'rest_framework', 'rest_framework',
'rest_framework.authtoken', 'rest_framework.authtoken',
'tests', 'tests',

View File

@ -27,9 +27,6 @@ class BasicModel(RESTFrameworkModel):
class BaseFilterableItem(RESTFrameworkModel): class BaseFilterableItem(RESTFrameworkModel):
text = models.CharField(max_length=100) text = models.CharField(max_length=100)
class Meta:
abstract = True
class FilterableItem(BaseFilterableItem): class FilterableItem(BaseFilterableItem):
decimal = models.DecimalField(max_digits=4, decimal_places=2) decimal = models.DecimalField(max_digits=4, decimal_places=2)

View File

@ -8,7 +8,7 @@ from django.conf.urls import include, url
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.db import models from django.db import models
from django.http import HttpResponse from django.http import HttpResponse
from django.test import TestCase from django.test import TestCase, override_settings
from django.utils import six from django.utils import six
from rest_framework import ( from rest_framework import (
@ -19,6 +19,7 @@ from rest_framework.authentication import (
TokenAuthentication TokenAuthentication
) )
from rest_framework.authtoken.models import Token from rest_framework.authtoken.models import Token
from rest_framework.authtoken.views import obtain_auth_token
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.test import APIClient, APIRequestFactory from rest_framework.test import APIClient, APIRequestFactory
from rest_framework.views import APIView from rest_framework.views import APIView
@ -75,15 +76,14 @@ urlpatterns = [
authentication_classes=[CustomKeywordTokenAuthentication] authentication_classes=[CustomKeywordTokenAuthentication]
) )
), ),
url(r'^auth-token/$', 'rest_framework.authtoken.views.obtain_auth_token'), url(r'^auth-token/$', obtain_auth_token),
url(r'^auth/', include('rest_framework.urls', namespace='rest_framework')), url(r'^auth/', include('rest_framework.urls', namespace='rest_framework')),
] ]
@override_settings(ROOT_URLCONF='tests.test_authentication')
class BasicAuthTests(TestCase): class BasicAuthTests(TestCase):
"""Basic authentication""" """Basic authentication"""
urls = 'tests.test_authentication'
def setUp(self): def setUp(self):
self.csrf_client = APIClient(enforce_csrf_checks=True) self.csrf_client = APIClient(enforce_csrf_checks=True)
self.username = 'john' self.username = 'john'
@ -151,10 +151,9 @@ class BasicAuthTests(TestCase):
self.assertEqual(response['WWW-Authenticate'], 'Basic realm="api"') self.assertEqual(response['WWW-Authenticate'], 'Basic realm="api"')
@override_settings(ROOT_URLCONF='tests.test_authentication')
class SessionAuthTests(TestCase): class SessionAuthTests(TestCase):
"""User session authentication""" """User session authentication"""
urls = 'tests.test_authentication'
def setUp(self): def setUp(self):
self.csrf_client = APIClient(enforce_csrf_checks=True) self.csrf_client = APIClient(enforce_csrf_checks=True)
self.non_csrf_client = APIClient(enforce_csrf_checks=False) self.non_csrf_client = APIClient(enforce_csrf_checks=False)
@ -223,7 +222,6 @@ class SessionAuthTests(TestCase):
class BaseTokenAuthTests(object): class BaseTokenAuthTests(object):
"""Token authentication""" """Token authentication"""
urls = 'tests.test_authentication'
model = None model = None
path = None path = None
header_prefix = 'Token ' header_prefix = 'Token '
@ -311,6 +309,7 @@ class BaseTokenAuthTests(object):
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
@override_settings(ROOT_URLCONF='tests.test_authentication')
class TokenAuthTests(BaseTokenAuthTests, TestCase): class TokenAuthTests(BaseTokenAuthTests, TestCase):
model = Token model = Token
path = '/token/' path = '/token/'
@ -367,11 +366,13 @@ class TokenAuthTests(BaseTokenAuthTests, TestCase):
self.assertEqual(response.data['token'], self.key) self.assertEqual(response.data['token'], self.key)
@override_settings(ROOT_URLCONF='tests.test_authentication')
class CustomTokenAuthTests(BaseTokenAuthTests, TestCase): class CustomTokenAuthTests(BaseTokenAuthTests, TestCase):
model = CustomToken model = CustomToken
path = '/customtoken/' path = '/customtoken/'
@override_settings(ROOT_URLCONF='tests.test_authentication')
class CustomKeywordTokenAuthTests(BaseTokenAuthTests, TestCase): class CustomKeywordTokenAuthTests(BaseTokenAuthTests, TestCase):
model = Token model = Token
path = '/customkeywordtoken/' path = '/customkeywordtoken/'

View File

@ -274,12 +274,11 @@ class IntegrationTestFiltering(CommonFilteringTestCase):
self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.status_code, status.HTTP_200_OK)
@override_settings(ROOT_URLCONF='tests.test_filters')
class IntegrationTestDetailFiltering(CommonFilteringTestCase): class IntegrationTestDetailFiltering(CommonFilteringTestCase):
""" """
Integration tests for filtered detail views. Integration tests for filtered detail views.
""" """
urls = 'tests.test_filters'
def _get_url(self, item): def _get_url(self, item):
return reverse('detail-view', kwargs=dict(pk=item.pk)) return reverse('detail-view', kwargs=dict(pk=item.pk))

View File

@ -5,7 +5,7 @@ from django.conf.urls import url
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.http import Http404 from django.http import Http404
from django.template import Template, TemplateDoesNotExist from django.template import Template, TemplateDoesNotExist
from django.test import TestCase from django.test import TestCase, override_settings
from django.utils import six from django.utils import six
from rest_framework import status from rest_framework import status
@ -43,9 +43,8 @@ urlpatterns = [
] ]
@override_settings(ROOT_URLCONF='tests.test_htmlrenderer')
class TemplateHTMLRendererTests(TestCase): class TemplateHTMLRendererTests(TestCase):
urls = 'tests.test_htmlrenderer'
def setUp(self): def setUp(self):
""" """
Monkeypatch get_template Monkeypatch get_template
@ -89,9 +88,8 @@ class TemplateHTMLRendererTests(TestCase):
self.assertEqual(response['Content-Type'], 'text/html; charset=utf-8') self.assertEqual(response['Content-Type'], 'text/html; charset=utf-8')
@override_settings(ROOT_URLCONF='tests.test_htmlrenderer')
class TemplateHTMLRendererExceptionTests(TestCase): class TemplateHTMLRendererExceptionTests(TestCase):
urls = 'tests.test_htmlrenderer'
def setUp(self): def setUp(self):
""" """
Monkeypatch get_template Monkeypatch get_template

View File

@ -1,6 +1,6 @@
from django.conf.urls import url from django.conf.urls import url
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.test import override_settings
from rest_framework.authentication import TokenAuthentication from rest_framework.authentication import TokenAuthentication
from rest_framework.authtoken.models import Token from rest_framework.authtoken.models import Token
@ -20,10 +20,8 @@ class MyMiddleware(object):
return response return response
@override_settings(ROOT_URLCONF='tests.test_middleware')
class TestMiddleware(APITestCase): class TestMiddleware(APITestCase):
urls = 'tests.test_middleware'
def test_middleware_can_access_user_when_processing_response(self): def test_middleware_can_access_user_when_processing_response(self):
user = User.objects.create_user('john', 'john@example.com', 'password') user = User.objects.create_user('john', 'john@example.com', 'password')
key = 'abcd1234' key = 'abcd1234'

View File

@ -1,7 +1,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django.conf.urls import url from django.conf.urls import url
from django.test import TestCase from django.test import TestCase, override_settings
from rest_framework import serializers from rest_framework import serializers
from rest_framework.test import APIRequestFactory from rest_framework.test import APIRequestFactory
@ -71,10 +71,8 @@ class NullableOneToOneTargetSerializer(serializers.HyperlinkedModelSerializer):
# TODO: Add test that .data cannot be accessed prior to .is_valid # TODO: Add test that .data cannot be accessed prior to .is_valid
@override_settings(ROOT_URLCONF='tests.test_relations_hyperlink')
class HyperlinkedManyToManyTests(TestCase): class HyperlinkedManyToManyTests(TestCase):
urls = 'tests.test_relations_hyperlink'
def setUp(self): def setUp(self):
for idx in range(1, 4): for idx in range(1, 4):
target = ManyToManyTarget(name='target-%d' % idx) target = ManyToManyTarget(name='target-%d' % idx)
@ -188,9 +186,8 @@ class HyperlinkedManyToManyTests(TestCase):
self.assertEqual(serializer.data, expected) self.assertEqual(serializer.data, expected)
@override_settings(ROOT_URLCONF='tests.test_relations_hyperlink')
class HyperlinkedForeignKeyTests(TestCase): class HyperlinkedForeignKeyTests(TestCase):
urls = 'tests.test_relations_hyperlink'
def setUp(self): def setUp(self):
target = ForeignKeyTarget(name='target-1') target = ForeignKeyTarget(name='target-1')
target.save() target.save()
@ -318,9 +315,8 @@ class HyperlinkedForeignKeyTests(TestCase):
self.assertEqual(serializer.errors, {'target': ['This field may not be null.']}) self.assertEqual(serializer.errors, {'target': ['This field may not be null.']})
@override_settings(ROOT_URLCONF='tests.test_relations_hyperlink')
class HyperlinkedNullableForeignKeyTests(TestCase): class HyperlinkedNullableForeignKeyTests(TestCase):
urls = 'tests.test_relations_hyperlink'
def setUp(self): def setUp(self):
target = ForeignKeyTarget(name='target-1') target = ForeignKeyTarget(name='target-1')
target.save() target.save()
@ -425,9 +421,8 @@ class HyperlinkedNullableForeignKeyTests(TestCase):
self.assertEqual(serializer.data, expected) self.assertEqual(serializer.data, expected)
@override_settings(ROOT_URLCONF='tests.test_relations_hyperlink')
class HyperlinkedNullableOneToOneTests(TestCase): class HyperlinkedNullableOneToOneTests(TestCase):
urls = 'tests.test_relations_hyperlink'
def setUp(self): def setUp(self):
target = OneToOneTarget(name='target-1') target = OneToOneTarget(name='target-1')
target.save() target.save()

View File

@ -8,7 +8,7 @@ from collections import MutableMapping, OrderedDict
from django.conf.urls import include, url from django.conf.urls import include, url
from django.core.cache import cache from django.core.cache import cache
from django.db import models from django.db import models
from django.test import TestCase from django.test import TestCase, override_settings
from django.utils import six from django.utils import six
from django.utils.safestring import SafeText from django.utils.safestring import SafeText
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -148,13 +148,11 @@ class DocumentingRendererTests(TestCase):
self.assertContains(response, '>PATCH<') self.assertContains(response, '>PATCH<')
@override_settings(ROOT_URLCONF='tests.test_renderers')
class RendererEndToEndTests(TestCase): class RendererEndToEndTests(TestCase):
""" """
End-to-end testing of renderers using an RendererMixin on a generic view. End-to-end testing of renderers using an RendererMixin on a generic view.
""" """
urls = 'tests.test_renderers'
def test_default_renderer_serializes_content(self): def test_default_renderer_serializes_content(self):
"""If the Accept header is not set the default renderer should serialize the response.""" """If the Accept header is not set the default renderer should serialize the response."""
resp = self.client.get('/') resp = self.client.get('/')
@ -397,13 +395,11 @@ class AsciiJSONRendererTests(TestCase):
# Tests for caching issue, #346 # Tests for caching issue, #346
@override_settings(ROOT_URLCONF='tests.test_renderers')
class CacheRenderTest(TestCase): class CacheRenderTest(TestCase):
""" """
Tests specific to caching responses Tests specific to caching responses
""" """
urls = 'tests.test_renderers'
def test_head_caching(self): def test_head_caching(self):
""" """
Test caching of HEAD requests Test caching of HEAD requests

View File

@ -7,7 +7,7 @@ from django.conf.urls import url
from django.contrib.auth import authenticate, login, logout from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.contrib.sessions.middleware import SessionMiddleware from django.contrib.sessions.middleware import SessionMiddleware
from django.test import TestCase from django.test import TestCase, override_settings
from django.utils import six from django.utils import six
from rest_framework import status from rest_framework import status
@ -113,9 +113,8 @@ urlpatterns = [
] ]
@override_settings(ROOT_URLCONF='tests.test_request')
class TestContentParsingWithAuthentication(TestCase): class TestContentParsingWithAuthentication(TestCase):
urls = 'tests.test_request'
def setUp(self): def setUp(self):
self.csrf_client = APIClient(enforce_csrf_checks=True) self.csrf_client = APIClient(enforce_csrf_checks=True)
self.username = 'john' self.username = 'john'

View File

@ -1,7 +1,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django.conf.urls import include, url from django.conf.urls import include, url
from django.test import TestCase from django.test import TestCase, override_settings
from django.utils import six from django.utils import six
from rest_framework import generics, routers, serializers, status, viewsets from rest_framework import generics, routers, serializers, status, viewsets
@ -131,13 +131,11 @@ urlpatterns = [
# TODO: Clean tests bellow - remove duplicates with above, better unit testing, ... # TODO: Clean tests bellow - remove duplicates with above, better unit testing, ...
@override_settings(ROOT_URLCONF='tests.test_response')
class RendererIntegrationTests(TestCase): class RendererIntegrationTests(TestCase):
""" """
End-to-end testing of renderers using an ResponseMixin on a generic view. End-to-end testing of renderers using an ResponseMixin on a generic view.
""" """
urls = 'tests.test_response'
def test_default_renderer_serializes_content(self): def test_default_renderer_serializes_content(self):
"""If the Accept header is not set the default renderer should serialize the response.""" """If the Accept header is not set the default renderer should serialize the response."""
resp = self.client.get('/') resp = self.client.get('/')
@ -201,9 +199,8 @@ class RendererIntegrationTests(TestCase):
self.assertEqual(resp.status_code, DUMMYSTATUS) self.assertEqual(resp.status_code, DUMMYSTATUS)
@override_settings(ROOT_URLCONF='tests.test_response')
class UnsupportedMediaTypeTests(TestCase): class UnsupportedMediaTypeTests(TestCase):
urls = 'tests.test_response'
def test_should_allow_posting_json(self): def test_should_allow_posting_json(self):
response = self.client.post('/json', data='{"test": 123}', content_type='application/json') response = self.client.post('/json', data='{"test": 123}', content_type='application/json')
@ -220,12 +217,11 @@ class UnsupportedMediaTypeTests(TestCase):
self.assertEqual(response.status_code, 415) self.assertEqual(response.status_code, 415)
@override_settings(ROOT_URLCONF='tests.test_response')
class Issue122Tests(TestCase): class Issue122Tests(TestCase):
""" """
Tests that covers #122. Tests that covers #122.
""" """
urls = 'tests.test_response'
def test_only_html_renderer(self): def test_only_html_renderer(self):
""" """
Test if no infinite recursion occurs. Test if no infinite recursion occurs.
@ -239,13 +235,11 @@ class Issue122Tests(TestCase):
self.client.get('/html1') self.client.get('/html1')
@override_settings(ROOT_URLCONF='tests.test_response')
class Issue467Tests(TestCase): class Issue467Tests(TestCase):
""" """
Tests for #467 Tests for #467
""" """
urls = 'tests.test_response'
def test_form_has_label_and_help_text(self): def test_form_has_label_and_help_text(self):
resp = self.client.get('/html_new_model') resp = self.client.get('/html_new_model')
self.assertEqual(resp['Content-Type'], 'text/html; charset=utf-8') self.assertEqual(resp['Content-Type'], 'text/html; charset=utf-8')
@ -253,13 +247,11 @@ class Issue467Tests(TestCase):
# self.assertContains(resp, 'Text description.') # self.assertContains(resp, 'Text description.')
@override_settings(ROOT_URLCONF='tests.test_response')
class Issue807Tests(TestCase): class Issue807Tests(TestCase):
""" """
Covers #807 Covers #807
""" """
urls = 'tests.test_response'
def test_does_not_append_charset_by_default(self): def test_does_not_append_charset_by_default(self):
""" """
Renderers don't include a charset unless set explicitly. Renderers don't include a charset unless set explicitly.

View File

@ -2,7 +2,7 @@ from __future__ import unicode_literals
from django.conf.urls import url from django.conf.urls import url
from django.core.urlresolvers import NoReverseMatch from django.core.urlresolvers import NoReverseMatch
from django.test import TestCase from django.test import TestCase, override_settings
from rest_framework.reverse import reverse from rest_framework.reverse import reverse
from rest_framework.test import APIRequestFactory from rest_framework.test import APIRequestFactory
@ -30,12 +30,11 @@ class MockVersioningScheme(object):
return 'http://scheme-reversed/view' return 'http://scheme-reversed/view'
@override_settings(ROOT_URLCONF='tests.test_reverse')
class ReverseTests(TestCase): class ReverseTests(TestCase):
""" """
Tests for fully qualified URLs when using `reverse`. Tests for fully qualified URLs when using `reverse`.
""" """
urls = 'tests.test_reverse'
def test_reversed_urls_are_fully_qualified(self): def test_reversed_urls_are_fully_qualified(self):
request = factory.get('/view') request = factory.get('/view')
url = reverse('view', request=request) url = reverse('view', request=request)

View File

@ -5,7 +5,7 @@ from collections import namedtuple
from django.conf.urls import include, url from django.conf.urls import include, url
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.db import models from django.db import models
from django.test import TestCase from django.test import TestCase, override_settings
from rest_framework import permissions, serializers, viewsets from rest_framework import permissions, serializers, viewsets
from rest_framework.decorators import detail_route, list_route from rest_framework.decorators import detail_route, list_route
@ -113,9 +113,8 @@ class TestSimpleRouter(TestCase):
self.assertEqual(route.mapping[method], endpoint) self.assertEqual(route.mapping[method], endpoint)
@override_settings(ROOT_URLCONF='tests.test_routers')
class TestRootView(TestCase): class TestRootView(TestCase):
urls = 'tests.test_routers'
def test_retrieve_namespaced_root(self): def test_retrieve_namespaced_root(self):
response = self.client.get('/namespaced/') response = self.client.get('/namespaced/')
self.assertEqual( self.assertEqual(
@ -135,12 +134,11 @@ class TestRootView(TestCase):
) )
@override_settings(ROOT_URLCONF='tests.test_routers')
class TestCustomLookupFields(TestCase): class TestCustomLookupFields(TestCase):
""" """
Ensure that custom lookup fields are correctly routed. Ensure that custom lookup fields are correctly routed.
""" """
urls = 'tests.test_routers'
def setUp(self): def setUp(self):
RouterTestModel.objects.create(uuid='123', text='foo bar') RouterTestModel.objects.create(uuid='123', text='foo bar')
@ -191,14 +189,13 @@ class TestLookupValueRegex(TestCase):
self.assertEqual(expected[idx], self.urls[idx].regex.pattern) self.assertEqual(expected[idx], self.urls[idx].regex.pattern)
@override_settings(ROOT_URLCONF='tests.test_routers')
class TestLookupUrlKwargs(TestCase): class TestLookupUrlKwargs(TestCase):
""" """
Ensure the router honors lookup_url_kwarg. Ensure the router honors lookup_url_kwarg.
Setup a deep lookup_field, but map it to a simple URL kwarg. Setup a deep lookup_field, but map it to a simple URL kwarg.
""" """
urls = 'tests.test_routers'
def setUp(self): def setUp(self):
RouterTestModel.objects.create(uuid='123', text='foo bar') RouterTestModel.objects.create(uuid='123', text='foo bar')

View File

@ -6,7 +6,7 @@ from io import BytesIO
from django.conf.urls import url from django.conf.urls import url
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.shortcuts import redirect from django.shortcuts import redirect
from django.test import TestCase from django.test import TestCase, override_settings
from rest_framework.decorators import api_view from rest_framework.decorators import api_view
from rest_framework.response import Response from rest_framework.response import Response
@ -44,9 +44,8 @@ urlpatterns = [
] ]
@override_settings(ROOT_URLCONF='tests.test_testing')
class TestAPITestClient(TestCase): class TestAPITestClient(TestCase):
urls = 'tests.test_testing'
def setUp(self): def setUp(self):
self.client = APIClient() self.client = APIClient()

View File

@ -2,7 +2,7 @@ from __future__ import unicode_literals
from django.conf.urls import url from django.conf.urls import url
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.test import TestCase from django.test import TestCase, override_settings
from django.utils import six from django.utils import six
import rest_framework.utils.model_meta import rest_framework.utils.model_meta
@ -47,12 +47,11 @@ urlpatterns = [
] ]
@override_settings(ROOT_URLCONF='tests.test_utils')
class BreadcrumbTests(TestCase): class BreadcrumbTests(TestCase):
""" """
Tests the breadcrumb functionality used by the HTML renderer. Tests the breadcrumb functionality used by the HTML renderer.
""" """
urls = 'tests.test_utils'
def test_root_breadcrumbs(self): def test_root_breadcrumbs(self):
url = '/' url = '/'
self.assertEqual( self.assertEqual(

View File

@ -1,5 +1,6 @@
import pytest import pytest
from django.conf.urls import include, url from django.conf.urls import include, url
from django.test import override_settings
from rest_framework import serializers, status, versioning from rest_framework import serializers, status, versioning
from rest_framework.decorators import APIView from rest_framework.decorators import APIView
@ -9,7 +10,28 @@ from rest_framework.reverse import reverse
from rest_framework.test import APIRequestFactory, APITestCase from rest_framework.test import APIRequestFactory, APITestCase
from rest_framework.versioning import NamespaceVersioning from rest_framework.versioning import NamespaceVersioning
from .utils import UsingURLPatterns
@override_settings(ROOT_URLCONF='tests.test_versioning')
class URLPatternsTestCase(APITestCase):
"""
Isolates URL patterns used during testing on the test class itself.
For example:
class MyTestCase(URLPatternsTestCase):
urlpatterns = [
...
]
def test_something(self):
...
"""
def setUp(self):
global urlpatterns
urlpatterns = self.urlpatterns
def tearDown(self):
global urlpatterns
urlpatterns = []
class RequestVersionView(APIView): class RequestVersionView(APIView):
@ -120,7 +142,7 @@ class TestRequestVersion:
assert response.data == {'version': None} assert response.data == {'version': None}
class TestURLReversing(UsingURLPatterns, APITestCase): class TestURLReversing(URLPatternsTestCase):
included = [ included = [
url(r'^namespaced/$', dummy_view, name='another'), url(r'^namespaced/$', dummy_view, name='another'),
url(r'^example/(?P<pk>\d+)/$', dummy_pk_view, name='example-detail') url(r'^example/(?P<pk>\d+)/$', dummy_pk_view, name='example-detail')
@ -238,7 +260,7 @@ class TestInvalidVersion:
assert response.status_code == status.HTTP_404_NOT_FOUND assert response.status_code == status.HTTP_404_NOT_FOUND
class TestHyperlinkedRelatedField(UsingURLPatterns, APITestCase): class TestHyperlinkedRelatedField(URLPatternsTestCase):
included = [ included = [
url(r'^namespaced/(?P<pk>\d+)/$', dummy_pk_view, name='namespaced'), url(r'^namespaced/(?P<pk>\d+)/$', dummy_pk_view, name='namespaced'),
] ]
@ -270,7 +292,7 @@ class TestHyperlinkedRelatedField(UsingURLPatterns, APITestCase):
self.field.to_internal_value('/v2/namespaced/3/') self.field.to_internal_value('/v2/namespaced/3/')
class TestNamespaceVersioningHyperlinkedRelatedFieldScheme(UsingURLPatterns, APITestCase): class TestNamespaceVersioningHyperlinkedRelatedFieldScheme(URLPatternsTestCase):
included = [ included = [
url(r'^namespaced/(?P<pk>\d+)/$', dummy_pk_view, name='namespaced'), url(r'^namespaced/(?P<pk>\d+)/$', dummy_pk_view, name='namespaced'),
] ]

View File

@ -2,30 +2,6 @@ from django.core.exceptions import ObjectDoesNotExist
from django.core.urlresolvers import NoReverseMatch from django.core.urlresolvers import NoReverseMatch
class UsingURLPatterns(object):
"""
Isolates URL patterns used during testing on the test class itself.
For example:
class MyTestCase(UsingURLPatterns, TestCase):
urlpatterns = [
...
]
def test_something(self):
...
"""
urls = __name__
def setUp(self):
global urlpatterns
urlpatterns = self.urlpatterns
def tearDown(self):
global urlpatterns
urlpatterns = []
class MockObject(object): class MockObject(object):
def __init__(self, **kwargs): def __init__(self, **kwargs):
self._kwargs = kwargs self._kwargs = kwargs

10
tox.ini
View File

@ -5,8 +5,8 @@ addopts=--tb=short
envlist = envlist =
py27-{lint,docs}, py27-{lint,docs},
{py27,py32,py33,py34,py35}-django18, {py27,py32,py33,py34,py35}-django18,
{py27,py34,py35}-django{19} {py27,py34,py35}-django19,
{py27,py34,py35}-django{110} {py27,py34,py35}-django110
[testenv] [testenv]
commands = ./runtests.py --fast {posargs} --coverage -rw commands = ./runtests.py --fast {posargs} --coverage -rw
@ -19,6 +19,12 @@ deps =
django110: Django==1.10a1 django110: Django==1.10a1
-rrequirements/requirements-testing.txt -rrequirements/requirements-testing.txt
-rrequirements/requirements-optionals.txt -rrequirements/requirements-optionals.txt
basepython =
py35: python3.5
py34: python3.4
py33: python3.3
py32: python3.2
py27: python2.7
[testenv:py27-lint] [testenv:py27-lint]
commands = ./runtests.py --lintonly commands = ./runtests.py --lintonly