Skip to content

Commit

Permalink
Version 0.2.2
Browse files Browse the repository at this point in the history
  • Loading branch information
Chibisov Gennady committed Mar 23, 2014
1 parent 1706579 commit 28562e4
Show file tree
Hide file tree
Showing 14 changed files with 157 additions and 25 deletions.
6 changes: 5 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ env:
- TOX_ENV=py27-drf2.3.10
- TOX_ENV=py27-drf2.3.11
- TOX_ENV=py27-drf2.3.12
- TOX_ENV=py33-drf2.3.12
- TOX_ENV=py27-drf2.3.13
- TOX_ENV=py33
- TOX_ENV=django1.5.5
- TOX_ENV=django1.6.2
- TOX_ENV=django1.7

script:
- tox -e $TOX_ENV -- tests_app
29 changes: 27 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ Full documentation for project is available at [http://chibisov.github.io/drf-ex
## Requirements

* Tested for python 2.7 and 3.3 versions
* Tested for all releases of Django Rest Framework from 2.3.5 to 2.3.12 versions
* Tested for all releases of Django Rest Framework from 2.3.5 to 2.3.13 versions
* Tested for Django 1.5.5, 1.6.2 and 1.7

## Installation:

Expand Down Expand Up @@ -60,4 +61,28 @@ Run tests from exact module:
Build docs:

$ cd docs
$ python backdoc.py --source index.md --title "Django Rest Framework extensions documentation" > index.html
$ python backdoc.py --source index.md --title "Django Rest Framework extensions documentation" > index.html

## Publishing new releases

Increment version in `rest_framework_extensions.__init__.py`. For example:

__version__ = '0.2.2' # from 0.2.1

Add new tag version for commit:

$ git tag 0.2.2

Push to master with tags:

$ git push origin master --tags

Don't forget to merge `master` to `gh-pages` branch and push to origin:

$ git co gh-pages
$ git merge --no-ff master
$ git push origin gh-pages

Publish to pypi:

$ python setup.py publish
Binary file modified docs/index.html
Binary file not shown.
9 changes: 6 additions & 3 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ If you use `DetailSerializerMixin` and don't specify `queryset_detail` attribute

#### PaginateByMaxMixin

*New in DRF-extensions Development version*
*New in DRF-extensions 0.2.2*

This mixin allows to paginate results by [max\_paginate\_by](http://www.django-rest-framework.org/api-guide/pagination#pagination-in-the-generic-views)
value. This approach is useful when clients want to take as much paginated data as possible,
Expand Down Expand Up @@ -332,7 +332,7 @@ Extensions for [permissions](http://www.django-rest-framework.org/api-guide/perm

#### Object permissions

*New in DRF-extensions Development version*
*New in DRF-extensions 0.2.2*

Django Rest Framework allows you to use [DjangoObjectPermissions](http://www.django-rest-framework.org/api-guide/permissions#djangoobjectpermissions) out of the box. But it has one limitation - if user has no permissions for viewing resource he will get `404` as response code. In most cases it's good approach because it solves security issues by default. But what if you wanted to return `401` or `403`? What if you wanted to say to user - "You need to be logged in for viewing current resource" or "You don't have permissions for viewing current resource"?

Expand Down Expand Up @@ -1482,10 +1482,13 @@ If you need to access the values of DRF-exteinsions API settings in your project
You can read about versioning, deprecation policy and upgrading from
[Django REST framework documentation](http://django-rest-framework.org/topics/release-notes).

#### New in development version
#### 0.2.2

*Mar. 23, 2014*

* Added [PaginateByMaxMixin](#paginatebymaxmixin)
* Added [ExtenedDjangoObjectPermissions](#object-permissions)
* Added tests for django 1.7

#### 0.2.1

Expand Down
2 changes: 1 addition & 1 deletion rest_framework_extensions/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
__version__ = '0.2.1'
__version__ = '0.2.2'

VERSION = __version__
31 changes: 23 additions & 8 deletions rest_framework_extensions/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -550,13 +550,10 @@ def check_nonce(request, oauth_request, oauth_nonce, oauth_timestamp):

# 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
import provider as oauth2_provider
from provider import scope as oauth2_provider_scope
from provider import constants as oauth2_constants
from provider import __version__ as provider_version
if provider_version in ('0.2.3', '0.2.4'):
if oauth2_provider.__version__ in ('0.2.3', '0.2.4'):
# 0.2.3 and 0.2.4 are supported version that do not support
# timezone aware datetimes
import datetime
Expand All @@ -566,8 +563,6 @@ def check_nonce(request, oauth_request, oauth_nonce, oauth_timestamp):
from django.utils.timezone import now as provider_now
except ImportError:
oauth2_provider = None
oauth2_provider_models = None
oauth2_provider_forms = None
oauth2_provider_scope = None
oauth2_constants = None
provider_now = None
Expand All @@ -583,4 +578,24 @@ def is_non_str_iterable(obj):
return hasattr(obj, '__iter__')
else:
def is_non_str_iterable(obj):
return hasattr(obj, '__iter__')
return hasattr(obj, '__iter__')


try:
from django.utils.encoding import python_2_unicode_compatible
except ImportError:
def python_2_unicode_compatible(klass):
"""
A decorator that defines __unicode__ and __str__ methods under Python 2.
Under Python 3 it does nothing.
To support Python 2 and 3 with a single code base, define a __str__ method
returning text and apply this decorator to the class.
"""
if '__str__' not in klass.__dict__:
raise ValueError("@python_2_unicode_compatible cannot be applied "
"to %s because it doesn't define __str__()." %
klass.__name__)
klass.__unicode__ = klass.__str__
klass.__str__ = lambda self: self.__unicode__().encode('utf-8')
return klass
16 changes: 15 additions & 1 deletion rest_framework_extensions/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from django.test.client import Client as DjangoClient
from django.test.client import ClientHandler
from django.test import testcases
from django.utils.http import urlencode
from rest_framework.settings import api_settings
from rest_framework_extensions.compat import RequestFactory as DjangoRequestFactory # changed here
from rest_framework_extensions.compat import force_bytes_or_smart_bytes, six # changed here
Expand Down Expand Up @@ -71,6 +72,17 @@ def _encode_data(self, data, format=None, content_type=None):

return ret, content_type

def get(self, path, data=None, **extra):
r = {
'QUERY_STRING': urlencode(data or {}, doseq=True),
}
# Fix to support old behavior where you have the arguments in the url
# See #1461
if not data and '?' in path:
r['QUERY_STRING'] = path.split('?')[1]
r.update(extra)
return self.generic('GET', path, **r)

def post(self, path, data=None, format=None, content_type=None, **extra):
data, content_type = self._encode_data(data, format, content_type)
return self.generic('POST', path, data, content_type, **extra)
Expand Down Expand Up @@ -134,6 +146,8 @@ def force_authenticate(self, user=None, token=None):
"""
self.handler._force_user = user
self.handler._force_token = token
if user is None:
self.logout() # Also clear any possible session info if required

def request(self, **kwargs):
# Ensure that any credentials set get added to every request.
Expand All @@ -154,4 +168,4 @@ class APISimpleTestCase(testcases.SimpleTestCase):
client_class = APIClient

class APILiveServerTestCase(testcases.LiveServerTestCase):
client_class = APIClient
client_class = APIClient
8 changes: 8 additions & 0 deletions rest_framework_extensions/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import itertools
from functools import wraps

from django import VERSION as django_version
from django.utils.decorators import available_attrs

import rest_framework
Expand All @@ -22,6 +23,13 @@ def get_rest_framework_features():
}


def get_django_features():
# todo: test me
return {
'has_odd_space_in_sql_query': django_version < (1, 7, 0)
}


def get_rest_framework_version():
return tuple(map(int, rest_framework.VERSION.split('.')))

Expand Down
10 changes: 10 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from setuptools import setup
import re
import os
import sys


def get_version(package):
Expand Down Expand Up @@ -41,6 +42,15 @@ def get_package_data(package):
version = get_version('rest_framework_extensions')


if sys.argv[-1] == 'publish':
os.system("python setup.py sdist upload")
# os.system("python setup.py bdist_wheel upload") # todo
print("You probably want to also tag the version now:")
print(" git tag -a %s -m 'version %s'" % (version, version))
print(" git push --tags")
sys.exit()


setup(
name='drf-extensions',
version=version,
Expand Down
1 change: 0 additions & 1 deletion tests_app/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
Django>=1.5.0
nose
django-nose
mock
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from django.contrib.contenttypes.models import ContentType

from rest_framework import status
from rest_framework_extensions.test import APITestCase

from rest_framework_extensions.compat import guardian, get_model_name
from rest_framework_extensions.utils import get_rest_framework_features
Expand Down Expand Up @@ -78,7 +79,7 @@ def setUp(self):
"Current DRF version doesn't support DjangoObjectPermissions"
)
class ExtendedDjangoObjectPermissionsTest_should_inherit_standard(ExtendedDjangoObjectPermissionTestMixin,
TestCase):
APITestCase):
urls = urlpatterns

# Delete
Expand Down Expand Up @@ -157,7 +158,7 @@ def test_cannot_read_list_permissions(self):
"Current DRF version doesn't support DjangoObjectPermissions"
)
class ExtendedDjangoObjectPermissionsTest_without_hiding_forbidden_objects(ExtendedDjangoObjectPermissionTestMixin,
TestCase):
APITestCase):
urls = urlpatterns

# Delete
Expand Down
2 changes: 1 addition & 1 deletion tests_app/tests/unit/key_constructor/bits/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@


class BitTestModel(models.Model):
is_active = models.BooleanField()
is_active = models.BooleanField(default=False)

class Meta:
app_label = 'tests_app'
17 changes: 15 additions & 2 deletions tests_app/tests/unit/key_constructor/bits/tests.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
# -*- coding: utf-8 -*-
from mock import Mock

import django
from django.test import TestCase
from django.utils.translation import override

from rest_framework import views
from rest_framework.response import Response
from rest_framework_extensions.test import APIRequestFactory
from rest_framework_extensions.utils import get_django_features

from rest_framework_extensions.key_constructor.bits import (
KeyBitDictBase,
Expand Down Expand Up @@ -373,7 +375,12 @@ def setUp(self):
def test_should_use_view__get_queryset__and_filter_it_with__filter_queryset(self):
expected = (u'SELECT "tests_app_bittestmodel"."id", "tests_app_bittestmodel"."is_active" '
u'FROM "tests_app_bittestmodel" '
u'WHERE "tests_app_bittestmodel"."is_active" = True ')
u'WHERE "tests_app_bittestmodel"."is_active" = True{space}')
if get_django_features()['has_odd_space_in_sql_query']:
space = ' '
else:
space = ''
expected = expected.format(space=space)
response = ListSqlQueryKeyBit().get_data(**self.kwargs)
self.assertEqual(response, expected)

Expand All @@ -396,7 +403,13 @@ def setUp(self):
def test_should_use_view__get_queryset__and_filter_it_with__filter_queryset__and_filter_by__lookup_field(self):
expected = (u'SELECT "tests_app_bittestmodel"."id", "tests_app_bittestmodel"."is_active" '
u'FROM "tests_app_bittestmodel" '
u'WHERE ("tests_app_bittestmodel"."is_active" = True AND "tests_app_bittestmodel"."id" = 123 )')
u'WHERE ("tests_app_bittestmodel"."is_active" = True {space}AND "tests_app_bittestmodel"."id" = 123{space})')
if get_django_features()['has_odd_space_in_sql_query']:
space = ' '
else:
space = ''
expected = expected.format(space=space)

response = RetrieveSqlQueryKeyBit().get_data(**self.kwargs)
self.assertEqual(response, expected)

Expand Down
Loading

0 comments on commit 28562e4

Please sign in to comment.