From 5484d570cb8214c776273b45320e7d1c73b85a34 Mon Sep 17 00:00:00 2001 From: Fabien Bochu Date: Mon, 19 Jan 2015 10:57:26 +0100 Subject: [PATCH 1/5] Fix timedelta JSON serialization on Python 2.6. --- rest_framework/compat.py | 8 ++++++++ rest_framework/utils/encoders.py | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/rest_framework/compat.py b/rest_framework/compat.py index 971dee9cf..17814136b 100644 --- a/rest_framework/compat.py +++ b/rest_framework/compat.py @@ -33,6 +33,14 @@ def unicode_to_repr(value): return value +def total_seconds(timedelta): + # TimeDelta.total_seconds() is only available in Python 2.7 + if hasattr(timedelta, 'total_seconds'): + return timedelta.total_seconds() + else: + return (timedelta.days * 86400.0) + float(timedelta.seconds) + (timedelta.microseconds / 1000000.0) + + # OrderedDict only available in Python 2.7. # This will always be the case in Django 1.7 and above, as these versions # no longer support Python 2.6. diff --git a/rest_framework/utils/encoders.py b/rest_framework/utils/encoders.py index 73cbe5d8a..104343a44 100644 --- a/rest_framework/utils/encoders.py +++ b/rest_framework/utils/encoders.py @@ -6,7 +6,7 @@ from django.db.models.query import QuerySet from django.utils import six, timezone from django.utils.encoding import force_text from django.utils.functional import Promise -from rest_framework.compat import OrderedDict +from rest_framework.compat import OrderedDict, total_seconds from rest_framework.utils.serializer_helpers import ReturnDict, ReturnList import datetime import decimal @@ -41,7 +41,7 @@ class JSONEncoder(json.JSONEncoder): representation = representation[:12] return representation elif isinstance(obj, datetime.timedelta): - return six.text_type(obj.total_seconds()) + return six.text_type(total_seconds(obj)) elif isinstance(obj, decimal.Decimal): # Serializers will coerce decimals to strings by default. return float(obj) From da1db34a36f6f0cb8722acbbf7c3182e32995ae3 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Mon, 19 Jan 2015 14:18:02 +0000 Subject: [PATCH 2/5] Handle UUID objects in JSONEncoder. Closes #2433. --- rest_framework/utils/encoders.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rest_framework/utils/encoders.py b/rest_framework/utils/encoders.py index 104343a44..bf7532711 100644 --- a/rest_framework/utils/encoders.py +++ b/rest_framework/utils/encoders.py @@ -12,6 +12,7 @@ import datetime import decimal import types import json +import uuid class JSONEncoder(json.JSONEncoder): @@ -45,6 +46,8 @@ class JSONEncoder(json.JSONEncoder): elif isinstance(obj, decimal.Decimal): # Serializers will coerce decimals to strings by default. return float(obj) + elif isinstance(obj, uuid.UUID): + return six.text_type(obj) elif isinstance(obj, QuerySet): return tuple(obj) elif hasattr(obj, 'tolist'): From 0dffc46cb71ec868cdbb37187ba03dea7bac4e7a Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Mon, 19 Jan 2015 14:21:09 +0000 Subject: [PATCH 3/5] ReturnDict and ReturnList repr as standard dict/list. Closes #2421. --- rest_framework/utils/serializer_helpers.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/rest_framework/utils/serializer_helpers.py b/rest_framework/utils/serializer_helpers.py index 65a04d06b..f99606039 100644 --- a/rest_framework/utils/serializer_helpers.py +++ b/rest_framework/utils/serializer_helpers.py @@ -16,6 +16,9 @@ class ReturnDict(OrderedDict): def copy(self): return ReturnDict(self, serializer=self.serializer) + def __repr__(self): + return dict.__repr__(self) + class ReturnList(list): """ @@ -27,6 +30,9 @@ class ReturnList(list): self.serializer = kwargs.pop('serializer') super(ReturnList, self).__init__(*args, **kwargs) + def __repr__(self): + return list.__repr__(self) + class BoundField(object): """ From af05820b1bfc60ceb7cbb35566588a732938cae2 Mon Sep 17 00:00:00 2001 From: Alexander Dutton Date: Mon, 19 Jan 2015 14:23:13 +0000 Subject: [PATCH 4/5] NotImplemented is not an exception `NotImplemented` is a singleton object, not an exception. You should be raising `NotImplementedError` here instead. --- rest_framework/renderers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py index 634338e9e..ba6c9cc15 100644 --- a/rest_framework/renderers.py +++ b/rest_framework/renderers.py @@ -46,7 +46,7 @@ class BaseRenderer(object): render_style = 'text' def render(self, data, accepted_media_type=None, renderer_context=None): - raise NotImplemented('Renderer class requires .render() to be implemented') + raise NotImplementedError('Renderer class requires .render() to be implemented') class JSONRenderer(BaseRenderer): From 46a3eda08d519c6908ecd1b9c2e13e5fdb773b0c Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Mon, 19 Jan 2015 14:48:13 +0000 Subject: [PATCH 5/5] NotImplemented -> NotImplementedError --- rest_framework/routers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rest_framework/routers.py b/rest_framework/routers.py index 61f3ccab0..827da0340 100644 --- a/rest_framework/routers.py +++ b/rest_framework/routers.py @@ -65,13 +65,13 @@ class BaseRouter(object): If `base_name` is not specified, attempt to automatically determine it from the viewset. """ - raise NotImplemented('get_default_base_name must be overridden') + raise NotImplementedError('get_default_base_name must be overridden') def get_urls(self): """ Return a list of URL patterns, given the registered viewsets. """ - raise NotImplemented('get_urls must be overridden') + raise NotImplementedError('get_urls must be overridden') @property def urls(self):