diff --git a/rest_framework/authtoken/models.py b/rest_framework/authtoken/models.py index 4da2aa625..7f5a75a3d 100644 --- a/rest_framework/authtoken/models.py +++ b/rest_framework/authtoken/models.py @@ -19,8 +19,8 @@ class Token(models.Model): return super(Token, self).save(*args, **kwargs) def generate_key(self): - unique = str(uuid.uuid4()) - return hmac.new(unique, digestmod=sha1).hexdigest() + unique = uuid.uuid4() + return hmac.new(unique.bytes, digestmod=sha1).hexdigest() def __unicode__(self): return self.key diff --git a/rest_framework/response.py b/rest_framework/response.py index be78c43ae..cad95611c 100644 --- a/rest_framework/response.py +++ b/rest_framework/response.py @@ -1,3 +1,5 @@ +import six + from django.core.handlers.wsgi import STATUS_CODE_TEXT from django.template.response import SimpleTemplateResponse @@ -22,9 +24,9 @@ class Response(SimpleTemplateResponse): self.data = data self.template_name = template_name self.exception = exception - + if headers: - for name,value in headers.iteritems(): + for name, value in six.iteritems(headers): self[name] = value @property diff --git a/rest_framework/tests/authentication.py b/rest_framework/tests/authentication.py index 709058088..33ef03126 100644 --- a/rest_framework/tests/authentication.py +++ b/rest_framework/tests/authentication.py @@ -157,29 +157,29 @@ class TokenAuthTests(TestCase): def test_token_login_json(self): """Ensure token login view using JSON POST works.""" client = Client(enforce_csrf_checks=True) - response = client.post('/auth-token/login/', + response = client.post('/auth-token/login/', json.dumps({'username': self.username, 'password': self.password}), 'application/json') self.assertEqual(response.status_code, 200) - self.assertEqual(json.loads(response.content)['token'], self.key) + self.assertEqual(json.loads(response.content.decode('ascii'))['token'], self.key) def test_token_login_json_bad_creds(self): """Ensure token login view using JSON POST fails if bad credentials are used.""" client = Client(enforce_csrf_checks=True) - response = client.post('/auth-token/login/', + response = client.post('/auth-token/login/', json.dumps({'username': self.username, 'password': "badpass"}), 'application/json') self.assertEqual(response.status_code, 400) def test_token_login_json_missing_fields(self): """Ensure token login view using JSON POST fails if missing fields.""" client = Client(enforce_csrf_checks=True) - response = client.post('/auth-token/login/', + response = client.post('/auth-token/login/', json.dumps({'username': self.username}), 'application/json') self.assertEqual(response.status_code, 400) def test_token_login_form(self): """Ensure token login view using form POST works.""" client = Client(enforce_csrf_checks=True) - response = client.post('/auth-token/login/', + response = client.post('/auth-token/login/', {'username': self.username, 'password': self.password}) self.assertEqual(response.status_code, 200) - self.assertEqual(json.loads(response.content)['token'], self.key) + self.assertEqual(json.loads(response.content.decode('ascii'))['token'], self.key) diff --git a/rest_framework/tests/files.py b/rest_framework/tests/files.py index a69695ca0..42e8ed5fc 100644 --- a/rest_framework/tests/files.py +++ b/rest_framework/tests/files.py @@ -1,6 +1,7 @@ from rest_framework.compat import BytesIO import datetime +import six from django.test import TestCase @@ -29,7 +30,7 @@ class FileSerializerTests(TestCase): def test_create(self): now = datetime.datetime.now() - file = BytesIO(b'stuff') + file = BytesIO(six.b('stuff')) file.name = 'stuff.txt' file.size = len(file.getvalue()) serializer = UploadedFileSerializer(data={'created': now}, files={'file': file}) diff --git a/rest_framework/tests/generics.py b/rest_framework/tests/generics.py index e4a4db806..b6d218473 100644 --- a/rest_framework/tests/generics.py +++ b/rest_framework/tests/generics.py @@ -1,5 +1,7 @@ from __future__ import unicode_literals +import six + from django.test import TestCase from django.test.client import RequestFactory from django.utils import simplejson as json @@ -189,7 +191,7 @@ class TestInstanceView(TestCase): request = factory.delete('/1') response = self.view(request, pk=1).render() self.assertEquals(response.status_code, status.HTTP_204_NO_CONTENT) - self.assertEquals(response.content, '') + self.assertEquals(response.content, six.b('')) ids = [obj.id for obj in self.objects.all()] self.assertEquals(ids, [2, 3]) diff --git a/rest_framework/tests/htmlrenderer.py b/rest_framework/tests/htmlrenderer.py index 4caed59ee..cef3ffe9d 100644 --- a/rest_framework/tests/htmlrenderer.py +++ b/rest_framework/tests/htmlrenderer.py @@ -1,3 +1,5 @@ +import six + from django.core.exceptions import PermissionDenied from django.conf.urls.defaults import patterns, url from django.http import Http404 @@ -68,13 +70,13 @@ class TemplateHTMLRendererTests(TestCase): def test_not_found_html_view(self): response = self.client.get('/not_found') self.assertEquals(response.status_code, 404) - self.assertEquals(response.content, "404 Not Found") + self.assertEquals(response.content, six.b("404 Not Found")) self.assertEquals(response['Content-Type'], 'text/html') def test_permission_denied_html_view(self): response = self.client.get('/permission_denied') self.assertEquals(response.status_code, 403) - self.assertEquals(response.content, "403 Forbidden") + self.assertEquals(response.content, six.b("403 Forbidden")) self.assertEquals(response['Content-Type'], 'text/html') @@ -105,11 +107,11 @@ class TemplateHTMLRendererExceptionTests(TestCase): def test_not_found_html_view_with_template(self): response = self.client.get('/not_found') self.assertEquals(response.status_code, 404) - self.assertEquals(response.content, "404: Not found") + self.assertEquals(response.content, six.b("404: Not found")) self.assertEquals(response['Content-Type'], 'text/html') def test_permission_denied_html_view_with_template(self): response = self.client.get('/permission_denied') self.assertEquals(response.status_code, 403) - self.assertEquals(response.content, "403: Permission denied") + self.assertEquals(response.content, six.b("403: Permission denied")) self.assertEquals(response['Content-Type'], 'text/html') diff --git a/rest_framework/tests/renderers.py b/rest_framework/tests/renderers.py index a2140361e..79ace78d6 100644 --- a/rest_framework/tests/renderers.py +++ b/rest_framework/tests/renderers.py @@ -1,5 +1,6 @@ import pickle import re +import six from django.conf.urls.defaults import patterns, url, include from django.core.cache import cache @@ -23,8 +24,8 @@ from decimal import Decimal DUMMYSTATUS = status.HTTP_200_OK DUMMYCONTENT = 'dummycontent' -RENDERER_A_SERIALIZER = lambda x: 'Renderer A: %s' % x -RENDERER_B_SERIALIZER = lambda x: 'Renderer B: %s' % x +RENDERER_A_SERIALIZER = lambda x: ('Renderer A: %s' % x).encode('ascii') +RENDERER_B_SERIALIZER = lambda x: ('Renderer B: %s' % x).encode('ascii') expected_results = [ @@ -141,7 +142,7 @@ class RendererEndToEndTests(TestCase): resp = self.client.head('/') self.assertEquals(resp.status_code, DUMMYSTATUS) self.assertEquals(resp['Content-Type'], RendererA.media_type) - self.assertEquals(resp.content, '') + self.assertEquals(resp.content, six.b('')) def test_default_renderer_serializes_content_on_accept_any(self): """If the Accept header is set to */* the default renderer should serialize the response.""" @@ -268,7 +269,8 @@ class JSONPRendererTests(TestCase): HTTP_ACCEPT='application/javascript') self.assertEquals(resp.status_code, 200) self.assertEquals(resp['Content-Type'], 'application/javascript') - self.assertEquals(resp.content, 'callback(%s);' % _flat_repr) + self.assertEquals(resp.content, + ('callback(%s);' % _flat_repr).encode('ascii')) def test_without_callback_without_json_renderer(self): """ @@ -278,7 +280,8 @@ class JSONPRendererTests(TestCase): HTTP_ACCEPT='application/javascript') self.assertEquals(resp.status_code, 200) self.assertEquals(resp['Content-Type'], 'application/javascript') - self.assertEquals(resp.content, 'callback(%s);' % _flat_repr) + self.assertEquals(resp.content, + ('callback(%s);' % _flat_repr).encode('ascii')) def test_with_callback(self): """ @@ -289,7 +292,8 @@ class JSONPRendererTests(TestCase): HTTP_ACCEPT='application/javascript') self.assertEquals(resp.status_code, 200) self.assertEquals(resp['Content-Type'], 'application/javascript') - self.assertEquals(resp.content, '%s(%s);' % (callback_func, _flat_repr)) + self.assertEquals(resp.content, + ('%s(%s);' % (callback_func, _flat_repr)).encode('ascii')) if yaml: diff --git a/rest_framework/tests/request.py b/rest_framework/tests/request.py index ff48f3fa3..68cfd0299 100644 --- a/rest_framework/tests/request.py +++ b/rest_framework/tests/request.py @@ -1,6 +1,8 @@ """ Tests for content parsing, and form-overloaded content parsing. """ +import six + from django.conf.urls.defaults import patterns from django.contrib.auth.models import User from django.test import TestCase, Client @@ -78,14 +80,14 @@ class TestContentParsing(TestCase): data = {'qwerty': 'uiop'} request = Request(factory.post('/', data)) request.parsers = (FormParser(), MultiPartParser()) - self.assertEqual(request.DATA.items(), data.items()) + self.assertEqual(list(request.DATA.items()), list(data.items())) def test_request_DATA_with_text_content(self): """ Ensure request.DATA returns content for POST request with non-form content. """ - content = 'qwerty' + content = six.b('qwerty') content_type = 'text/plain' request = Request(factory.post('/', content, content_type=content_type)) request.parsers = (PlainTextParser(),) @@ -98,7 +100,7 @@ class TestContentParsing(TestCase): data = {'qwerty': 'uiop'} request = Request(factory.post('/', data)) request.parsers = (FormParser(), MultiPartParser()) - self.assertEqual(request.POST.items(), data.items()) + self.assertEqual(list(request.POST.items()), list(data.items())) def test_standard_behaviour_determines_form_content_PUT(self): """ @@ -116,14 +118,14 @@ class TestContentParsing(TestCase): request = Request(factory.put('/', data)) request.parsers = (FormParser(), MultiPartParser()) - self.assertEqual(request.DATA.items(), data.items()) + self.assertEqual(list(request.DATA.items()), list(data.items())) def test_standard_behaviour_determines_non_form_content_PUT(self): """ Ensure request.DATA returns content for PUT request with non-form content. """ - content = 'qwerty' + content = six.b('qwerty') content_type = 'text/plain' request = Request(factory.put('/', content, content_type=content_type)) request.parsers = (PlainTextParser(), ) diff --git a/rest_framework/tests/response.py b/rest_framework/tests/response.py index d7b75450c..237b12a97 100644 --- a/rest_framework/tests/response.py +++ b/rest_framework/tests/response.py @@ -1,4 +1,5 @@ import unittest +import six from django.conf.urls.defaults import patterns, url, include from django.test import TestCase @@ -25,8 +26,8 @@ class MockJsonRenderer(BaseRenderer): DUMMYSTATUS = status.HTTP_200_OK DUMMYCONTENT = 'dummycontent' -RENDERER_A_SERIALIZER = lambda x: 'Renderer A: %s' % x -RENDERER_B_SERIALIZER = lambda x: 'Renderer B: %s' % x +RENDERER_A_SERIALIZER = lambda x: ('Renderer A: %s' % x).encode('ascii') +RENDERER_B_SERIALIZER = lambda x: ('Renderer B: %s' % x).encode('ascii') class RendererA(BaseRenderer): @@ -95,7 +96,7 @@ class RendererIntegrationTests(TestCase): resp = self.client.head('/') self.assertEquals(resp.status_code, DUMMYSTATUS) self.assertEquals(resp['Content-Type'], RendererA.media_type) - self.assertEquals(resp.content, '') + self.assertEquals(resp.content, six.b('')) def test_default_renderer_serializes_content_on_accept_any(self): """If the Accept header is set to */* the default renderer should serialize the response.""" diff --git a/rest_framework/utils/__init__.py b/rest_framework/utils/__init__.py index a2406852d..458793539 100644 --- a/rest_framework/utils/__init__.py +++ b/rest_framework/utils/__init__.py @@ -1,8 +1,11 @@ +import six + try: from django.utils.encoding import smart_text except ImportError: from django.utils.encoding import smart_unicode as smart_text + from django.utils.xmlutils import SimplerXMLGenerator from rest_framework.compat import StringIO import re @@ -74,7 +77,7 @@ class XMLRenderer(): xml.endElement("list-item") elif isinstance(data, dict): - for key, value in data.iteritems(): + for key, value in six.iteritems(data): xml.startElement(key, {}) self._to_xml(xml, value) xml.endElement(key)