diff options
| author | Tom Christie | 2015-01-19 15:23:08 +0000 |
|---|---|---|
| committer | Tom Christie | 2015-01-19 15:23:08 +0000 |
| commit | e5b94f7b7bbf2f6f35c5e33fb2723bdb0d33bad3 (patch) | |
| tree | a156a4a29a26540c52e5580ffa555b14d6c63fbe /rest_framework | |
| parent | dbb684117f6fe0f9c34f98d5e914fc106090cdbc (diff) | |
| parent | 3cc39ffbceffc5fdbb511d9a10e7732329e8baa4 (diff) | |
| download | django-rest-framework-e5b94f7b7bbf2f6f35c5e33fb2723bdb0d33bad3.tar.bz2 | |
Merge branch 'version-3.1' into cursor-pagination
Diffstat (limited to 'rest_framework')
| -rw-r--r-- | rest_framework/__init__.py | 2 | ||||
| -rw-r--r-- | rest_framework/compat.py | 16 | ||||
| -rw-r--r-- | rest_framework/pagination.py | 6 | ||||
| -rw-r--r-- | rest_framework/parsers.py | 2 | ||||
| -rw-r--r-- | rest_framework/relations.py | 5 | ||||
| -rw-r--r-- | rest_framework/renderers.py | 10 | ||||
| -rw-r--r-- | rest_framework/routers.py | 4 | ||||
| -rw-r--r-- | rest_framework/settings.py | 2 | ||||
| -rw-r--r-- | rest_framework/throttling.py | 10 | ||||
| -rw-r--r-- | rest_framework/utils/encoders.py | 6 | ||||
| -rw-r--r-- | rest_framework/utils/serializer_helpers.py | 6 | ||||
| -rw-r--r-- | rest_framework/versioning.py | 2 |
12 files changed, 45 insertions, 26 deletions
diff --git a/rest_framework/__init__.py b/rest_framework/__init__.py index dec89b3e..fdcebb7b 100644 --- a/rest_framework/__init__.py +++ b/rest_framework/__init__.py @@ -8,7 +8,7 @@ ______ _____ _____ _____ __ """ __title__ = 'Django REST framework' -__version__ = '3.0.2' +__version__ = '3.0.3' __author__ = 'Tom Christie' __license__ = 'BSD 2-Clause' __copyright__ = 'Copyright 2011-2015 Tom Christie' diff --git a/rest_framework/compat.py b/rest_framework/compat.py index 7241da27..bd3802ad 100644 --- a/rest_framework/compat.py +++ b/rest_framework/compat.py @@ -8,7 +8,7 @@ from __future__ import unicode_literals from django.core.exceptions import ImproperlyConfigured from django.conf import settings from django.utils.encoding import force_text -from django.utils.six.moves.urllib import parse as urlparse +from django.utils.six.moves.urllib.parse import urlparse as _urlparse from django.utils import six import django import inspect @@ -38,10 +38,18 @@ def unicode_http_header(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. -# For Django <= 1.6 and Python 2.6 fall back to OrderedDict. +# For Django <= 1.6 and Python 2.6 fall back to SortedDict. try: from collections import OrderedDict except ImportError: @@ -187,7 +195,7 @@ except ImportError: class RequestFactory(DjangoRequestFactory): def generic(self, method, path, data='', content_type='application/octet-stream', **extra): - parsed = urlparse.urlparse(path) + parsed = _urlparse(path) data = force_bytes_or_smart_bytes(data, settings.DEFAULT_CHARSET) r = { 'PATH_INFO': self._get_path(parsed), @@ -227,6 +235,8 @@ except ImportError: if six.PY3: SHORT_SEPARATORS = (',', ':') LONG_SEPARATORS = (', ', ': ') + INDENT_SEPARATORS = (',', ': ') else: SHORT_SEPARATORS = (b',', b':') LONG_SEPARATORS = (b', ', b': ') + INDENT_SEPARATORS = (b',', b': ') diff --git a/rest_framework/pagination.py b/rest_framework/pagination.py index f56f55ce..5482788a 100644 --- a/rest_framework/pagination.py +++ b/rest_framework/pagination.py @@ -135,13 +135,13 @@ class BasePagination(object): display_page_controls = False def paginate_queryset(self, queryset, request, view=None): # pragma: no cover - raise NotImplemented('paginate_queryset() must be implemented.') + raise NotImplementedError('paginate_queryset() must be implemented.') def get_paginated_response(self, data): # pragma: no cover - raise NotImplemented('get_paginated_response() must be implemented.') + raise NotImplementedError('get_paginated_response() must be implemented.') def to_html(self): # pragma: no cover - raise NotImplemented('to_html() must be implemented to display page controls.') + raise NotImplementedError('to_html() must be implemented to display page controls.') class PageNumberPagination(BasePagination): diff --git a/rest_framework/parsers.py b/rest_framework/parsers.py index cb23423d..dd069840 100644 --- a/rest_framework/parsers.py +++ b/rest_framework/parsers.py @@ -179,7 +179,7 @@ class FileUploadParser(BaseParser): for index, handler in enumerate(upload_handlers): file_obj = handler.file_complete(counters[index]) if file_obj: - return DataAndFiles(None, {'file': file_obj}) + return DataAndFiles({}, {'file': file_obj}) raise ParseError("FileUpload parse error - " "none of upload handlers can handle the stream") diff --git a/rest_framework/relations.py b/rest_framework/relations.py index 05ac3d1c..a85edfec 100644 --- a/rest_framework/relations.py +++ b/rest_framework/relations.py @@ -7,6 +7,7 @@ from django.utils import six from django.utils.encoding import smart_text from django.utils.six.moves.urllib import parse as urlparse from django.utils.translation import ugettext_lazy as _ +from rest_framework.compat import OrderedDict from rest_framework.fields import get_attribute, empty, Field from rest_framework.reverse import reverse from rest_framework.utils import html @@ -103,7 +104,7 @@ class RelatedField(Field): @property def choices(self): - return dict([ + return OrderedDict([ ( six.text_type(self.to_representation(item)), six.text_type(item) @@ -364,7 +365,7 @@ class ManyRelatedField(Field): (item, self.child_relation.to_representation(item)) for item in iterable ] - return dict([ + return OrderedDict([ ( six.text_type(item_representation), six.text_type(item) + ' - ' + six.text_type(item_representation) diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py index 4c46b049..f970a363 100644 --- a/rest_framework/renderers.py +++ b/rest_framework/renderers.py @@ -18,7 +18,7 @@ from django.template import Context, RequestContext, loader, Template from django.test.client import encode_multipart from django.utils import six from rest_framework import exceptions, serializers, status, VERSION -from rest_framework.compat import SHORT_SEPARATORS, LONG_SEPARATORS +from rest_framework.compat import SHORT_SEPARATORS, LONG_SEPARATORS, INDENT_SEPARATORS from rest_framework.exceptions import ParseError from rest_framework.settings import api_settings from rest_framework.request import is_form_media_type, override_method @@ -43,7 +43,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): @@ -87,7 +87,11 @@ class JSONRenderer(BaseRenderer): renderer_context = renderer_context or {} indent = self.get_indent(accepted_media_type, renderer_context) - separators = SHORT_SEPARATORS if (indent is None and self.compact) else LONG_SEPARATORS + + if indent is None: + separators = SHORT_SEPARATORS if self.compact else LONG_SEPARATORS + else: + separators = INDENT_SEPARATORS ret = json.dumps( data, cls=self.encoder_class, diff --git a/rest_framework/routers.py b/rest_framework/routers.py index 61f3ccab..827da034 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): diff --git a/rest_framework/settings.py b/rest_framework/settings.py index 3cce26b1..ca5af86e 100644 --- a/rest_framework/settings.py +++ b/rest_framework/settings.py @@ -176,7 +176,7 @@ class APISettings(object): For example: from rest_framework.settings import api_settings - print api_settings.DEFAULT_RENDERER_CLASSES + print(api_settings.DEFAULT_RENDERER_CLASSES) Any setting with string import paths will be automatically resolved and return the class, rather than the string literal. diff --git a/rest_framework/throttling.py b/rest_framework/throttling.py index 361dbddf..0f10136d 100644 --- a/rest_framework/throttling.py +++ b/rest_framework/throttling.py @@ -32,10 +32,10 @@ class BaseThrottle(object): if num_proxies == 0 or xff is None: return remote_addr addrs = xff.split(',') - client_addr = addrs[-min(num_proxies, len(xff))] + client_addr = addrs[-min(num_proxies, len(addrs))] return client_addr.strip() - return xff if xff else remote_addr + return ''.join(xff.split()) if xff else remote_addr def wait(self): """ @@ -173,12 +173,6 @@ class AnonRateThrottle(SimpleRateThrottle): if request.user.is_authenticated(): return None # Only throttle unauthenticated requests. - ident = request.META.get('HTTP_X_FORWARDED_FOR') - if ident is None: - ident = request.META.get('REMOTE_ADDR') - else: - ident = ''.join(ident.split()) - return self.cache_format % { 'scope': self.scope, 'ident': self.get_ident(request) diff --git a/rest_framework/utils/encoders.py b/rest_framework/utils/encoders.py index 0bd24939..2160d18b 100644 --- a/rest_framework/utils/encoders.py +++ b/rest_framework/utils/encoders.py @@ -6,9 +6,11 @@ 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 total_seconds import datetime import decimal import json +import uuid class JSONEncoder(json.JSONEncoder): @@ -38,10 +40,12 @@ 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) + elif isinstance(obj, uuid.UUID): + return six.text_type(obj) elif isinstance(obj, QuerySet): return tuple(obj) elif hasattr(obj, 'tolist'): diff --git a/rest_framework/utils/serializer_helpers.py b/rest_framework/utils/serializer_helpers.py index 65a04d06..f9960603 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): """ diff --git a/rest_framework/versioning.py b/rest_framework/versioning.py index e31c71e9..a07b629f 100644 --- a/rest_framework/versioning.py +++ b/rest_framework/versioning.py @@ -17,7 +17,7 @@ class BaseVersioning(object): def determine_version(self, request, *args, **kwargs): msg = '{cls}.determine_version() must be implemented.' - raise NotImplemented(msg.format( + raise NotImplementedError(msg.format( cls=self.__class__.__name__ )) |
