Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,12 @@ before_install:
# Force an upgrade of py & pytest to avoid VersionConflict
- pip install --upgrade py
- pip install "pytest>=2.8,<3"
- pip install codecov
- pip install codecov flake8
install:
- pip install Django${DJANGO} djangorestframework${DRF}
- python setup.py install
script:
- flake8
- coverage run setup.py -v test
after_success:
- codecov
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ Jerel Unruh <mail@unruhdesigns.com>
Greg Aker <greg@gregaker.net>
Adam Wróbel <https://adamwrobel.com>
Christian Zosel <https://zosel.ch>
Oliver Sauder <os@esite.ch>

1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ v2.3.0
and there was no way to turn it off.
* Fix for apps that don't use `django.contrib.contenttypes`.
* Fix `resource_name` support for POST requests and nested serializers
* Enforcing flake8 linting

v2.2.0

Expand Down
1 change: 0 additions & 1 deletion example/api/resources/identity.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ class GenericIdentity(generics.GenericAPIView):
renderer_classes = (renderers.JSONRenderer, )
parser_classes = (parsers.JSONParser, )


def get_queryset(self):
return auth_models.User.objects.all()

Expand Down
3 changes: 2 additions & 1 deletion example/api/serializers/identity.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ class IdentitySerializer(serializers.ModelSerializer):
"""
Identity Serializer
"""

def validate_first_name(self, data):
if len(data) > 10:
raise serializers.ValidationError(
'There\'s a problem with first name')
'There\'s a problem with first name')
return data

def validate_last_name(self, data):
Expand Down
1 change: 0 additions & 1 deletion example/api/serializers/post.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,3 @@ class PostSerializer(serializers.Serializer):
Blog post serializer
"""
title = serializers.CharField(max_length=50)

2 changes: 2 additions & 0 deletions example/factories/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
faker = FakerFactory.create()
faker.seed(983843)


class BlogFactory(factory.django.DjangoModelFactory):
class Meta:
model = Blog
Expand All @@ -23,6 +24,7 @@ class Meta:

bio = factory.RelatedFactory('example.factories.AuthorBioFactory', 'author')


class AuthorBioFactory(factory.django.DjangoModelFactory):
class Meta:
model = AuthorBio
Expand Down
1 change: 0 additions & 1 deletion example/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,3 @@ class Comment(BaseModel):

def __str__(self):
return self.body

14 changes: 7 additions & 7 deletions example/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def get_copyright(self, resource):

def get_root_meta(self, resource, many):
return {
'api_docs': '/docs/api/blogs'
'api_docs': '/docs/api/blogs'
}

class Meta:
Expand Down Expand Up @@ -55,17 +55,17 @@ def __init__(self, *args, **kwargs):
body_format = serializers.SerializerMethodField()
# many related from model
comments = relations.ResourceRelatedField(
many=True, read_only=True)
many=True, read_only=True)
# many related from serializer
suggested = relations.SerializerMethodResourceRelatedField(
source='get_suggested', model=Entry, many=True, read_only=True,
related_link_view_name='entry-suggested',
related_link_url_kwarg='entry_pk',
self_link_view_name='entry-relationships',
source='get_suggested', model=Entry, many=True, read_only=True,
related_link_view_name='entry-suggested',
related_link_url_kwarg='entry_pk',
self_link_view_name='entry-relationships',
)
# single related from serializer
featured = relations.SerializerMethodResourceRelatedField(
source='get_featured', model=Entry, read_only=True)
source='get_featured', model=Entry, read_only=True)
tags = TaggedItemSerializer(many=True, read_only=True)

def get_suggested(self, obj):
Expand Down
2 changes: 1 addition & 1 deletion example/settings/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
from .dev import *
from .dev import * # noqa
2 changes: 1 addition & 1 deletion example/settings/test.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from .dev import *
from .dev import * # noqa

DATABASES = {
'default': {
Expand Down
4 changes: 2 additions & 2 deletions example/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class TestBase(APITestCase):
"""
Test base class to setup a couple users.
"""

def setUp(self):
"""
Create those users
Expand All @@ -15,7 +16,7 @@ def setUp(self):
self.create_users()

def create_user(self, username, email, password="pw",
first_name='', last_name=''):
first_name='', last_name=''):
"""
Helper method to create a user
"""
Expand All @@ -39,4 +40,3 @@ def create_users(self):
self.miles = self.create_user(
'miles', 'miles@example.com',
first_name="Miles", last_name="Davis")

5 changes: 3 additions & 2 deletions example/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import pytest
from pytest_factoryboy import register

from example.factories import BlogFactory, AuthorFactory, AuthorBioFactory, EntryFactory, CommentFactory, \
from example.factories import (
BlogFactory, AuthorFactory, AuthorBioFactory, EntryFactory, CommentFactory,
TaggedItemFactory
)

register(BlogFactory)
register(AuthorFactory)
Expand Down Expand Up @@ -31,4 +33,3 @@ def multiple_entries(blog_factory, author_factory, entry_factory, comment_factor
comment_factory(entry=entries[0])
comment_factory(entry=entries[1])
return entries

32 changes: 23 additions & 9 deletions example/tests/integration/test_includes.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,21 @@


def test_default_included_data_on_list(multiple_entries, client):
return test_included_data_on_list(multiple_entries=multiple_entries, client=client, query='?page_size=5')
return test_included_data_on_list(
multiple_entries=multiple_entries, client=client, query='?page_size=5'
)


def test_included_data_on_list(multiple_entries, client, query='?include=comments&page_size=5'):
response = client.get(reverse("entry-list") + query)
included = load_json(response.content).get('included')

assert len(load_json(response.content)['data']) == len(multiple_entries), 'Incorrect entry count'
assert [x.get('type') for x in included] == ['comments', 'comments'], 'List included types are incorrect'
assert len(load_json(response.content)['data']) == len(multiple_entries), (
'Incorrect entry count'
)
assert [x.get('type') for x in included] == ['comments', 'comments'], (
'List included types are incorrect'
)

comment_count = len([resource for resource in included if resource["type"] == "comments"])
expected_comment_count = sum([entry.comments.count() for entry in multiple_entries])
Expand All @@ -39,7 +45,9 @@ def test_included_data_on_detail(single_entry, client, query='?include=comments'

def test_dynamic_related_data_is_included(single_entry, entry_factory, client):
entry_factory()
response = client.get(reverse("entry-detail", kwargs={'pk': single_entry.pk}) + '?include=featured')
response = client.get(
reverse("entry-detail", kwargs={'pk': single_entry.pk}) + '?include=featured'
)
included = load_json(response.content).get('included')

assert [x.get('type') for x in included] == ['entries'], 'Dynamic included types are incorrect'
Expand All @@ -48,7 +56,9 @@ def test_dynamic_related_data_is_included(single_entry, entry_factory, client):

def test_dynamic_many_related_data_is_included(single_entry, entry_factory, client):
entry_factory()
response = client.get(reverse("entry-detail", kwargs={'pk': single_entry.pk}) + '?include=suggested')
response = client.get(
reverse("entry-detail", kwargs={'pk': single_entry.pk}) + '?include=suggested'
)
included = load_json(response.content).get('included')

assert included
Expand All @@ -58,12 +68,12 @@ def test_dynamic_many_related_data_is_included(single_entry, entry_factory, clie
def test_missing_field_not_included(author_bio_factory, author_factory, client):
# First author does not have a bio
author = author_factory(bio=None)
response = client.get(reverse('author-detail', args=[author.pk])+'?include=bio')
response = client.get(reverse('author-detail', args=[author.pk]) + '?include=bio')
data = load_json(response.content)
assert 'included' not in data
# Second author does
author = author_factory()
response = client.get(reverse('author-detail', args=[author.pk])+'?include=bio')
response = client.get(reverse('author-detail', args=[author.pk]) + '?include=bio')
data = load_json(response.content)
assert 'included' in data
assert len(data['included']) == 1
Expand All @@ -75,7 +85,9 @@ def test_deep_included_data_on_list(multiple_entries, client):
'comments.author.bio&page_size=5')
included = load_json(response.content).get('included')

assert len(load_json(response.content)['data']) == len(multiple_entries), 'Incorrect entry count'
assert len(load_json(response.content)['data']) == len(multiple_entries), (
'Incorrect entry count'
)
assert [x.get('type') for x in included] == [
'authorBios', 'authorBios', 'authors', 'authors', 'comments', 'comments'
], 'List included types are incorrect'
Expand All @@ -99,7 +111,9 @@ def test_deep_included_data_on_list(multiple_entries, client):
'comments.author.bio&page_size=5')
included = load_json(response.content).get('included')

assert len(load_json(response.content)['data']) == len(multiple_entries), 'Incorrect entry count'
assert len(load_json(response.content)['data']) == len(multiple_entries), (
'Incorrect entry count'
)
assert [x.get('type') for x in included] == [
'authorBios', 'authorBios', 'authors', 'authors', 'authors', 'authors',
'comments', 'comments'], 'List included types are incorrect'
Expand Down
37 changes: 30 additions & 7 deletions example/tests/integration/test_model_resource_name.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ def _check_resource_and_relationship_comment_type_match(django_client):
comment_relationship_type = load_json(entry_response.content).get(
'data')[0].get('relationships').get('comments').get('data')[0].get('type')

assert comment_resource_type == comment_relationship_type, "The resource type seen in the relationships and head resource do not match"
assert comment_resource_type == comment_relationship_type, (
"The resource type seen in the relationships and head resource do not match"
)


def _check_relationship_and_included_comment_type_are_the_same(django_client, url):
Expand All @@ -33,7 +35,9 @@ def _check_relationship_and_included_comment_type_are_the_same(django_client, ur
comment_relationship_type = data.get('relationships').get('comments').get('data')[0].get('type')
comment_included_type = comment.get('type')

assert comment_relationship_type == comment_included_type, "The resource type seen in the relationships and included do not match"
assert comment_relationship_type == comment_included_type, (
"The resource type seen in the relationships and included do not match"
)


@pytest.mark.usefixtures("single_entry")
Expand Down Expand Up @@ -81,7 +85,12 @@ def test_resource_name_precendence(self, client, monkeypatch):
'resource_name from model incorrect on list')

# serializer > model
monkeypatch.setattr(serializers.CommentSerializer.Meta, 'resource_name', 'resource_name_from_serializer', False)
monkeypatch.setattr(
serializers.CommentSerializer.Meta,
'resource_name',
'resource_name_from_serializer',
False
)
response = client.get(reverse("comment-list"))
data = load_json(response.content)['data'][0]
assert (data.get('type') == 'resource_name_from_serializer'), (
Expand All @@ -104,8 +113,18 @@ def test_model_resource_name_create(self, client):
assert response.status_code == status.HTTP_201_CREATED

def test_serializer_resource_name_create(self, client, monkeypatch):
monkeypatch.setattr(serializers.CommentSerializer.Meta, 'resource_name', 'renamed_comments', False)
monkeypatch.setattr(serializers.EntrySerializer.Meta, 'resource_name', 'renamed_entries', False)
monkeypatch.setattr(
serializers.CommentSerializer.Meta,
'resource_name',
'renamed_comments',
False
)
monkeypatch.setattr(
serializers.EntrySerializer.Meta,
'resource_name',
'renamed_entries',
False
)
create_data = deepcopy(self.create_data)
create_data['data']['type'] = 'renamed_comments'
create_data['data']['relationships']['entry']['data']['type'] = 'renamed_entries'
Expand Down Expand Up @@ -143,7 +162,9 @@ def test_type_match_on_included_and_inline_without_serializer_resource_name(self

_check_relationship_and_included_comment_type_are_the_same(client, reverse("entry-list"))

def test_type_match_on_included_and_inline_with_serializer_resource_name_and_JSONAPIMeta(self, client):
def test_type_match_on_included_and_inline_with_serializer_resource_name_and_JSONAPIMeta(
self, client
):
models.Comment.__bases__ += (_PatchedModel,)
serializers.CommentSerializer.Meta.resource_name = "resource_name_from_serializer"

Expand All @@ -163,7 +184,9 @@ def test_resource_and_relationship_type_match_with_JSONAPIMeta(self, client):

_check_resource_and_relationship_comment_type_match(client)

def test_resource_and_relationship_type_match_with_serializer_resource_name_and_JSONAPIMeta(self, client):
def test_resource_and_relationship_type_match_with_serializer_resource_name_and_JSONAPIMeta(
self, client
):
models.Comment.__bases__ += (_PatchedModel,)
serializers.CommentSerializer.Meta.resource_name = "resource_name_from_serializer"

Expand Down
1 change: 0 additions & 1 deletion example/tests/integration/test_non_paginated_responses.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from django.core.urlresolvers import reverse
from django.conf import settings

try:
from unittest import mock
Expand Down
11 changes: 6 additions & 5 deletions example/tests/integration/test_pagination.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

pytestmark = pytest.mark.django_db


@mock.patch(
'rest_framework_json_api.utils'
'.get_default_included_resources_from_serializer',
Expand Down Expand Up @@ -62,11 +63,11 @@ def test_pagination_with_single_entry(single_entry, client):
}
}],
"links": {
"first": "http://testserver/entries?page=1",
"last": "http://testserver/entries?page=1",
"next": None,
"prev": None,
},
"first": "http://testserver/entries?page=1",
"last": "http://testserver/entries?page=1",
"next": None,
"prev": None,
},
"meta":
{
"pagination":
Expand Down
3 changes: 2 additions & 1 deletion example/tests/integration/test_sparse_fieldsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@
def test_sparse_fieldset_ordered_dict_error(multiple_entries, client):
base_url = reverse('entry-list')
querystring = '?fields[entries]=blog,headline'
response = client.get(base_url + querystring) # RuntimeError: OrderedDict mutated during iteration
# RuntimeError: OrderedDict mutated during iteration
response = client.get(base_url + querystring)
assert response.status_code == 200 # succeed if we didn't fail due to the above RuntimeError
1 change: 0 additions & 1 deletion example/tests/test_format_keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ def setUp(self):
super(FormatKeysSetTests, self).setUp()
self.detail_url = reverse('user-detail', kwargs={'pk': self.miles.pk})


def test_camelization(self):
"""
Test that camelization works.
Expand Down
5 changes: 1 addition & 4 deletions example/tests/test_generic_validation.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import json

from django.core.urlresolvers import reverse
from django.conf import settings

from rest_framework.serializers import ValidationError

from example.tests import TestBase
from example.tests.utils import load_json
Expand All @@ -13,6 +9,7 @@ class GenericValidationTest(TestBase):
"""
Test that a non serializer specific validation can be thrown and formatted
"""

def setUp(self):
super(GenericValidationTest, self).setUp()
self.url = reverse('user-validation', kwargs={'pk': self.miles.pk})
Expand Down
3 changes: 0 additions & 3 deletions example/tests/test_generic_viewset.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import json

from django.core.urlresolvers import reverse
from django.conf import settings

Expand Down Expand Up @@ -42,7 +40,6 @@ def test_default_rest_framework_behavior(self):

assert expected == parsed_content


def test_ember_expected_renderer(self):
"""
The :class:`UserEmber` ViewSet has the ``resource_name`` of 'data'
Expand Down
Loading