aboutsummaryrefslogtreecommitdiffstats
path: root/djangorestframework
diff options
context:
space:
mode:
Diffstat (limited to 'djangorestframework')
-rw-r--r--djangorestframework/__init__.py2
-rw-r--r--djangorestframework/compat.py25
-rw-r--r--djangorestframework/mixins.py6
-rw-r--r--djangorestframework/parsers.py2
-rw-r--r--djangorestframework/renderers.py8
-rw-r--r--djangorestframework/runtests/runcoverage.py1
-rw-r--r--djangorestframework/templatetags/add_query_param.py12
-rw-r--r--djangorestframework/tests/content.py25
-rw-r--r--djangorestframework/tests/mixins.py11
-rw-r--r--djangorestframework/tests/renderers.py180
-rw-r--r--djangorestframework/utils/__init__.py2
-rw-r--r--djangorestframework/utils/breadcrumbs.py2
-rw-r--r--djangorestframework/utils/mediatypes.py2
-rw-r--r--djangorestframework/views.py5
14 files changed, 247 insertions, 36 deletions
diff --git a/djangorestframework/__init__.py b/djangorestframework/__init__.py
index 62edc070..55f92cc4 100644
--- a/djangorestframework/__init__.py
+++ b/djangorestframework/__init__.py
@@ -1,3 +1,3 @@
-__version__ = '0.3.1-dev'
+__version__ = '0.3.2-dev'
VERSION = __version__ # synonym
diff --git a/djangorestframework/compat.py b/djangorestframework/compat.py
index 38119811..7690316c 100644
--- a/djangorestframework/compat.py
+++ b/djangorestframework/compat.py
@@ -432,3 +432,28 @@ try:
except ImportError:
yaml = None
+import unittest
+try:
+ import unittest.skip
+except ImportError: # python < 2.7
+ from unittest import TestCase
+ import functools
+
+ def skip(reason):
+ # Pasted from py27/lib/unittest/case.py
+ """
+ Unconditionally skip a test.
+ """
+ def decorator(test_item):
+ if not (isinstance(test_item, type) and issubclass(test_item, TestCase)):
+ @functools.wraps(test_item)
+ def skip_wrapper(*args, **kwargs):
+ pass
+ test_item = skip_wrapper
+
+ test_item.__unittest_skip__ = True
+ test_item.__unittest_skip_why__ = reason
+ return test_item
+ return decorator
+
+ unittest.skip = skip
diff --git a/djangorestframework/mixins.py b/djangorestframework/mixins.py
index f57760ec..8e6b1ed8 100644
--- a/djangorestframework/mixins.py
+++ b/djangorestframework/mixins.py
@@ -8,6 +8,7 @@ from django.core.paginator import Paginator
from django.db.models.fields.related import ForeignKey
from django.db.models.query import Q
from django.http import HttpResponse
+from urlobject import URLObject
from djangorestframework import status
from djangorestframework.renderers import BaseRenderer
@@ -706,11 +707,12 @@ class PaginatorMixin(object):
def url_with_page_number(self, page_number):
""" Constructs a url used for getting the next/previous urls """
- url = "%s?page=%d" % (self.request.path, page_number)
+ url = URLObject.parse(self.request.get_full_path())
+ url = url.add_query_param('page', page_number)
limit = self.get_limit()
if limit != self.limit:
- url = "%s&limit=%d" % (url, limit)
+ url = url.add_query_param('limit', limit)
return url
diff --git a/djangorestframework/parsers.py b/djangorestframework/parsers.py
index 7d765022..c218e5ee 100644
--- a/djangorestframework/parsers.py
+++ b/djangorestframework/parsers.py
@@ -31,7 +31,7 @@ __all__ = (
'FormParser',
'MultiPartParser',
'YAMLParser',
- 'XMLParser'
+ 'XMLParser'
)
diff --git a/djangorestframework/renderers.py b/djangorestframework/renderers.py
index 0c80f07e..42d80bd4 100644
--- a/djangorestframework/renderers.py
+++ b/djangorestframework/renderers.py
@@ -169,7 +169,7 @@ if yaml:
if obj is None:
return ''
- return yaml.dump(obj)
+ return yaml.safe_dump(obj)
else:
YAMLRenderer = None
@@ -215,7 +215,7 @@ class DocumentingTemplateRenderer(BaseRenderer):
"""
# Find the first valid renderer and render the content. (Don't use another documenting renderer.)
- renderers = [renderer for renderer in view.renderers if not isinstance(renderer, DocumentingTemplateRenderer)]
+ renderers = [renderer for renderer in view.renderers if not issubclass(renderer, DocumentingTemplateRenderer)]
if not renderers:
return '[No renderers were found]'
@@ -246,14 +246,14 @@ class DocumentingTemplateRenderer(BaseRenderer):
form_instance = view.get_bound_form(view.response.cleaned_content, method=method)
if form_instance and not form_instance.is_valid():
form_instance = None
- except:
+ except Exception:
form_instance = None
# If we still don't have a form instance then try to get an unbound form
if not form_instance:
try:
form_instance = view.get_bound_form(method=method)
- except:
+ except Exception:
pass
# If we still don't have a form instance then try to get an unbound form which can tunnel arbitrary content types
diff --git a/djangorestframework/runtests/runcoverage.py b/djangorestframework/runtests/runcoverage.py
index ab1b0498..0ab61479 100644
--- a/djangorestframework/runtests/runcoverage.py
+++ b/djangorestframework/runtests/runcoverage.py
@@ -35,7 +35,6 @@ def main():
else:
test_runner = TestRunner()
failures = test_runner.run_tests(['djangorestframework'])
-
cov.stop()
# Discover the list of all modules that we should test coverage for
diff --git a/djangorestframework/templatetags/add_query_param.py b/djangorestframework/templatetags/add_query_param.py
index 94833bce..ce175b81 100644
--- a/djangorestframework/templatetags/add_query_param.py
+++ b/djangorestframework/templatetags/add_query_param.py
@@ -1,17 +1,11 @@
from django.template import Library
-from urlparse import urlparse, urlunparse
-from urllib import quote
+from urlobject import URLObject
register = Library()
+
def add_query_param(url, param):
(key, sep, val) = param.partition('=')
- param = '%s=%s' % (key, quote(val))
- (scheme, netloc, path, params, query, fragment) = urlparse(url)
- if query:
- query += "&" + param
- else:
- query = param
- return urlunparse((scheme, netloc, path, params, query, fragment))
+ return unicode(URLObject(url) & (key, val))
register.filter('add_query_param', add_query_param)
diff --git a/djangorestframework/tests/content.py b/djangorestframework/tests/content.py
index 048586c8..47dfce80 100644
--- a/djangorestframework/tests/content.py
+++ b/djangorestframework/tests/content.py
@@ -6,7 +6,7 @@ from django.contrib.auth.models import User
from django.test import TestCase, Client
from djangorestframework import status
from djangorestframework.authentication import UserLoggedInAuthentication
-from djangorestframework.compat import RequestFactory
+from djangorestframework.compat import RequestFactory, unittest
from djangorestframework.mixins import RequestMixin
from djangorestframework.parsers import FormParser, MultiPartParser, \
PlainTextParser, JSONParser
@@ -114,21 +114,22 @@ class TestContentParsing(TestCase):
self.assertEqual(view.DATA.items(), form_data.items())
self.assertEqual(view.request.POST.items(), form_data.items())
- # def test_accessing_post_after_data_for_json(self):
- # """Ensures request.POST can be accessed after request.DATA in json request"""
- # from django.utils import simplejson as json
+ @unittest.skip('This test was disabled some time ago for some reason')
+ def test_accessing_post_after_data_for_json(self):
+ """Ensures request.POST can be accessed after request.DATA in json request"""
+ from django.utils import simplejson as json
- # data = {'qwerty': 'uiop'}
- # content = json.dumps(data)
- # content_type = 'application/json'
+ data = {'qwerty': 'uiop'}
+ content = json.dumps(data)
+ content_type = 'application/json'
- # view = RequestMixin()
- # view.parsers = (JSONParser,)
+ view = RequestMixin()
+ view.parsers = (JSONParser,)
- # view.request = self.req.post('/', content, content_type=content_type)
+ view.request = self.req.post('/', content, content_type=content_type)
- # self.assertEqual(view.DATA.items(), data.items())
- # self.assertEqual(view.request.POST.items(), [])
+ self.assertEqual(view.DATA.items(), data.items())
+ self.assertEqual(view.request.POST.items(), [])
def test_accessing_post_after_data_for_overloaded_json(self):
"""Ensures request.POST can be accessed after request.DATA in overloaded json request"""
diff --git a/djangorestframework/tests/mixins.py b/djangorestframework/tests/mixins.py
index 3b814aa7..2913160d 100644
--- a/djangorestframework/tests/mixins.py
+++ b/djangorestframework/tests/mixins.py
@@ -237,3 +237,14 @@ class TestPagination(TestCase):
response = MockPaginatorView.as_view()(request)
content = json.loads(response.content)
self.assertEqual(response.status_code, status.NOT_FOUND)
+
+ def test_existing_query_parameters_are_preserved(self):
+ """ Tests that existing query parameters are preserved when
+ generating next/previous page links """
+ request = self.req.get('/paginator/?foo=bar&another=something')
+ response = MockPaginatorView.as_view()(request)
+ content = json.loads(response.content)
+ self.assertEqual(response.status_code, status.OK)
+ self.assertTrue('foo=bar' in content['next'])
+ self.assertTrue('another=something' in content['next'])
+ self.assertTrue('page=2' in content['next'])
diff --git a/djangorestframework/tests/renderers.py b/djangorestframework/tests/renderers.py
index bd0d360c..e80f0f20 100644
--- a/djangorestframework/tests/renderers.py
+++ b/djangorestframework/tests/renderers.py
@@ -5,7 +5,7 @@ from djangorestframework import status
from djangorestframework.views import View
from djangorestframework.compat import View as DjangoView
from djangorestframework.renderers import BaseRenderer, JSONRenderer, YAMLRenderer, \
- XMLRenderer, JSONPRenderer
+ XMLRenderer, JSONPRenderer, DocumentingHTMLRenderer
from djangorestframework.parsers import JSONParser, YAMLParser
from djangorestframework.mixins import ResponseMixin
from djangorestframework.response import Response
@@ -46,15 +46,30 @@ class MockView(ResponseMixin, DjangoView):
class MockGETView(View):
+
def get(self, request, **kwargs):
return {'foo': ['bar', 'baz']}
+class HTMLView(View):
+ renderers = (DocumentingHTMLRenderer, )
+
+ def get(self, request, **kwargs):
+ return 'text'
+
+class HTMLView1(View):
+ renderers = (DocumentingHTMLRenderer, JSONRenderer)
+
+ def get(self, request, **kwargs):
+ return 'text'
+
urlpatterns = patterns('',
url(r'^.*\.(?P<format>.+)$', MockView.as_view(renderers=[RendererA, RendererB])),
url(r'^$', MockView.as_view(renderers=[RendererA, RendererB])),
url(r'^jsonp/jsonrenderer$', MockGETView.as_view(renderers=[JSONRenderer, JSONPRenderer])),
url(r'^jsonp/nojsonrenderer$', MockGETView.as_view(renderers=[JSONPRenderer])),
+ url(r'^html$', HTMLView.as_view()),
+ url(r'^html1$', HTMLView1.as_view()),
)
@@ -327,3 +342,166 @@ class XMLRendererTestCase(TestCase):
self.assertTrue(xml.startswith('<?xml version="1.0" encoding="utf-8"?>\n<root>'))
self.assertTrue(xml.endswith('</root>'))
self.assertTrue(string in xml, '%r not in %r' % (string, xml))
+
+class HTMLView(View):
+ renderers = (DocumentingHTMLRenderer)
+
+ def get(self, request, **kwargs):
+ return 'text'
+
+urlpatterns += patterns('',
+ url(r'^/html$', HTMLView.as_view()),
+)
+
+class Issue122Tests(TestCase):
+ """
+ Tests that cover issues.
+ """
+
+ urls = 'djangorestframework.tests.renderers'
+
+ def test_without_callback_with_json_renderer(self):
+ """
+ Test JSONP rendering with View JSON Renderer.
+ """
+ resp = self.client.get('/jsonp/jsonrenderer',
+ HTTP_ACCEPT='application/json-p')
+ self.assertEquals(resp.status_code, 200)
+ self.assertEquals(resp['Content-Type'], 'application/json-p')
+ self.assertEquals(resp.content, 'callback(%s);' % _flat_repr)
+
+ def test_without_callback_without_json_renderer(self):
+ """
+ Test JSONP rendering without View JSON Renderer.
+ """
+ resp = self.client.get('/jsonp/nojsonrenderer',
+ HTTP_ACCEPT='application/json-p')
+ self.assertEquals(resp.status_code, 200)
+ self.assertEquals(resp['Content-Type'], 'application/json-p')
+ self.assertEquals(resp.content, 'callback(%s);' % _flat_repr)
+
+ def test_with_callback(self):
+ """
+ Test JSONP rendering with callback function name.
+ """
+ callback_func = 'myjsonpcallback'
+ resp = self.client.get('/jsonp/nojsonrenderer?callback=' + callback_func,
+ HTTP_ACCEPT='application/json-p')
+ self.assertEquals(resp.status_code, 200)
+ self.assertEquals(resp['Content-Type'], 'application/json-p')
+ self.assertEquals(resp.content, '%s(%s);' % (callback_func, _flat_repr))
+
+
+if YAMLRenderer:
+ _yaml_repr = 'foo: [bar, baz]\n'
+
+ class YAMLRendererTests(TestCase):
+ """
+ Tests specific to the JSON Renderer
+ """
+
+ def test_render(self):
+ """
+ Test basic YAML rendering.
+ """
+ obj = {'foo': ['bar', 'baz']}
+ renderer = YAMLRenderer(None)
+ content = renderer.render(obj, 'application/yaml')
+ self.assertEquals(content, _yaml_repr)
+
+ def test_render_and_parse(self):
+ """
+ Test rendering and then parsing returns the original object.
+ IE obj -> render -> parse -> obj.
+ """
+ obj = {'foo': ['bar', 'baz']}
+
+ renderer = YAMLRenderer(None)
+ parser = YAMLParser(None)
+
+ content = renderer.render(obj, 'application/yaml')
+ (data, files) = parser.parse(StringIO(content))
+ self.assertEquals(obj, data)
+
+
+class XMLRendererTestCase(TestCase):
+ """
+ Tests specific to the XML Renderer
+ """
+
+ def test_render_string(self):
+ """
+ Test XML rendering.
+ """
+ renderer = XMLRenderer(None)
+ content = renderer.render({'field': 'astring'}, 'application/xml')
+ self.assertXMLContains(content, '<field>astring</field>')
+
+ def test_render_integer(self):
+ """
+ Test XML rendering.
+ """
+ renderer = XMLRenderer(None)
+ content = renderer.render({'field': 111}, 'application/xml')
+ self.assertXMLContains(content, '<field>111</field>')
+
+ def test_render_datetime(self):
+ """
+ Test XML rendering.
+ """
+ renderer = XMLRenderer(None)
+ content = renderer.render({
+ 'field': datetime.datetime(2011, 12, 25, 12, 45, 00)
+ }, 'application/xml')
+ self.assertXMLContains(content, '<field>2011-12-25 12:45:00</field>')
+
+ def test_render_float(self):
+ """
+ Test XML rendering.
+ """
+ renderer = XMLRenderer(None)
+ content = renderer.render({'field': 123.4}, 'application/xml')
+ self.assertXMLContains(content, '<field>123.4</field>')
+
+ def test_render_decimal(self):
+ """
+ Test XML rendering.
+ """
+ renderer = XMLRenderer(None)
+ content = renderer.render({'field': Decimal('111.2')}, 'application/xml')
+ self.assertXMLContains(content, '<field>111.2</field>')
+
+ def test_render_none(self):
+ """
+ Test XML rendering.
+ """
+ renderer = XMLRenderer(None)
+ content = renderer.render({'field': None}, 'application/xml')
+ self.assertXMLContains(content, '<field></field>')
+
+ def assertXMLContains(self, xml, string):
+ self.assertTrue(xml.startswith('<?xml version="1.0" encoding="utf-8"?>\n<root>'))
+ self.assertTrue(xml.endswith('</root>'))
+ self.assertTrue(string in xml, '%r not in %r' % (string, xml))
+
+
+
+class Issue122Tests(TestCase):
+ """
+ Tests that covers #122.
+ """
+
+ urls = 'djangorestframework.tests.renderers'
+
+ def test_only_html_renderer(self):
+ """
+ Test if no recursion occurs.
+ """
+ resp = self.client.get('/html')
+
+ def test_html_renderer_is_first(self):
+ """
+ Test if no recursion occurs.
+ """
+ resp = self.client.get('/html1')
+
diff --git a/djangorestframework/utils/__init__.py b/djangorestframework/utils/__init__.py
index 305311f4..2b4fd10e 100644
--- a/djangorestframework/utils/__init__.py
+++ b/djangorestframework/utils/__init__.py
@@ -43,7 +43,7 @@ def url_resolves(url):
"""
try:
resolve(url)
- except:
+ except Exception:
return False
return True
diff --git a/djangorestframework/utils/breadcrumbs.py b/djangorestframework/utils/breadcrumbs.py
index 6cf978ed..fd966282 100644
--- a/djangorestframework/utils/breadcrumbs.py
+++ b/djangorestframework/utils/breadcrumbs.py
@@ -11,7 +11,7 @@ def get_breadcrumbs(url):
try:
(view, unused_args, unused_kwargs) = resolve(url)
- except:
+ except Exception:
pass
else:
# Check if this is a REST framework view, and if so add it to the breadcrumbs
diff --git a/djangorestframework/utils/mediatypes.py b/djangorestframework/utils/mediatypes.py
index 3c0eefc4..c0071f01 100644
--- a/djangorestframework/utils/mediatypes.py
+++ b/djangorestframework/utils/mediatypes.py
@@ -109,7 +109,7 @@ class _MediaType(object):
# """
# try:
# return Decimal(self.params.get('q', '1.0'))
- # except:
+ # except Exception:
# return Decimal(0)
#def score(self):
diff --git a/djangorestframework/views.py b/djangorestframework/views.py
index 4cc2c7cb..4606e50b 100644
--- a/djangorestframework/views.py
+++ b/djangorestframework/views.py
@@ -115,8 +115,9 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView):
# Calls to 'reverse' will not be fully qualified unless we set the scheme/host/port here.
orig_prefix = get_script_prefix()
- prefix = '%s://%s' % (request.is_secure() and 'https' or 'http', request.get_host())
- set_script_prefix(prefix + orig_prefix)
+ if not (orig_prefix.startswith('http:') or orig_prefix.startswith('https:')):
+ prefix = '%s://%s' % (request.is_secure() and 'https' or 'http', request.get_host())
+ set_script_prefix(prefix + orig_prefix)
try:
self.initial(request, *args, **kwargs)