diff --git a/sqlalchemy_jsonapi/__init__.py b/sqlalchemy_jsonapi/__init__.py index 9f9fd7f..3545260 100644 --- a/sqlalchemy_jsonapi/__init__.py +++ b/sqlalchemy_jsonapi/__init__.py @@ -1,10 +1,10 @@ -from .constants import Endpoint, Method -from .serializer import (ALL_PERMISSIONS, INTERACTIVE_PERMISSIONS, JSONAPI, - AttributeActions, Permissions, RelationshipActions, - attr_descriptor, permission_test, - relationship_descriptor) +from .constants import Endpoint, Method # NOQA +from .serializer import ( # NOQA + ALL_PERMISSIONS, INTERACTIVE_PERMISSIONS, JSONAPI, AttributeActions, + Permissions, RelationshipActions, attr_descriptor, permission_test, + relationship_descriptor) try: from .flaskext import FlaskJSONAPI except ImportError: - FlaskJSONAPI = None \ No newline at end of file + FlaskJSONAPI = None diff --git a/sqlalchemy_jsonapi/constants.py b/sqlalchemy_jsonapi/constants.py index c7b519a..7f1d624 100644 --- a/sqlalchemy_jsonapi/constants.py +++ b/sqlalchemy_jsonapi/constants.py @@ -27,4 +27,4 @@ class Endpoint(Enum): COLLECTION = '/' RESOURCE = '//' RELATED = '///' - RELATIONSHIP = '///relationships/' \ No newline at end of file + RELATIONSHIP = '///relationships/' diff --git a/sqlalchemy_jsonapi/flaskext.py b/sqlalchemy_jsonapi/flaskext.py index 2548d32..1a743a9 100644 --- a/sqlalchemy_jsonapi/flaskext.py +++ b/sqlalchemy_jsonapi/flaskext.py @@ -35,6 +35,7 @@ def default(self, value): return str(value) return json.JSONEncoder.default(self, value) + #: The views to generate views = [ (Method.GET, Endpoint.COLLECTION), (Method.GET, Endpoint.RESOURCE), @@ -163,7 +164,10 @@ def _setup_adapter(self, namespace, route_prefix): :param namespace: Prefix for generated endpoints :param route_prefix: Prefix for route patterns """ - self.serializer = JSONAPI(self.sqla.Model, prefix='{}://{}{}'.format(self.app.config['PREFERRED_URL_SCHEME'], self.app.config['SERVER_NAME'], route_prefix)) + self.serializer = JSONAPI( + self.sqla.Model, prefix='{}://{}{}'.format( + self.app.config['PREFERRED_URL_SCHEME'], + self.app.config['SERVER_NAME'], route_prefix)) for view in views: method, endpoint = view pattern = route_prefix + endpoint.value diff --git a/sqlalchemy_jsonapi/serializer.py b/sqlalchemy_jsonapi/serializer.py index 16dcef1..4bb51b6 100644 --- a/sqlalchemy_jsonapi/serializer.py +++ b/sqlalchemy_jsonapi/serializer.py @@ -4,14 +4,12 @@ Colton J. Provias MIT License """ - -from collections import MutableMapping from enum import Enum -from inflection import pluralize, dasherize, parameterize, tableize, underscore + +from inflection import dasherize, tableize, underscore from sqlalchemy.exc import IntegrityError from sqlalchemy.orm.interfaces import MANYTOONE from sqlalchemy.util.langhelpers import iterate_attributes -from pprint import pprint from .errors import (BadRequestError, InvalidTypeForEndpointError, MissingTypeError, NotSortableError, PermissionDeniedError, @@ -128,6 +126,7 @@ def __call__(self, fn): fn.__jsonapi_check_permission__ |= set(self.permission) return fn + #: More consistent name for the decorators permission_test = PermissionTest @@ -227,7 +226,8 @@ def __init__(self, base, prefix=''): continue prepped_name = self._api_type_for_model(model) - api_type = getattr(model, '__jsonapi_type_override__', prepped_name) + api_type = getattr( + model, '__jsonapi_type_override__', prepped_name) model_keys = set(model.__mapper__.all_orm_descriptors.keys()) model_keys |= set(model.__mapper__.relationships.keys()) @@ -236,8 +236,10 @@ def __init__(self, base, prefix=''): model.__jsonapi_rel_desc__ = {} model.__jsonapi_permissions__ = {} model.__jsonapi_type__ = api_type - model.__jsonapi_map_to_py__ = {dasherize(underscore(x)): x for x in model_keys} - model.__jsonapi_map_to_api__ = {x: dasherize(underscore(x)) for x in model_keys} + model.__jsonapi_map_to_py__ = { + dasherize(underscore(x)): x for x in model_keys} + model.__jsonapi_map_to_api__ = { + x: dasherize(underscore(x)) for x in model_keys} for prop_name, prop_value in iterate_attributes(model): @@ -292,8 +294,10 @@ def _fetch_model(self, api_type): def _lazy_relationship(self, api_type, obj_id, rel_key): return { - 'self': '{}/{}/{}/relationships/{}'.format(self.prefix, api_type, obj_id, rel_key), - 'related': '{}/{}/{}/{}'.format(self.prefix, api_type, obj_id, rel_key) + 'self': '{}/{}/{}/relationships/{}'.format( + self.prefix, api_type, obj_id, rel_key), + 'related': '{}/{}/{}/{}'.format( + self.prefix, api_type, obj_id, rel_key) } def _get_relationship(self, resource, rel_key, permission): @@ -359,7 +363,9 @@ def _render_full_resource(self, instance, include, fields): } attrs_to_ignore = {'__mapper__', 'id'} if api_type in fields.keys(): - local_fields = list(map((lambda x: instance.__jsonapi_map_to_py__[x]), fields[api_type])) + local_fields = list(map(( + lambda x: instance.__jsonapi_map_to_py__[x]), + fields[api_type])) else: local_fields = orm_desc_keys @@ -384,23 +390,27 @@ def _render_full_resource(self, instance, include, fields): if api_key in include.keys(): related = desc(instance) if related is not None: - perm = get_permission_test(related, None, Permissions.VIEW) - if key in local_fields and (related is None or not perm(related)): + perm = get_permission_test( + related, None, Permissions.VIEW) + if (key in local_fields + and (related is None or not perm(related))): to_ret['relationships'][api_key]['data'] = None continue if key in local_fields: - to_ret['relationships'][api_key]['data'] = self._render_short_instance(related) + to_ret['relationships'][api_key]['data'] = self._render_short_instance(related) # NOQA new_include = self._parse_include(include[api_key]) - built = self._render_full_resource(related, new_include, fields) + built = self._render_full_resource( + related, new_include, fields) included = built.pop('included') to_ret['included'].update(included) - to_ret['included'][(related.__jsonapi_type__, related.id)] = built + to_ret['included'][(related.__jsonapi_type__, related.id)] = built # NOQA else: if key in local_fields: to_ret['relationships'][api_key] = { - 'links': self._lazy_relationship(api_type, instance.id, api_key), + 'links': self._lazy_relationship( + api_type, instance.id, api_key), } if api_key not in include.keys(): @@ -418,20 +428,21 @@ def _render_full_resource(self, instance, include, fields): continue if key in local_fields: - to_ret['relationships'][api_key]['data'].append(self._render_short_instance(item)) + to_ret['relationships'][api_key]['data'].append( + self._render_short_instance(item)) new_include = self._parse_include(include[api_key]) built = self._render_full_resource(item, new_include, fields) included = built.pop('included') to_ret['included'].update(included) - to_ret['included'][(item.__jsonapi_type__, item.id)] = built + to_ret['included'][(item.__jsonapi_type__, item.id)] = built # NOQA for key in set(orm_desc_keys) - attrs_to_ignore: try: desc = get_attr_desc(instance, key, AttributeActions.GET) if key in local_fields: - to_ret['attributes'][instance.__jsonapi_map_to_api__[key]] = desc(instance) + to_ret['attributes'][instance.__jsonapi_map_to_api__[key]] = desc(instance) # NOQA except PermissionDeniedError: continue @@ -756,7 +767,7 @@ def get_relationship(self, session, query, api_type, obj_id, rel_key): RelationshipActions.GET)(resource) if relationship.direction == MANYTOONE: - if related == None: + if related is None: response.data['data'] = None else: try: @@ -801,7 +812,7 @@ def patch_relationship(self, session, json_data, api_type, obj_id, try: if relationship.direction == MANYTOONE: if not isinstance(json_data['data'], dict)\ - and json_data['data'] != None: + and json_data['data'] is not None: raise ValidationError('Provided data must be a hash.') related = getattr(resource, relationship.key) @@ -811,7 +822,7 @@ def patch_relationship(self, session, json_data, api_type, obj_id, setter = get_rel_desc(resource, relationship.key, RelationshipActions.SET) - if json_data['data'] == None: + if json_data['data'] is None: setter(resource, None) else: to_relate = self._fetch_resource( @@ -909,7 +920,9 @@ def patch_resource(self, session, json_data, api_type, obj_id): session, json_data['data']['relationships'][api_key], model.__jsonapi_type__, resource.id, api_key) - data_keys = set(map((lambda x: resource.__jsonapi_map_to_py__.get(x, None)), json_data['data']['attributes'].keys())) + data_keys = set(map(( + lambda x: resource.__jsonapi_map_to_py__.get(x, None)), + json_data['data']['attributes'].keys())) model_keys = set(orm_desc_keys) - attrs_to_ignore if not data_keys <= model_keys: @@ -920,7 +933,7 @@ def patch_resource(self, session, json_data, api_type, obj_id): for key in data_keys & model_keys: setter = get_attr_desc(resource, key, AttributeActions.SET) - setter(resource, json_data['data']['attributes'][resource.__jsonapi_map_to_api__[key]]) + setter(resource, json_data['data']['attributes'][resource.__jsonapi_map_to_api__[key]]) # NOQA session.commit() except IntegrityError as e: session.rollback() @@ -960,7 +973,9 @@ def post_collection(self, session, data, api_type): data['data'].setdefault('relationships', {}) data['data'].setdefault('attributes', {}) - data_keys = set(map((lambda x: resource.__jsonapi_map_to_py__.get(x, None)), data['data'].get('relationships', {}).keys())) + data_keys = set(map(( + lambda x: resource.__jsonapi_map_to_py__.get(x, None)), + data['data'].get('relationships', {}).keys())) model_keys = set(resource.__mapper__.relationships.keys()) if not data_keys <= model_keys: raise BadRequestError( @@ -1036,7 +1051,9 @@ def post_collection(self, session, data, api_type): Permissions.CREATE) setters.append([setter, to_relate]) - data_keys = set(map((lambda x: resource.__jsonapi_map_to_py__.get(x, None)), data['data'].get('attributes', {}).keys())) + data_keys = set(map(( + lambda x: resource.__jsonapi_map_to_py__.get(x, None)), + data['data'].get('attributes', {}).keys())) model_keys = set(orm_desc_keys) - attrs_to_ignore if not data_keys <= model_keys: diff --git a/sqlalchemy_jsonapi/tests/app.py b/sqlalchemy_jsonapi/tests/app.py index 386fe75..8dd0c17 100644 --- a/sqlalchemy_jsonapi/tests/app.py +++ b/sqlalchemy_jsonapi/tests/app.py @@ -12,7 +12,9 @@ from sqlalchemy import Boolean, Column, ForeignKey, Unicode, UnicodeText from sqlalchemy.ext.hybrid import hybrid_property from sqlalchemy.orm import backref, relationship, validates -from sqlalchemy_jsonapi import FlaskJSONAPI, Permissions, permission_test, Method, Endpoint, INTERACTIVE_PERMISSIONS +from sqlalchemy_jsonapi import ( + FlaskJSONAPI, Permissions, permission_test, Method, Endpoint, + INTERACTIVE_PERMISSIONS) from sqlalchemy_utils import EmailType, PasswordType, Timestamp, UUIDType app = Flask(__name__) diff --git a/sqlalchemy_jsonapi/tests/conftest.py b/sqlalchemy_jsonapi/tests/conftest.py index e028a30..7ab0b43 100644 --- a/sqlalchemy_jsonapi/tests/conftest.py +++ b/sqlalchemy_jsonapi/tests/conftest.py @@ -87,10 +87,9 @@ def user(session): @pytest.fixture def post(user, session): - new_post = BlogPost(author=user, - title=fake.sentence(), - content=fake.paragraph(), - is_published=True) + new_post = BlogPost( + author=user, title=fake.sentence(), content=fake.paragraph(), + is_published=True) session.add(new_post) session.commit() return new_post @@ -98,10 +97,9 @@ def post(user, session): @pytest.fixture def unpublished_post(user, session): - new_post = BlogPost(author=user, - title=fake.sentence(), - content=fake.paragraph(), - is_published=False) + new_post = BlogPost( + author=user, title=fake.sentence(), content=fake.paragraph(), + is_published=False) session.add(new_post) session.commit() return new_post @@ -110,13 +108,12 @@ def unpublished_post(user, session): @pytest.fixture def bunch_of_posts(user, session): for x in range(30): - new_post = BlogPost(author=user, - title=fake.sentence(), - content=fake.paragraph(), - is_published=fake.boolean()) + new_post = BlogPost( + author=user, title=fake.sentence(), content=fake.paragraph(), + is_published=fake.boolean()) session.add(new_post) - new_post.comments.append(BlogComment(author=user, - content=fake.paragraph())) + new_post.comments.append( + BlogComment(author=user, content=fake.paragraph())) session.commit() diff --git a/sqlalchemy_jsonapi/tests/test_collection_get.py b/sqlalchemy_jsonapi/tests/test_collection_get.py index 8442eb8..90ad978 100644 --- a/sqlalchemy_jsonapi/tests/test_collection_get.py +++ b/sqlalchemy_jsonapi/tests/test_collection_get.py @@ -1,5 +1,5 @@ from sqlalchemy_jsonapi.errors import ( - BadRequestError, NotAnAttributeError, NotSortableError) + BadRequestError, NotSortableError) def test_200_with_no_querystring(bunch_of_posts, client): @@ -14,39 +14,44 @@ def test_200_with_single_included_model(bunch_of_posts, client): assert response.json_data['included'][0]['type'] == 'users' -def test_200_with_including_model_and_including_inbetween(bunch_of_posts, - client): - response = client.get('/api/blog-comments/?include=post.author').validate(200) +def test_200_with_including_model_and_including_inbetween( + bunch_of_posts, client): + response = client.get( + '/api/blog-comments/?include=post.author').validate(200) assert response.json_data['data'][0]['type'] == 'blog-comments' for data in response.json_data['included']: assert data['type'] in ['blog-posts', 'users'] def test_200_with_multiple_includes(bunch_of_posts, client): - response = client.get('/api/blog-posts/?include=comments,author').validate(200) + response = client.get( + '/api/blog-posts/?include=comments,author').validate(200) assert response.json_data['data'][0]['type'] == 'blog-posts' for data in response.json_data['included']: assert data['type'] in ['blog-comments', 'users'] def test_200_with_single_field(bunch_of_posts, client): - response = client.get('/api/blog-posts/?fields[blog-posts]=title').validate(200) + response = client.get( + '/api/blog-posts/?fields[blog-posts]=title').validate(200) for item in response.json_data['data']: assert {'title'} == set(item['attributes'].keys()) assert len(item['relationships']) == 0 def test_200_with_multiple_fields(bunch_of_posts, client): - response = client.get('/api/blog-posts/?fields[blog-posts]=title,content,is-published').validate( + response = client.get( + '/api/blog-posts/?fields[blog-posts]=title,content,is-published').validate( # NOQA 200) for item in response.json_data['data']: - assert {'title', 'content', 'is-published'} == set(item['attributes'].keys()) + assert {'title', 'content', 'is-published'} == set( + item['attributes'].keys()) assert len(item['relationships']) == 0 def test_200_with_single_field_across_a_relationship(bunch_of_posts, client): response = client.get( - '/api/blog-posts/?fields[blog-posts]=title,content&fields[blog-comments]=author&include=comments').validate( + '/api/blog-posts/?fields[blog-posts]=title,content&fields[blog-comments]=author&include=comments').validate( # NOQA 200) for item in response.json_data['data']: assert {'title', 'content'} == set(item['attributes'].keys()) @@ -85,19 +90,20 @@ def test_409_when_given_a_missing_field_for_sorting(bunch_of_posts, client): def test_200_paginated_response_by_page(bunch_of_posts, client): - response = client.get('/api/blog-posts/?page[number]=2&page[size]=5').validate( - 200) + response = client.get( + '/api/blog-posts/?page[number]=2&page[size]=5').validate(200) assert len(response.json_data['data']) == 5 def test_200_paginated_response_by_offset(bunch_of_posts, client): - response = client.get('/api/blog-posts/?page[offset]=5&page[limit]=5').validate( - 200) + response = client.get( + '/api/blog-posts/?page[offset]=5&page[limit]=5').validate(200) assert len(response.json_data['data']) == 5 def test_200_when_pagination_is_out_of_range(bunch_of_posts, client): - client.get('/api/blog-posts/?page[offset]=999999&page[limit]=5').validate(200) + client.get( + '/api/blog-posts/?page[offset]=999999&page[limit]=5').validate(200) def test_400_when_provided_crap_data_for_pagination(bunch_of_posts, client): diff --git a/sqlalchemy_jsonapi/tests/test_collection_post.py b/sqlalchemy_jsonapi/tests/test_collection_post.py index 8dba8e2..ebacbcb 100644 --- a/sqlalchemy_jsonapi/tests/test_collection_post.py +++ b/sqlalchemy_jsonapi/tests/test_collection_post.py @@ -2,8 +2,7 @@ from sqlalchemy_jsonapi.errors import ( InvalidTypeForEndpointError, MissingTypeError, PermissionDeniedError, - ValidationError, MissingContentTypeError, NotAnAttributeError, - BadRequestError) + ValidationError, MissingContentTypeError) from faker import Faker fake = Faker() @@ -20,10 +19,9 @@ def test_200_resource_creation(client): } } } - response = client.post('/api/users/', - data=json.dumps(payload), - content_type='application/vnd.api+json').validate( - 201) + response = client.post( + '/api/users/', data=json.dumps(payload), + content_type='application/vnd.api+json').validate(201) assert response.json_data['data']['type'] == 'users' user_id = response.json_data['data']['id'] response = client.get('/api/users/{}/'.format(user_id)).validate(200) @@ -48,13 +46,13 @@ def test_200_resource_creation_with_relationships(user, client): } } } - response = client.post('/api/blog-posts/', - data=json.dumps(payload), - content_type='application/vnd.api+json').validate( - 201) + response = client.post( + '/api/blog-posts/', data=json.dumps(payload), + content_type='application/vnd.api+json').validate(201) assert response.json_data['data']['type'] == 'blog-posts' post_id = response.json_data['data']['id'] - response = client.get('/api/blog-posts/{}/?include=author'.format(post_id)).validate(200) + response = client.get( + '/api/blog-posts/{}/?include=author'.format(post_id)).validate(200) assert response.json_data['data']['relationships']['author']['data'][ 'id' ] == str(user.id) @@ -62,10 +60,10 @@ def test_200_resource_creation_with_relationships(user, client): def test_403_when_access_is_denied(client): payload = {'data': {'type': 'logs'}} - client.post('/api/logs/', - data=json.dumps(payload), - content_type='application/vnd.api+json').validate( - 403, PermissionDeniedError) + client.post( + '/api/logs/', data=json.dumps(payload), + content_type='application/vnd.api+json').validate( + 403, PermissionDeniedError) def test_409_when_id_already_exists(user, client): @@ -80,18 +78,18 @@ def test_409_when_id_already_exists(user, client): } } } - client.post('/api/users/', - data=json.dumps(payload), - content_type='application/vnd.api+json').validate( - 409, ValidationError) + client.post( + '/api/users/', data=json.dumps(payload), + content_type='application/vnd.api+json').validate( + 409, ValidationError) def test_409_when_type_doesnt_match_endpoint(client): payload = {'data': {'type': 'blog-posts'}} - client.post('/api/users/', - data=json.dumps(payload), - content_type='application/vnd.api+json').validate( - 409, InvalidTypeForEndpointError) + client.post( + '/api/users/', data=json.dumps(payload), + content_type='application/vnd.api+json').validate( + 409, InvalidTypeForEndpointError) def test_409_when_missing_content_type(client): @@ -109,10 +107,10 @@ def test_409_when_missing_type(client): } } } - client.post('/api/users/', - data=json.dumps(payload), - content_type='application/vnd.api+json').validate( - 409, MissingTypeError) + client.post( + '/api/users/', data=json.dumps(payload), + content_type='application/vnd.api+json').validate( + 409, MissingTypeError) def test_409_for_invalid_value(client): @@ -126,10 +124,10 @@ def test_409_for_invalid_value(client): } } } - client.post('/api/users/', - data=json.dumps(payload), - content_type='application/vnd.api+json').validate( - 409, ValidationError) + client.post( + '/api/users/', data=json.dumps(payload), + content_type='application/vnd.api+json').validate( + 409, ValidationError) def test_409_for_wrong_field_name(client): @@ -144,7 +142,7 @@ def test_409_for_wrong_field_name(client): } } } - client.post('/api/users/', - data=json.dumps(payload), - content_type='application/vnd.api+json').validate( - 409, ValidationError) + client.post( + '/api/users/', data=json.dumps(payload), + content_type='application/vnd.api+json').validate( + 409, ValidationError) diff --git a/sqlalchemy_jsonapi/tests/test_related_get.py b/sqlalchemy_jsonapi/tests/test_related_get.py index 225d028..f7e2bd9 100644 --- a/sqlalchemy_jsonapi/tests/test_related_get.py +++ b/sqlalchemy_jsonapi/tests/test_related_get.py @@ -5,7 +5,8 @@ def test_200_result_of_to_one(post, client): - response = client.get('/api/blog-posts/{}/author/'.format(post.id)).validate( + response = client.get( + '/api/blog-posts/{}/author/'.format(post.id)).validate( 200) assert response.json_data['data']['type'] == 'users' diff --git a/sqlalchemy_jsonapi/tests/test_relationship_delete.py b/sqlalchemy_jsonapi/tests/test_relationship_delete.py index c7ae5a8..bf84140 100644 --- a/sqlalchemy_jsonapi/tests/test_relationship_delete.py +++ b/sqlalchemy_jsonapi/tests/test_relationship_delete.py @@ -2,9 +2,8 @@ from uuid import uuid4 from sqlalchemy_jsonapi.errors import ( - BadRequestError, PermissionDeniedError, RelationshipNotFoundError, - ResourceNotFoundError, ToManyExpectedError, MissingContentTypeError, - ValidationError) + PermissionDeniedError, RelationshipNotFoundError, ResourceNotFoundError, + MissingContentTypeError, ValidationError) def test_200_on_deletion_from_to_many(comment, client): @@ -22,37 +21,36 @@ def test_200_on_deletion_from_to_many(comment, client): def test_404_on_resource_not_found(client): - client.delete('/api/blog-posts/{}/relationships/comments/'.format(uuid4()), - data='{}', - content_type='application/vnd.api+json').validate( - 404, ResourceNotFoundError) + client.delete( + '/api/blog-posts/{}/relationships/comments/'.format(uuid4()), + data='{}', content_type='application/vnd.api+json').validate( + 404, ResourceNotFoundError) def test_404_on_relationship_not_found(post, client): - client.delete('/api/blog-posts/{}/relationships/comment/'.format( - post.id), - data='{}', - content_type='application/vnd.api+json').validate( - 404, RelationshipNotFoundError) + client.delete( + '/api/blog-posts/{}/relationships/comment/'.format(post.id), + data='{}', content_type='application/vnd.api+json').validate( + 404, RelationshipNotFoundError) def test_403_on_permission_denied(user, client): - client.delete('/api/users/{}/relationships/logs/'.format( - user.id), - data='{"data": []}', - content_type='application/vnd.api+json').validate( - 403, PermissionDeniedError) + client.delete( + '/api/users/{}/relationships/logs/'.format(user.id), + data='{"data": []}', + content_type='application/vnd.api+json').validate( + 403, PermissionDeniedError) def test_409_on_to_one_provided(post, client): - client.delete('/api/blog-posts/{}/relationships/author/'.format( - post.id), - data='{"data": {}}', - content_type='application/vnd.api+json').validate( - 409, ValidationError) + client.delete( + '/api/blog-posts/{}/relationships/author/'.format(post.id), + data='{"data": {}}', + content_type='application/vnd.api+json').validate( + 409, ValidationError) def test_409_missing_content_type_header(post, client): - client.delete('/api/blog-posts/{}/relationships/comment/'.format( - post.id), - data='{}').validate(409, MissingContentTypeError) + client.delete( + '/api/blog-posts/{}/relationships/comment/'.format(post.id), + data='{}').validate(409, MissingContentTypeError) diff --git a/sqlalchemy_jsonapi/tests/test_relationship_patch.py b/sqlalchemy_jsonapi/tests/test_relationship_patch.py index d1d8df5..1610d98 100644 --- a/sqlalchemy_jsonapi/tests/test_relationship_patch.py +++ b/sqlalchemy_jsonapi/tests/test_relationship_patch.py @@ -21,104 +21,102 @@ def test_200_on_to_one_set_to_null(post, client): '/api/blog-posts/{}/relationships/author/'.format(post.id), data=json.dumps(payload), content_type='application/vnd.api+json').validate(200) - assert response.json_data['data'] == None + assert response.json_data['data'] is None def test_200_on_to_many_set_to_resources(post, comment, client): payload = {'data': [{'type': 'blog-comments', 'id': str(comment.id)}]} - response = client.patch('/api/blog-posts/{}/relationships/comments/'.format( - post.id), - data=json.dumps(payload), - content_type='application/vnd.api+json').validate( - 200) + response = client.patch( + '/api/blog-posts/{}/relationships/comments/'.format(post.id), + data=json.dumps(payload), + content_type='application/vnd.api+json').validate(200) assert response.json_data['data'][0]['id'] == str(comment.id) assert len(response.json_data['data']) == 1 def test_200_on_to_many_set_to_empty(post, client): payload = {'data': []} - response = client.patch('/api/blog-posts/{}/relationships/comments/'.format( - post.id), - data=json.dumps(payload), - content_type='application/vnd.api+json').validate( - 200) + response = client.patch( + '/api/blog-posts/{}/relationships/comments/'.format(post.id), + data=json.dumps(payload), + content_type='application/vnd.api+json').validate(200) assert len(response.json_data['data']) == 0 def test_409_on_to_one_set_to_empty_list(post, client): payload = {'data': []} - client.patch('/api/blog-posts/{}/relationships/author/'.format( - post.id), - data=json.dumps(payload), - content_type='application/vnd.api+json').validate( - 409, ValidationError) + client.patch( + '/api/blog-posts/{}/relationships/author/'.format(post.id), + data=json.dumps(payload), + content_type='application/vnd.api+json').validate( + 409, ValidationError) def test_409_on_to_many_set_to_null(post, client): payload = {'data': None} - client.patch('/api/blog-posts/{}/relationships/comments/'.format( - post.id), - data=json.dumps(payload), - content_type='application/vnd.api+json').validate( - 409, ValidationError) + client.patch( + '/api/blog-posts/{}/relationships/comments/'.format(post.id), + data=json.dumps(payload), + content_type='application/vnd.api+json').validate( + 409, ValidationError) def test_404_on_resource_not_found(client): - client.patch('/api/blog-posts/{}/relationships/comments/'.format( - uuid4()), - data='{}', - content_type='application/vnd.api+json').validate( - 404, ResourceNotFoundError) + client.patch( + '/api/blog-posts/{}/relationships/comments/'.format(uuid4()), + data='{}', + content_type='application/vnd.api+json').validate( + 404, ResourceNotFoundError) def test_404_on_relationship_not_found(client, post): - client.patch('/api/blog-posts/{}/relationships/comment/'.format( - post.id), - data='{}', - content_type='application/vnd.api+json').validate( - 404, RelationshipNotFoundError) + client.patch( + '/api/blog-posts/{}/relationships/comment/'.format(post.id), + data='{}', + content_type='application/vnd.api+json').validate( + 404, RelationshipNotFoundError) def test_404_on_related_item_not_found(post, client): payload = {'data': [{'type': 'blog-comments', 'id': str(uuid4())}]} - client.patch('/api/blog-posts/{}/relationships/comments/'.format( - post.id), - data=json.dumps(payload), - content_type='application/vnd.api+json').validate( - 404, ResourceNotFoundError) + client.patch( + '/api/blog-posts/{}/relationships/comments/'.format(post.id), + data=json.dumps(payload), + content_type='application/vnd.api+json').validate( + 404, ResourceNotFoundError) def test_403_on_permission_denied(user, log, client): payload = {'data': {'type': 'users', 'id': str(user.id)}} - client.patch('/api/logs/{}/relationships/user/'.format( - log.id), - data=json.dumps(payload), - content_type='application/vnd.api+json').validate( - 403, PermissionDeniedError) + client.patch( + '/api/logs/{}/relationships/user/'.format(log.id), + data=json.dumps(payload), + content_type='application/vnd.api+json').validate( + 403, PermissionDeniedError) def test_403_on_permission_denied_on_related(log, user, client): payload = {'data': {'type': 'logs', 'id': str(log.id)}} - client.patch('/api/users/{}/relationships/logs/'.format( - user.id), - data=json.dumps(payload), - content_type='application/vnd.api+json').validate( - 403, PermissionDeniedError) + client.patch( + '/api/users/{}/relationships/logs/'.format(user.id), + data=json.dumps(payload), + content_type='application/vnd.api+json').validate( + 403, PermissionDeniedError) def test_409_on_to_one_with_incompatible_model(post, comment, client): payload = {'data': {'type': 'blog-comments', 'id': str(comment.id)}} - client.patch('/api/blog-posts/{}/relationships/author/'.format( - post.id), - data=json.dumps(payload), - content_type='application/vnd.api+json').validate( - 409, ValidationError) + client.patch( + '/api/blog-posts/{}/relationships/author/'.format(post.id), + data=json.dumps(payload), + content_type='application/vnd.api+json').validate( + 409, ValidationError) def test_409_on_to_many_with_incompatible_model(post, client): payload = {'data': [{'type': 'blog-posts', 'id': str(post.id)}]} - client.patch('/api/blog-posts/{}/relationships/author/'.format( - post.id), - data=json.dumps(payload), - content_type='application/vnd.api+json').validate( - 409, ValidationError) + client.patch( + '/api/blog-posts/{}/relationships/author/'.format(post.id), + data=json.dumps(payload), + content_type='application/vnd.api+json').validate( + 409, ValidationError) diff --git a/sqlalchemy_jsonapi/tests/test_relationship_post.py b/sqlalchemy_jsonapi/tests/test_relationship_post.py index 287fedf..457ab24 100644 --- a/sqlalchemy_jsonapi/tests/test_relationship_post.py +++ b/sqlalchemy_jsonapi/tests/test_relationship_post.py @@ -1,36 +1,36 @@ import json from uuid import uuid4 -from sqlalchemy_jsonapi.errors import ValidationError, ResourceNotFoundError, RelationshipNotFoundError +from sqlalchemy_jsonapi.errors import ( + ValidationError, ResourceNotFoundError, RelationshipNotFoundError) def test_200_on_to_many(comment, post, client): payload = {'data': [{'type': 'blog-comments', 'id': str(comment.id)}]} - response = client.post('/api/blog-posts/{}/relationships/comments/'.format( - post.id), - data=json.dumps(payload), - content_type='application/vnd.api+json').validate( - 200) + response = client.post( + '/api/blog-posts/{}/relationships/comments/'.format(post.id), + data=json.dumps(payload), + content_type='application/vnd.api+json').validate(200) assert str(comment.id) in [str(x['id']) for x in response.json_data['data']] def test_409_on_hash_instead_of_array_provided(comment, post, client): payload = {'data': {'type': 'blog-comments', 'id': str(comment.id)}} - client.post('/api/blog-posts/{}/relationships/comments/'.format( - post.id), - data=json.dumps(payload), - content_type='application/vnd.api+json').validate( - 409, ValidationError) + client.post( + '/api/blog-posts/{}/relationships/comments/'.format(post.id), + data=json.dumps(payload), + content_type='application/vnd.api+json').validate( + 409, ValidationError) def test_409_on_incompatible_model(user, post, client): payload = {'data': [{'type': 'users', 'id': str(user.id)}]} - client.post('/api/blog-posts/{}/relationships/comments/'.format( - post.id), - data=json.dumps(payload), - content_type='application/vnd.api+json').validate( - 409, ValidationError) + client.post( + '/api/blog-posts/{}/relationships/comments/'.format(post.id), + data=json.dumps(payload), + content_type='application/vnd.api+json').validate( + 409, ValidationError) def test_409_on_to_one_relationship(post, client): @@ -41,15 +41,16 @@ def test_409_on_to_one_relationship(post, client): def test_404_on_resource_not_found(client): - client.post('/api/blog-posts/{}/relationships/comments/'.format(uuid4()), - data='{}', - content_type='application/vnd.api+json').validate( - 404, ResourceNotFoundError) + client.post( + '/api/blog-posts/{}/relationships/comments/'.format(uuid4()), + data='{}', + content_type='application/vnd.api+json').validate( + 404, ResourceNotFoundError) def test_404_on_relationship_not_found(post, client): - client.post('/api/blog-posts/{}/relationships/comment/'.format( - post.id), - data='{}', - content_type='application/vnd.api+json').validate( - 404, RelationshipNotFoundError) + client.post( + '/api/blog-posts/{}/relationships/comment/'.format(post.id), + data='{}', + content_type='application/vnd.api+json').validate( + 404, RelationshipNotFoundError) diff --git a/sqlalchemy_jsonapi/tests/test_resource_get.py b/sqlalchemy_jsonapi/tests/test_resource_get.py index 4f81414..bbecf0d 100644 --- a/sqlalchemy_jsonapi/tests/test_resource_get.py +++ b/sqlalchemy_jsonapi/tests/test_resource_get.py @@ -1,4 +1,5 @@ -from sqlalchemy_jsonapi.errors import ResourceNotFoundError, PermissionDeniedError +from sqlalchemy_jsonapi.errors import ( + ResourceNotFoundError, PermissionDeniedError) from uuid import uuid4 @@ -42,16 +43,17 @@ def test_200_with_multiple_includes(post, client): def test_200_with_single_field(post, client): - response = client.get('/api/blog-posts/{}/?fields[blog-posts]=title'.format( - post.id)).validate(200) + response = client.get( + '/api/blog-posts/{}/?fields[blog-posts]=title'.format( + post.id)).validate(200) assert {'title'} == set(response.json_data['data']['attributes'].keys()) assert len(response.json_data['data']['relationships']) == 0 def test_200_with_multiple_fields(post, client): - response = client.get('/api/blog-posts/{}/?fields[blog-posts]=title,content'.format( - post.id)).validate( - 200) + response = client.get( + '/api/blog-posts/{}/?fields[blog-posts]=title,content'.format( + post.id)).validate(200) assert {'title', 'content' } == set(response.json_data['data']['attributes'].keys()) assert len(response.json_data['data']['relationships']) == 0 @@ -59,9 +61,8 @@ def test_200_with_multiple_fields(post, client): def test_200_with_single_field_across_a_relationship(post, client): response = client.get( - '/api/blog-posts/{}/?fields[blog-posts]=title,content&fields[blog-comments]=author&include=comments'.format( - post.id)).validate( - 200) + '/api/blog-posts/{}/?fields[blog-posts]=title,content&fields[blog-comments]=author&include=comments'.format( # NOQA + post.id)).validate(200) assert {'title', 'content' } == set(response.json_data['data']['attributes'].keys()) assert len(response.json_data['data']['relationships']) == 0 diff --git a/sqlalchemy_jsonapi/tests/test_resource_patch.py b/sqlalchemy_jsonapi/tests/test_resource_patch.py index e5cdac1..d905b6d 100644 --- a/sqlalchemy_jsonapi/tests/test_resource_patch.py +++ b/sqlalchemy_jsonapi/tests/test_resource_patch.py @@ -3,8 +3,7 @@ from sqlalchemy_jsonapi.errors import ( BadRequestError, PermissionDeniedError, ResourceNotFoundError, - RelatedResourceNotFoundError, RelationshipNotFoundError, ValidationError, - MissingTypeError) + ValidationError) def test_200(client, post, user): @@ -25,10 +24,10 @@ def test_200(client, post, user): } } } - response = client.patch('/api/blog-posts/{}/'.format(post.id), - data=json.dumps(payload), - content_type='application/vnd.api+json').validate( - 200) + response = client.patch( + '/api/blog-posts/{}/'.format(post.id), + data=json.dumps(payload), + content_type='application/vnd.api+json').validate(200) assert response.json_data['data']['id'] == str(post.id) assert response.json_data['data']['type'] == 'blog-posts' assert response.json_data['data']['attributes']['title' @@ -36,17 +35,18 @@ def test_200(client, post, user): def test_400_missing_type(post, client): - client.patch('/api/blog-posts/{}/'.format(post.id), - data=json.dumps({}), - content_type='application/vnd.api+json').validate( - 400, BadRequestError) + client.patch( + '/api/blog-posts/{}/'.format(post.id), + data=json.dumps({}), + content_type='application/vnd.api+json').validate( + 400, BadRequestError) def test_404_resource_not_found(client): - client.patch('/api/blog-posts/{}/'.format(uuid4()), - content_type='application/vnd.api+json', - data='{}').validate( - 404, ResourceNotFoundError) + client.patch( + '/api/blog-posts/{}/'.format(uuid4()), + content_type='application/vnd.api+json', + data='{}').validate(404, ResourceNotFoundError) def test_404_related_resource_not_found(client, post): @@ -64,10 +64,11 @@ def test_404_related_resource_not_found(client, post): } } } - client.patch('/api/blog-posts/{}/'.format(post.id), - data=json.dumps(payload), - content_type='application/vnd.api+json').validate( - 404, ResourceNotFoundError) + client.patch( + '/api/blog-posts/{}/'.format(post.id), + data=json.dumps(payload), + content_type='application/vnd.api+json').validate( + 404, ResourceNotFoundError) def test_400_field_not_found(client, post, user): @@ -85,10 +86,11 @@ def test_400_field_not_found(client, post, user): } } } - client.patch('/api/blog-posts/{}/'.format(post.id), - data=json.dumps(payload), - content_type='application/vnd.api+json').validate( - 400, BadRequestError) + client.patch( + '/api/blog-posts/{}/'.format(post.id), + data=json.dumps(payload), + content_type='application/vnd.api+json').validate( + 400, BadRequestError) def test_409_type_mismatch_to_one(client, post, user): @@ -106,10 +108,11 @@ def test_409_type_mismatch_to_one(client, post, user): } } } - client.patch('/api/blog-posts/{}/'.format(post.id), - data=json.dumps(payload), - content_type='application/vnd.api+json').validate( - 409, ValidationError) + client.patch( + '/api/blog-posts/{}/'.format(post.id), + data=json.dumps(payload), + content_type='application/vnd.api+json').validate( + 409, ValidationError) def test_400_type_mismatch_to_many(client, post, user): @@ -127,10 +130,11 @@ def test_400_type_mismatch_to_many(client, post, user): } } } - client.patch('/api/blog-posts/{}/'.format(post.id), - data=json.dumps(payload), - content_type='application/vnd.api+json').validate( - 400, BadRequestError) + client.patch( + '/api/blog-posts/{}/'.format(post.id), + data=json.dumps(payload), + content_type='application/vnd.api+json').validate( + 400, BadRequestError) def test_409_validation_failed(client, post, user): @@ -151,10 +155,11 @@ def test_409_validation_failed(client, post, user): } } } - client.patch('/api/blog-posts/{}/'.format(post.id), - data=json.dumps(payload), - content_type='application/vnd.api+json').validate( - 409, ValidationError) + client.patch( + '/api/blog-posts/{}/'.format(post.id), + data=json.dumps(payload), + content_type='application/vnd.api+json').validate( + 409, ValidationError) def test_400_type_does_not_match_endpoint(client, post, user): @@ -175,14 +180,16 @@ def test_400_type_does_not_match_endpoint(client, post, user): } } } - client.patch('/api/blog-posts/{}/'.format(post.id), - data=json.dumps(payload), - content_type='application/vnd.api+json').validate( - 400, BadRequestError) + client.patch( + '/api/blog-posts/{}/'.format(post.id), + data=json.dumps(payload), + content_type='application/vnd.api+json').validate( + 400, BadRequestError) def test_403_permission_denied(user, client): - client.patch('/api/users/{}/'.format(user.id), - data='{}', - content_type='application/vnd.api+json').validate( - 403, PermissionDeniedError) + client.patch( + '/api/users/{}/'.format(user.id), + data='{}', + content_type='application/vnd.api+json').validate( + 403, PermissionDeniedError) diff --git a/sqlalchemy_jsonapi/tests/test_serializer.py b/sqlalchemy_jsonapi/tests/test_serializer.py index 07060c9..668a3fc 100644 --- a/sqlalchemy_jsonapi/tests/test_serializer.py +++ b/sqlalchemy_jsonapi/tests/test_serializer.py @@ -4,8 +4,12 @@ def test_include_different_types_same_id(session, comment): new_id = uuid.uuid4() - comment.post.id = comment.author.id = comment.post_id = comment.author_id = new_id + comment.post.id = new_id + comment.author.id = new_id + comment.post_id = new_id + comment.author_id = new_id session.commit() - r = api.serializer.get_resource(session, {'include': 'post,author'}, 'blog-comments', comment.id) + r = api.serializer.get_resource( + session, {'include': 'post,author'}, 'blog-comments', comment.id) assert len(r.data['included']) == 2 diff --git a/tox.ini b/tox.ini index 9e801d2..2cfd3db 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py27,py3 +envlist = py27,py3,dandruff [testenv] use_develop=True