Skip to content

Commit

Permalink
Removed Django 1.5-1.6 support.
Browse files Browse the repository at this point in the history
  • Loading branch information
SeanHayes committed Oct 21, 2015
1 parent a9e5b61 commit 39c6308
Show file tree
Hide file tree
Showing 39 changed files with 260 additions and 756 deletions.
10 changes: 0 additions & 10 deletions .travis.yml
Expand Up @@ -3,14 +3,11 @@ sudo: false
language: python

python:
- "2.6"
- "2.7"
- "3.3"
- "3.4"

env:
- DJANGO_VERSION=1.5
- DJANGO_VERSION=1.6
- DJANGO_VERSION=1.7
- DJANGO_VERSION=1.8
- DJANGO_VERSION=dev
Expand All @@ -19,13 +16,6 @@ matrix:
allow_failures:
- env: DJANGO_VERSION=dev
- env: MODE=flake8-strict
exclude:
- env: DJANGO_VERSION=dev
python: "2.6"
- env: DJANGO_VERSION=1.8
python: "2.6"
- env: DJANGO_VERSION=1.7
python: "2.6"
include:
- python: "2.7"
env: MODE=flake8
Expand Down
2 changes: 1 addition & 1 deletion docs/compatibility_notes.rst
Expand Up @@ -19,7 +19,7 @@ updated & a migration was added (``0002_add_apikey_index.py``). However, due
to the way MySQL works & the way Django generates index names, this migration
would fail miserably on many MySQL installs.

If you are using MySQL, South & the ``ApiKey`` authentication class, you should
If you are using MySQL & the ``ApiKey`` authentication class, you may need to
manually add an index for the the ``ApiKey.key`` field. Something to the effect
of::

Expand Down
15 changes: 0 additions & 15 deletions docs/debugging.rst
Expand Up @@ -70,18 +70,3 @@ You can do this over an entire collection as well::
curl -H 'Content-Type: application/json' -X PUT --data @- "http://localhost:8000/api/v1/entry/"

.. _Requests: http://python-requests.org


"Why is my syncdb with superuser failing with a DatabaseError?"
===============================================================

More specifically, this specific ``DatabaseError``::

django.db.utils.DatabaseError: no such table: tastypie_apikey

This is a side effect of the (disabled by default) ``create_api_key`` signal
as described in the :ref:`authentication` section of the
documentation when used in conjunction with South.

To work around this issue, you can disable the ``create_api_key`` signal
until you have completed running ``syncdb --migrate`` for the first time.
4 changes: 2 additions & 2 deletions docs/geodjango.rst
Expand Up @@ -6,7 +6,7 @@ GeoDjango

Tastypie features support for GeoDjango! Resources return and accept
`GeoJSON <http://geojson.org/geojson-spec.html>`_ (or similarly-formatted
analogs for other formats) and all `spatial lookup <https://docs.djangoproject.com/en/1.3/ref/contrib/gis/geoquerysets/#spatial-lookups>`_ filters are supported. Distance lookups are not yet supported.
analogs for other formats) and all `spatial lookup <https://docs.djangoproject.com/en/dev/ref/contrib/gis/geoquerysets/#spatial-lookups>`_ filters are supported. Distance lookups are not yet supported.

Usage
=====
Expand Down Expand Up @@ -61,7 +61,7 @@ GeoJSON analog for your perferred format.
Filtering
---------

We can filter using any standard GeoDjango `spatial lookup <https://docs.djangoproject.com/en/1.3/ref/contrib/gis/geoquerysets/#spatial-lookups>`_ filter. Simply provide a GeoJSON (or the analog) as a ``GET`` parameter value.
We can filter using any standard GeoDjango `spatial lookup <https://docs.djangoproject.com/en/dev/ref/contrib/gis/geoquerysets/#spatial-lookups>`_ filter. Simply provide a GeoJSON (or the analog) as a ``GET`` parameter value.

Let's find all of our ``GeoNote`` resources that contain a point inside
of `Golden Gate Park <https://sf.localwiki.org/Golden_Gate_Park>`_::
Expand Down
2 changes: 1 addition & 1 deletion docs/index.rst
Expand Up @@ -97,7 +97,7 @@ Required
--------

* Python 2.6+ or Python 3.3+
* Django 1.5+
* Django 1.7+
* dateutil (http://labix.org/python-dateutil) >= 2.1

Optional
Expand Down
2 changes: 1 addition & 1 deletion docs/python3.rst
Expand Up @@ -14,7 +14,7 @@ to run your existing software without modification.
All tests pass under both Python 2 & 3.

.. _`six`: http://pythonhosted.org/six/
.. _`Django`: https://docs.djangoproject.com/en/1.5/topics/python3/#str-and-unicode-methods
.. _`Django`: https://docs.djangoproject.com/en/dev/topics/python3/#str-and-unicode-methods


Incompatibilities
Expand Down
2 changes: 1 addition & 1 deletion docs/tutorial.rst
Expand Up @@ -60,7 +60,7 @@ your project or ``PYTHONPATH``.
1. Download the dependencies:

* Python 2.6+ or Python 3.3+
* Django 1.5+
* Django 1.7+
* ``python-mimeparse`` 0.1.4+ (http://pypi.python.org/pypi/python-mimeparse)
* ``dateutil`` (http://labix.org/python-dateutil)
* **OPTIONAL** - ``lxml`` (http://lxml.de/) and ``defusedxml`` (https://pypi.python.org/pypi/defusedxml) if using the XML serializer
Expand Down
1 change: 0 additions & 1 deletion setup.py
Expand Up @@ -21,7 +21,6 @@
'tastypie.utils',
'tastypie.management',
'tastypie.management.commands',
'tastypie.south_migrations',
'tastypie.migrations',
'tastypie.contrib',
'tastypie.contrib.gis',
Expand Down
16 changes: 6 additions & 10 deletions tastypie/authentication.py
@@ -1,5 +1,6 @@
from __future__ import unicode_literals
import base64
from hashlib import sha1
import hmac
import time
import uuid
Expand All @@ -10,14 +11,9 @@
from django.middleware.csrf import _sanitize_token, constant_time_compare
from django.utils.http import same_origin
from django.utils.translation import ugettext as _
from tastypie.http import HttpUnauthorized
from tastypie.compat import get_user_model, get_username_field

try:
from hashlib import sha1
except ImportError:
import sha
sha1 = sha.sha
from tastypie.compat import get_user_model, get_username_field
from tastypie.http import HttpUnauthorized

try:
import python_digest
Expand Down Expand Up @@ -189,8 +185,8 @@ def is_authenticated(self, request, **kwargs):
username_field = get_username_field()
User = get_user_model()

lookup_kwargs = {username_field: username}
try:
lookup_kwargs = {username_field: username}
user = User.objects.select_related('api_key').get(**lookup_kwargs)
except (User.DoesNotExist, User.MultipleObjectsReturned):
return self._unauthorized()
Expand Down Expand Up @@ -315,7 +311,7 @@ def _unauthorized(self):
opaque = hmac.new(str(new_uuid).encode('utf-8'), digestmod=sha1).hexdigest()
response['WWW-Authenticate'] = python_digest.build_digest_challenge(
timestamp=time.time(),
secret=getattr(settings, 'SECRET_KEY', ''),
secret=settings.SECRET_KEY,
realm=self.realm,
opaque=opaque,
stale=False
Expand Down Expand Up @@ -343,7 +339,7 @@ def is_authenticated(self, request, **kwargs):
digest_response = python_digest.parse_digest_credentials(request.META['HTTP_AUTHORIZATION'])

# FIXME: Should the nonce be per-user?
if not python_digest.validate_nonce(digest_response.nonce, getattr(settings, 'SECRET_KEY', '')):
if not python_digest.validate_nonce(digest_response.nonce, settings.SECRET_KEY):
return self._unauthorized()

user = self.get_user(digest_response.username)
Expand Down
26 changes: 7 additions & 19 deletions tastypie/compat.py
Expand Up @@ -2,33 +2,21 @@

import django
from django.conf import settings
from django.contrib.auth import get_user_model # flake8: noqa


__all__ = ['get_user_model', 'get_username_field', 'AUTH_USER_MODEL']

AUTH_USER_MODEL = getattr(settings, 'AUTH_USER_MODEL', 'auth.User')

# Django 1.5+ compatibility
if django.VERSION >= (1, 5):
def get_user_model():
from django.contrib.auth import get_user_model as django_get_user_model
AUTH_USER_MODEL = settings.AUTH_USER_MODEL

return django_get_user_model()

def get_username_field():
return get_user_model().USERNAME_FIELD
else:
def get_user_model():
from django.contrib.auth.models import User

return User

def get_username_field():
return 'username'
def get_username_field():
return get_user_model().USERNAME_FIELD


def get_module_name(meta):
return getattr(meta, 'model_name', None) or getattr(meta, 'module_name')
return meta.model_name


# commit_on_success replaced by atomic in Django >=1.8
atomic_decorator = getattr(django.db.transaction, 'atomic', None) or getattr(django.db.transaction, 'commit_on_success')
atomic_decorator = django.db.transaction.atomic
4 changes: 1 addition & 3 deletions tastypie/contrib/contenttypes/resources.py
Expand Up @@ -10,9 +10,7 @@ class GenericResource(ModelResource):
Provides a stand-in resource for GFK relations.
"""
def __init__(self, resources, *args, **kwargs):
self.resource_mapping = dict(
(r._meta.resource_name, r) for r in resources
)
self.resource_mapping = {r._meta.resource_name: r for r in resources}
super(GenericResource, self).__init__(*args, **kwargs)

def get_via_uri(self, uri, request=None):
Expand Down
14 changes: 7 additions & 7 deletions tastypie/fields.py
Expand Up @@ -4,11 +4,7 @@
from dateutil.parser import parse
import decimal
from decimal import Decimal

try:
import importlib
except ImportError:
from django.utils import importlib
import importlib

from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
from django.db.models.fields.related import SingleRelatedObjectDescriptor
Expand Down Expand Up @@ -280,7 +276,7 @@ def convert(self, value):
if value is None:
return None

return Decimal(str(value))
return Decimal(value)

def hydrate(self, bundle):
value = super(DecimalField, self).hydrate(bundle)
Expand Down Expand Up @@ -624,7 +620,11 @@ def resource_from_data(self, fk_resource, data, request=None, related_obj=None,
fk_bundle.related_obj = related_obj
fk_bundle.related_name = related_name

unique_keys = dict((k, v) for k, v in data.items() if k == 'pk' or (hasattr(fk_resource, k) and getattr(fk_resource, k).unique))
unique_keys = {
k: v
for k, v in data.items()
if k == 'pk' or (hasattr(fk_resource, k) and getattr(fk_resource, k).unique)
}

# If we have no unique keys, we shouldn't go look for some resource that
# happens to match other kwargs. In the case of a create, it might be the
Expand Down
7 changes: 1 addition & 6 deletions tastypie/models.py
@@ -1,5 +1,6 @@
from __future__ import unicode_literals

from hashlib import sha1
import hmac
import time

Expand All @@ -9,12 +10,6 @@

from tastypie.utils import now

try:
from hashlib import sha1
except ImportError:
import sha
sha1 = sha.sha


@python_2_unicode_compatible
class ApiAccess(models.Model):
Expand Down
16 changes: 4 additions & 12 deletions tastypie/resources.py
@@ -1,5 +1,4 @@
from __future__ import unicode_literals
from __future__ import with_statement
from copy import deepcopy
from datetime import datetime
import logging
Expand All @@ -23,9 +22,10 @@
from django.db.models.constants import LOOKUP_SEP
from django.db.models.sql.constants import QUERY_TERMS
from django.http import HttpResponse, HttpResponseNotFound, Http404
from django.utils import six
from django.utils.cache import patch_cache_control, patch_vary_headers
from django.utils.html import escape
from django.utils import six
from django.views.decorators.csrf import csrf_exempt

from tastypie.authentication import Authentication
from tastypie.authorization import ReadOnlyAuthorization
Expand All @@ -45,13 +45,6 @@
from tastypie.validation import Validation
from tastypie.compat import get_module_name, atomic_decorator

# If ``csrf_exempt`` isn't present, stub it.
try:
from django.views.decorators.csrf import csrf_exempt
except ImportError:
def csrf_exempt(func):
return func


def sanitize(text):
# We put the single quotes back, due to their frequent usage in exception
Expand Down Expand Up @@ -288,9 +281,8 @@ def _handle_500(self, request, exception):

# When DEBUG is False, send an error message to the admins (unless it's
# a 404, in which case we check the setting).
send_broken_links = getattr(settings, 'SEND_BROKEN_LINK_EMAILS', False)

if not response_code == 404 or send_broken_links:
if not response_code == 404:
log = logging.getLogger('django.request.tastypie')
log.error('Internal Server Error: %s' % request.path, exc_info=True,
extra={'status_code': response_code, 'request': request})
Expand Down Expand Up @@ -2124,7 +2116,7 @@ def obj_get(self, bundle, **kwargs):
field_names = self._meta.object_class._meta.get_all_field_names()
field_names.append('pk')

kwargs = dict([(k, v,) for k, v in kwargs.items() if k in field_names])
kwargs = {k: v for k, v in kwargs.items() if k in field_names}

try:
object_list = self.get_object_list(bundle.request).filter(**kwargs)
Expand Down
16 changes: 10 additions & 6 deletions tastypie/serializers.py
Expand Up @@ -297,15 +297,15 @@ def to_simple(self, data, options):
return data
if stype == _DICT:
to_simple = self.to_simple
return dict([(key, to_simple(val, options)) for key, val in six.iteritems(data)])
return {key: to_simple(val, options) for key, val in six.iteritems(data)}
if stype == _STR:
return force_text(data)
if stype == _LIST:
to_simple = self.to_simple
return [to_simple(item, options) for item in data]
if stype == _BUNDLE:
to_simple = self.to_simple
return dict([(key, to_simple(val, options)) for key, val in six.iteritems(data.data)])
return {key: to_simple(val, options) for key, val in six.iteritems(data.data)}
if stype == _DATETIME:
return self.format_datetime(data)
if stype == _DATE:
Expand Down Expand Up @@ -373,11 +373,15 @@ def from_etree(self, data):
for element in elements:
if element.tag in ('object', 'objects'):
return self.from_etree(element)
return dict((element.tag, self.from_etree(element))
for element in elements)
return {
element.tag: self.from_etree(element)
for element in elements
}
elif data.tag == 'object' or data.get('type') == 'hash':
return dict((element.tag, self.from_etree(element))
for element in data.getchildren())
return {
element.tag: self.from_etree(element)
for element in data.getchildren()
}
elif data.tag == 'objects' or data.get('type') == 'list':
return [self.from_etree(element) for element in data.getchildren()]
else:
Expand Down

0 comments on commit 39c6308

Please sign in to comment.