aboutsummaryrefslogtreecommitdiffstats
path: root/rest_framework/compat.py
diff options
context:
space:
mode:
Diffstat (limited to 'rest_framework/compat.py')
-rw-r--r--rest_framework/compat.py85
1 files changed, 77 insertions, 8 deletions
diff --git a/rest_framework/compat.py b/rest_framework/compat.py
index 07fdddce..cd39f544 100644
--- a/rest_framework/compat.py
+++ b/rest_framework/compat.py
@@ -6,6 +6,7 @@ versions of django/python, and compatibility wrappers around optional packages.
from __future__ import unicode_literals
import django
+from django.core.exceptions import ImproperlyConfigured
# Try to import six from Django, fallback to included `six`.
try:
@@ -87,9 +88,7 @@ else:
raise ImportError("User model is not to be found.")
-# First implementation of Django class-based views did not include head method
-# in base View class - https://code.djangoproject.com/ticket/15668
-if django.VERSION >= (1, 4):
+if django.VERSION >= (1, 5):
from django.views.generic import View
else:
from django.views.generic import View as _View
@@ -97,6 +96,8 @@ else:
from django.utils.functional import update_wrapper
class View(_View):
+ # 1.3 does not include head method in base View class
+ # See: https://code.djangoproject.com/ticket/15668
@classonlymethod
def as_view(cls, **initkwargs):
"""
@@ -126,11 +127,15 @@ else:
update_wrapper(view, cls.dispatch, assigned=())
return view
-# Taken from @markotibold's attempt at supporting PATCH.
-# https://github.com/markotibold/django-rest-framework/tree/patch
-http_method_names = set(View.http_method_names)
-http_method_names.add('patch')
-View.http_method_names = list(http_method_names) # PATCH method is not implemented by Django
+ # _allowed_methods only present from 1.5 onwards
+ def _allowed_methods(self):
+ return [m.upper() for m in self.http_method_names if hasattr(self, m)]
+
+
+# PATCH method is not implemented by Django
+if 'patch' not in View.http_method_names:
+ View.http_method_names = View.http_method_names + ['patch']
+
# PUT, DELETE do not require CSRF until 1.4. They should. Make it better.
if django.VERSION >= (1, 4):
@@ -395,6 +400,41 @@ except ImportError:
kw = dict((k, int(v)) for k, v in kw.iteritems() if v is not None)
return datetime.datetime(**kw)
+
+# smart_urlquote is new on Django 1.4
+try:
+ from django.utils.html import smart_urlquote
+except ImportError:
+ import re
+ from django.utils.encoding import smart_str
+ try:
+ from urllib.parse import quote, urlsplit, urlunsplit
+ except ImportError: # Python 2
+ from urllib import quote
+ from urlparse import urlsplit, urlunsplit
+
+ unquoted_percents_re = re.compile(r'%(?![0-9A-Fa-f]{2})')
+
+ def smart_urlquote(url):
+ "Quotes a URL if it isn't already quoted."
+ # Handle IDN before quoting.
+ scheme, netloc, path, query, fragment = urlsplit(url)
+ try:
+ netloc = netloc.encode('idna').decode('ascii') # IDN -> ACE
+ except UnicodeError: # invalid domain part
+ pass
+ else:
+ url = urlunsplit((scheme, netloc, path, query, fragment))
+
+ # An URL is considered unquoted if it contains no % characters or
+ # contains a % not followed by two hexadecimal digits. See #9655.
+ if '%' not in url or unquoted_percents_re.search(url):
+ # See http://bugs.python.org/issue2637
+ url = quote(smart_str(url), safe=b'!*\'();:@&=+$,/?#[]~')
+
+ return force_text(url)
+
+
# Markdown is optional
try:
import markdown
@@ -426,3 +466,32 @@ try:
import defusedxml.ElementTree as etree
except ImportError:
etree = None
+
+# OAuth is optional
+try:
+ # Note: The `oauth2` package actually provides oauth1.0a support. Urg.
+ import oauth2 as oauth
+except ImportError:
+ oauth = None
+
+# OAuth is optional
+try:
+ import oauth_provider
+ from oauth_provider.store import store as oauth_provider_store
+except (ImportError, ImproperlyConfigured):
+ oauth_provider = None
+ oauth_provider_store = None
+
+# OAuth 2 support is optional
+try:
+ import provider.oauth2 as oauth2_provider
+ from provider.oauth2 import models as oauth2_provider_models
+ from provider.oauth2 import forms as oauth2_provider_forms
+ from provider import scope as oauth2_provider_scope
+ from provider import constants as oauth2_constants
+except ImportError:
+ oauth2_provider = None
+ oauth2_provider_models = None
+ oauth2_provider_forms = None
+ oauth2_provider_scope = None
+ oauth2_constants = None