aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AUTHORS4
-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
-rw-r--r--examples/pygments_api/tests.py2
-rw-r--r--requirements.txt1
-rw-r--r--setup.py1
-rw-r--r--tox.ini18
19 files changed, 271 insertions, 38 deletions
diff --git a/AUTHORS b/AUTHORS
index 5a2bc165..5e085eb8 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,4 +1,4 @@
-Tom Christie <tomchristie> - tom@tomchristie.com, @thisneonsoul
+Tom Christie <tomchristie> - tom@tomchristie.com, @_tomchristie
Marko Tibold <markotibold> (Additional thanks for providing & managing the Jenkins CI Server)
Paul Bagwell <pbgwl>
Sébastien Piquemal <sebpiq>
@@ -22,6 +22,8 @@ Meurig Freeman <meurig>
Anthony Nemitz <anemitz>
Ewoud Kohl van Wijngaarden <ekohl>
Michael Ding <yandy>
+Mjumbe Poe <mjumbewu>
+Natim <natim>
THANKS TO:
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)
diff --git a/examples/pygments_api/tests.py b/examples/pygments_api/tests.py
index 98139ce2..24726647 100644
--- a/examples/pygments_api/tests.py
+++ b/examples/pygments_api/tests.py
@@ -18,7 +18,7 @@ class TestPygmentsExample(TestCase):
def tearDown(self):
try:
shutil.rmtree(self.temp_dir)
- except:
+ except Exception:
pass
def test_get_to_root(self):
diff --git a/requirements.txt b/requirements.txt
index 2b54c95b..56926c0f 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -3,3 +3,4 @@
Django>=1.2
coverage>=3.4
+URLObject>=0.6.0
diff --git a/setup.py b/setup.py
index 1d738328..690a7e0f 100644
--- a/setup.py
+++ b/setup.py
@@ -26,6 +26,7 @@ setup(
package_dir={'djangorestframework': 'djangorestframework'},
package_data = {'djangorestframework': ['templates/*', 'static/*']},
test_suite = 'djangorestframework.runtests.runcoverage.main',
+ install_requires=['URLObject>=0.6.0'],
classifiers = [
'Development Status :: 4 - Beta',
'Environment :: Web Environment',
diff --git a/tox.ini b/tox.ini
index 6c51cc07..2e6ab204 100644
--- a/tox.ini
+++ b/tox.ini
@@ -33,6 +33,7 @@ basepython=python2.5
deps=
django==1.2.4
coverage==3.4
+ URLObject>=0.6.0
unittest-xml-reporting==1.2
Pyyaml==3.10
# Optional packages:
@@ -43,6 +44,7 @@ basepython=python2.6
deps=
django==1.2.4
coverage==3.4
+ URLObject>=0.6.0
unittest-xml-reporting==1.2
Pyyaml==3.10
# Optional packages:
@@ -53,6 +55,7 @@ basepython=python2.7
deps=
django==1.2.4
coverage==3.4
+ URLObject>=0.6.0
unittest-xml-reporting==1.2
Pyyaml==3.10
# Optional packages:
@@ -63,6 +66,7 @@ basepython=python2.5
deps=
django==1.3
coverage==3.4
+ URLObject>=0.6.0
unittest-xml-reporting==1.2
Pyyaml==3.10
# Optional packages:
@@ -73,6 +77,7 @@ basepython=python2.6
deps=
django==1.3
coverage==3.4
+ URLObject>=0.6.0
unittest-xml-reporting==1.2
Pyyaml==3.10
# Optional packages:
@@ -83,6 +88,7 @@ basepython=python2.7
deps=
django==1.3
coverage==3.4
+ URLObject>=0.6.0
unittest-xml-reporting==1.2
Pyyaml==3.10
# Optional packages:
@@ -93,6 +99,7 @@ basepython=python2.5
deps=
http://www.djangoproject.com/download/1.4-alpha-1/tarball/
coverage==3.4
+ URLObject>=0.6.0
unittest-xml-reporting==1.2
Pyyaml==3.10
# Optional packages:
@@ -103,6 +110,7 @@ basepython=python2.6
deps=
http://www.djangoproject.com/download/1.4-alpha-1/tarball/
coverage==3.4
+ URLObject>=0.6.0
unittest-xml-reporting==1.2
Pyyaml==3.10
# Optional packages:
@@ -113,6 +121,7 @@ basepython=python2.7
deps=
http://www.djangoproject.com/download/1.4-alpha-1/tarball/
coverage==3.4
+ URLObject>=0.6.0
unittest-xml-reporting==1.2
Pyyaml==3.10
# Optional packages:
@@ -127,6 +136,7 @@ commands=
deps=
django==1.2.4
coverage==3.4
+ URLObject>=0.6.0
wsgiref==0.1.2
Pygments==1.4
httplib2==0.6.0
@@ -141,6 +151,7 @@ commands=
deps=
django==1.2.4
coverage==3.4
+ URLObject>=0.6.0
wsgiref==0.1.2
Pygments==1.4
httplib2==0.6.0
@@ -155,6 +166,7 @@ commands=
deps=
django==1.2.4
coverage==3.4
+ URLObject>=0.6.0
wsgiref==0.1.2
Pygments==1.4
httplib2==0.6.0
@@ -169,6 +181,7 @@ commands=
deps=
django==1.3
coverage==3.4
+ URLObject>=0.6.0
wsgiref==0.1.2
Pygments==1.4
httplib2==0.6.0
@@ -183,6 +196,7 @@ commands=
deps=
django==1.3
coverage==3.4
+ URLObject>=0.6.0
wsgiref==0.1.2
Pygments==1.4
httplib2==0.6.0
@@ -197,6 +211,7 @@ commands=
deps=
django==1.3
coverage==3.4
+ URLObject>=0.6.0
wsgiref==0.1.2
Pygments==1.4
httplib2==0.6.0
@@ -211,6 +226,7 @@ commands=
deps=
http://www.djangoproject.com/download/1.4-alpha-1/tarball/
coverage==3.4
+ URLObject>=0.6.0
wsgiref==0.1.2
Pygments==1.4
httplib2==0.6.0
@@ -225,6 +241,7 @@ commands=
deps=
http://www.djangoproject.com/download/1.4-alpha-1/tarball/
coverage==3.4
+ URLObject>=0.6.0
wsgiref==0.1.2
Pygments==1.4
httplib2==0.6.0
@@ -239,6 +256,7 @@ commands=
deps=
http://www.djangoproject.com/download/1.4-alpha-1/tarball/
coverage==3.4
+ URLObject>=0.6.0
wsgiref==0.1.2
Pygments==1.4
httplib2==0.6.0