From aeff878d58e3349f3dd3ee58f0b12b5a9d7fd467 Mon Sep 17 00:00:00 2001 From: Pierre CHAISY Date: Mon, 20 Mar 2017 22:38:52 +0100 Subject: [PATCH 01/26] Update resource_manager.rst --- docs/resource_manager.rst | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/resource_manager.rst b/docs/resource_manager.rst index 54e952d..6d334cc 100644 --- a/docs/resource_manager.rst +++ b/docs/resource_manager.rst @@ -9,11 +9,9 @@ Resource manager is the link between your logical data abstraction, your data la Flask-REST-JSONAPI provides 3 kinds of resource manager with default methods implementation according to JSONAPI 1.0 specification: -| * **ResourceList**: provides get and post methods to retrieve a collection of objects or create one. -| -| * **ResourceDetail**: provides get, patch and delete methods to retrieve details of an object, update an object and delete an object -| -| * **ResourceRelationship**: provides get, post, patch and delete methods to get relationships, create relationships, update relationships and delete relationships between objects. +* **ResourceList**: provides get and post methods to retrieve a collection of objects or create one. +* **ResourceDetail**: provides get, patch and delete methods to retrieve details of an object, update an object and delete an object +* **ResourceRelationship**: provides get, post, patch and delete methods to get relationships, create relationships, update relationships and delete relationships between objects. You can rewrite each default methods implementation to make custom work. If you rewrite all default methods implementation of a resource manager or if you rewrite a method and disable access to others, you don't have to set any attribute of your resource manager. From 640f99bbc70ff09b8a208bdaa5cbbbabb69e43dd Mon Sep 17 00:00:00 2001 From: Pierre CHAISY Date: Mon, 20 Mar 2017 23:02:39 +0100 Subject: [PATCH 02/26] Update conf.py --- docs/conf.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 5b42bcc..19eb54f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -128,7 +128,15 @@ # further. For a list of options available for each theme, see the # documentation. # -# html_theme_options = {} +html_theme_options = { + 'github_user': 'akira-dev', + 'github_repo': 'flask-rest-jsonapi', + 'github_banner': true, + 'travis_button': true, + 'show_related': true, + 'page_width': 1080px, + 'fixed_sidebar': true +} # Add any paths that contain custom themes here, relative to this directory. # html_theme_path = [] From a5b98d57e2eb39692135e065482b04e8a5cbe9af Mon Sep 17 00:00:00 2001 From: Pierre CHAISY Date: Mon, 20 Mar 2017 23:08:12 +0100 Subject: [PATCH 03/26] Update conf.py --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 19eb54f..9d19b6f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -134,7 +134,7 @@ 'github_banner': true, 'travis_button': true, 'show_related': true, - 'page_width': 1080px, + 'page_width': '1080px', 'fixed_sidebar': true } From dd85228eae0f3339636615a245e287dc658f8a65 Mon Sep 17 00:00:00 2001 From: Pierre CHAISY Date: Mon, 20 Mar 2017 23:12:21 +0100 Subject: [PATCH 04/26] Update conf.py --- docs/conf.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 9d19b6f..72a1273 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -135,7 +135,8 @@ 'travis_button': true, 'show_related': true, 'page_width': '1080px', - 'fixed_sidebar': true + 'fixed_sidebar': true, + 'code_font_size': '0.6em' } # Add any paths that contain custom themes here, relative to this directory. From 746cfc791c0369564f377364383510b070adadcc Mon Sep 17 00:00:00 2001 From: Pierre CHAISY Date: Mon, 20 Mar 2017 23:15:48 +0100 Subject: [PATCH 05/26] Update conf.py --- docs/conf.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 72a1273..bd88269 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -129,14 +129,14 @@ # documentation. # html_theme_options = { - 'github_user': 'akira-dev', - 'github_repo': 'flask-rest-jsonapi', - 'github_banner': true, - 'travis_button': true, - 'show_related': true, - 'page_width': '1080px', - 'fixed_sidebar': true, - 'code_font_size': '0.6em' + 'github_user': 'akira-dev' +# 'github_repo': 'flask-rest-jsonapi', +# 'github_banner': true, +# 'travis_button': true, +# 'show_related': true, +# 'page_width': '1080px', +# 'fixed_sidebar': true, +# 'code_font_size': '0.6em' } # Add any paths that contain custom themes here, relative to this directory. From 4b3c1c09c51f039702b7db978babaab642e937da Mon Sep 17 00:00:00 2001 From: Pierre CHAISY Date: Mon, 20 Mar 2017 23:18:05 +0100 Subject: [PATCH 06/26] Update conf.py --- docs/conf.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index bd88269..ad65227 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -129,11 +129,11 @@ # documentation. # html_theme_options = { - 'github_user': 'akira-dev' -# 'github_repo': 'flask-rest-jsonapi', -# 'github_banner': true, -# 'travis_button': true, -# 'show_related': true, + 'github_user': 'akira-dev', + 'github_repo': 'flask-rest-jsonapi', + 'github_banner': true, + 'travis_button': true, + 'show_related': true # 'page_width': '1080px', # 'fixed_sidebar': true, # 'code_font_size': '0.6em' From 6dd96228737251d54c56bec3c0e5c2674310e905 Mon Sep 17 00:00:00 2001 From: Pierre CHAISY Date: Mon, 20 Mar 2017 23:19:36 +0100 Subject: [PATCH 07/26] Update conf.py --- docs/conf.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index ad65227..1514940 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -130,10 +130,10 @@ # html_theme_options = { 'github_user': 'akira-dev', - 'github_repo': 'flask-rest-jsonapi', - 'github_banner': true, - 'travis_button': true, - 'show_related': true + 'github_repo': 'flask-rest-jsonapi' +# 'github_banner': true, +# 'travis_button': true, +# 'show_related': true # 'page_width': '1080px', # 'fixed_sidebar': true, # 'code_font_size': '0.6em' From de666588ed86cd64ae036f550b589d241b8a0184 Mon Sep 17 00:00:00 2001 From: Pierre CHAISY Date: Mon, 20 Mar 2017 23:23:36 +0100 Subject: [PATCH 08/26] Update conf.py --- docs/conf.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 1514940..a92e87d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -130,13 +130,13 @@ # html_theme_options = { 'github_user': 'akira-dev', - 'github_repo': 'flask-rest-jsonapi' -# 'github_banner': true, -# 'travis_button': true, -# 'show_related': true -# 'page_width': '1080px', -# 'fixed_sidebar': true, -# 'code_font_size': '0.6em' + 'github_repo': 'flask-rest-jsonapi', + 'github_banner': True, + 'travis_button': True, + 'show_related': True, + 'page_width': '1080px', + 'fixed_sidebar': True, + 'code_font_size': '0.6em' } # Add any paths that contain custom themes here, relative to this directory. From 466e67abccb63dfeaa93581d2e8277c6fcac4a68 Mon Sep 17 00:00:00 2001 From: Pierre CHAISY Date: Mon, 20 Mar 2017 23:28:02 +0100 Subject: [PATCH 09/26] Update conf.py --- docs/conf.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index a92e87d..b1c7ef8 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -129,14 +129,14 @@ # documentation. # html_theme_options = { - 'github_user': 'akira-dev', + 'github_user': 'miLibris', 'github_repo': 'flask-rest-jsonapi', 'github_banner': True, 'travis_button': True, 'show_related': True, 'page_width': '1080px', 'fixed_sidebar': True, - 'code_font_size': '0.6em' + 'code_font_size': '0.7em' } # Add any paths that contain custom themes here, relative to this directory. From b66ac757703550b0c1b2e1def18bae9404685f1e Mon Sep 17 00:00:00 2001 From: Pierre CHAISY Date: Mon, 20 Mar 2017 23:31:11 +0100 Subject: [PATCH 10/26] Update index.rst --- docs/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.rst b/docs/index.rst index 1060932..3bb2cc6 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -9,7 +9,7 @@ Main concepts ------------- .. image:: img/schema.png - :width: 600px + :width: 900px :alt: Architecture | * `JSON API 1.0 specification `_: it is a very popular specification about client server interactions for REST JSON API. It helps you to work in team because it is very precise and sharable. Thanks to this specification your api offers lot of features like a strong structure of request and response, filtering, pagination, sparse fieldsets, including related objects, great error formatting etc. From 0b4b513dd5b3d1b804342391f82297ec92b2e7dc Mon Sep 17 00:00:00 2001 From: Pierre CHAISY Date: Mon, 20 Mar 2017 23:35:39 +0100 Subject: [PATCH 11/26] Update resource_manager.rst --- docs/resource_manager.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/resource_manager.rst b/docs/resource_manager.rst index 6d334cc..daddb5b 100644 --- a/docs/resource_manager.rst +++ b/docs/resource_manager.rst @@ -52,7 +52,7 @@ You can plug additional decorators to each methods with this optional attributes :patch_decorators: a list a decorators plugged to the patch method :delete_decorators: a list a decorators plugged to the delete method -You can also provides default schema kwargs to each resource manager methods with this optional attributes: +You can also provide default schema kwargs to each resource manager methods with this optional attributes: :get_schema_kwargs: a dict of default schema kwargs in get method :post_schema_kwargs: a dict of default schema kwargs in post method From 0d293b3f3c5c09eb4ce442865aba5103fe8b485e Mon Sep 17 00:00:00 2001 From: Pierre CHAISY Date: Mon, 20 Mar 2017 23:37:49 +0100 Subject: [PATCH 12/26] Update conf.py --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index b1c7ef8..c563a24 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -136,7 +136,7 @@ 'show_related': True, 'page_width': '1080px', 'fixed_sidebar': True, - 'code_font_size': '0.7em' + 'code_font_size': '0.8em' } # Add any paths that contain custom themes here, relative to this directory. From 41448d752cb38a0616f72977738edc3030cc5d13 Mon Sep 17 00:00:00 2001 From: Pierre CHAISY Date: Mon, 20 Mar 2017 23:38:44 +0100 Subject: [PATCH 13/26] Update resource_manager.rst --- docs/resource_manager.rst | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/docs/resource_manager.rst b/docs/resource_manager.rst index daddb5b..49ccdb1 100644 --- a/docs/resource_manager.rst +++ b/docs/resource_manager.rst @@ -48,16 +48,6 @@ All resource mangers are inherited from flask.views.MethodView so you can provid You can plug additional decorators to each methods with this optional attributes: :get_decorators: a list a decorators plugged to the get method - :post_decorators: a list a decorators plugged to the post method - :patch_decorators: a list a decorators plugged to the patch method - :delete_decorators: a list a decorators plugged to the delete method - -You can also provide default schema kwargs to each resource manager methods with this optional attributes: - - :get_schema_kwargs: a dict of default schema kwargs in get method - :post_schema_kwargs: a dict of default schema kwargs in post method - :patch_schema_kwargs: a dict of default schema kwargs in patch method - :delete_schema_kwargs: a dict of default schema kwargs in delete method Each method of a resource manager got a pre and post process methods that take view args and kwargs as parameter for the pre process methods and the result of the method as parameter for the post process method. Thanks to this you can make custom work before and after the method process. Availables rewritable methods are: From a616ddc4843f0e8c6613a60fb2d6e0e3d7c224db Mon Sep 17 00:00:00 2001 From: Pierre CHAISY Date: Mon, 20 Mar 2017 23:41:06 +0100 Subject: [PATCH 14/26] Update resource_manager.rst --- docs/resource_manager.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/resource_manager.rst b/docs/resource_manager.rst index 49ccdb1..e23edc2 100644 --- a/docs/resource_manager.rst +++ b/docs/resource_manager.rst @@ -48,6 +48,7 @@ All resource mangers are inherited from flask.views.MethodView so you can provid You can plug additional decorators to each methods with this optional attributes: :get_decorators: a list a decorators plugged to the get method + :post_decorators: a list a decorators plugged to the post method Each method of a resource manager got a pre and post process methods that take view args and kwargs as parameter for the pre process methods and the result of the method as parameter for the post process method. Thanks to this you can make custom work before and after the method process. Availables rewritable methods are: From c49b879de9184d4295eb9ae79bf7c727a3ddc3f4 Mon Sep 17 00:00:00 2001 From: Pierre CHAISY Date: Mon, 20 Mar 2017 23:43:33 +0100 Subject: [PATCH 15/26] Update resource_manager.rst --- docs/resource_manager.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/resource_manager.rst b/docs/resource_manager.rst index e23edc2..298fa64 100644 --- a/docs/resource_manager.rst +++ b/docs/resource_manager.rst @@ -47,9 +47,6 @@ All resource mangers are inherited from flask.views.MethodView so you can provid You can plug additional decorators to each methods with this optional attributes: - :get_decorators: a list a decorators plugged to the get method - :post_decorators: a list a decorators plugged to the post method - Each method of a resource manager got a pre and post process methods that take view args and kwargs as parameter for the pre process methods and the result of the method as parameter for the post process method. Thanks to this you can make custom work before and after the method process. Availables rewritable methods are: :before_get: pre process method of the get method From 9068d001c120e8f746831ec522b5a87cc0ef7e36 Mon Sep 17 00:00:00 2001 From: Pierre CHAISY Date: Mon, 20 Mar 2017 23:44:51 +0100 Subject: [PATCH 16/26] Update resource_manager.rst --- docs/resource_manager.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/resource_manager.rst b/docs/resource_manager.rst index 298fa64..f55ecd2 100644 --- a/docs/resource_manager.rst +++ b/docs/resource_manager.rst @@ -47,6 +47,8 @@ All resource mangers are inherited from flask.views.MethodView so you can provid You can plug additional decorators to each methods with this optional attributes: + :get_decorators: a list of decorators to plug to the get method + Each method of a resource manager got a pre and post process methods that take view args and kwargs as parameter for the pre process methods and the result of the method as parameter for the post process method. Thanks to this you can make custom work before and after the method process. Availables rewritable methods are: :before_get: pre process method of the get method From 944b0cbbe29e41d3dc91bdd48df2791338a9c32a Mon Sep 17 00:00:00 2001 From: Pierre CHAISY Date: Mon, 20 Mar 2017 23:46:31 +0100 Subject: [PATCH 17/26] Update resource_manager.rst --- docs/resource_manager.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/resource_manager.rst b/docs/resource_manager.rst index f55ecd2..ca29cf9 100644 --- a/docs/resource_manager.rst +++ b/docs/resource_manager.rst @@ -48,6 +48,7 @@ All resource mangers are inherited from flask.views.MethodView so you can provid You can plug additional decorators to each methods with this optional attributes: :get_decorators: a list of decorators to plug to the get method + :post_decorators: a list of decorators to plug to the post method Each method of a resource manager got a pre and post process methods that take view args and kwargs as parameter for the pre process methods and the result of the method as parameter for the post process method. Thanks to this you can make custom work before and after the method process. Availables rewritable methods are: From 9489048073f4d37a5f81b00ad69c427d7e3aa266 Mon Sep 17 00:00:00 2001 From: Pierre CHAISY Date: Mon, 20 Mar 2017 23:49:04 +0100 Subject: [PATCH 18/26] Update resource_manager.rst --- docs/resource_manager.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/resource_manager.rst b/docs/resource_manager.rst index ca29cf9..b11693e 100644 --- a/docs/resource_manager.rst +++ b/docs/resource_manager.rst @@ -48,7 +48,7 @@ All resource mangers are inherited from flask.views.MethodView so you can provid You can plug additional decorators to each methods with this optional attributes: :get_decorators: a list of decorators to plug to the get method - :post_decorators: a list of decorators to plug to the post method + :post_decorators: idem for the post method Each method of a resource manager got a pre and post process methods that take view args and kwargs as parameter for the pre process methods and the result of the method as parameter for the post process method. Thanks to this you can make custom work before and after the method process. Availables rewritable methods are: From 82d61a4a41b5e2df3581ad8ba3edf02d65d89c41 Mon Sep 17 00:00:00 2001 From: Pierre CHAISY Date: Mon, 20 Mar 2017 23:50:45 +0100 Subject: [PATCH 19/26] Update resource_manager.rst --- docs/resource_manager.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/resource_manager.rst b/docs/resource_manager.rst index b11693e..19a326f 100644 --- a/docs/resource_manager.rst +++ b/docs/resource_manager.rst @@ -48,7 +48,7 @@ All resource mangers are inherited from flask.views.MethodView so you can provid You can plug additional decorators to each methods with this optional attributes: :get_decorators: a list of decorators to plug to the get method - :post_decorators: idem for the post method + :pos_decorators: idem for the post method Each method of a resource manager got a pre and post process methods that take view args and kwargs as parameter for the pre process methods and the result of the method as parameter for the post process method. Thanks to this you can make custom work before and after the method process. Availables rewritable methods are: From 28e2ccb02b0eec8fa1b5785e6a0dbe44bc1ccaad Mon Sep 17 00:00:00 2001 From: Pierre CHAISY Date: Mon, 20 Mar 2017 23:55:35 +0100 Subject: [PATCH 20/26] Update resource_manager.rst --- docs/resource_manager.rst | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/docs/resource_manager.rst b/docs/resource_manager.rst index 19a326f..e87a80f 100644 --- a/docs/resource_manager.rst +++ b/docs/resource_manager.rst @@ -47,8 +47,17 @@ All resource mangers are inherited from flask.views.MethodView so you can provid You can plug additional decorators to each methods with this optional attributes: - :get_decorators: a list of decorators to plug to the get method - :pos_decorators: idem for the post method +* **get_decorators**: a list of decorators to plug to the get method +* **post_decorators**: a list a decorators plugged to the post method +* **patch_decorators**: a list a decorators plugged to the patch method +* **delete_decorators**: a list a decorators plugged to the delete method + +You can also provide default schema kwargs to each resource manager methods with this optional attributes: + +* **get_schema_kwargs**: a dict of default schema kwargs in get method +* **post_schema_kwargs**: a dict of default schema kwargs in post method +* **patch_schema_kwargs**: a dict of default schema kwargs in patch method +* **delete_schema_kwargs**: a dict of default schema kwargs in delete method Each method of a resource manager got a pre and post process methods that take view args and kwargs as parameter for the pre process methods and the result of the method as parameter for the post process method. Thanks to this you can make custom work before and after the method process. Availables rewritable methods are: From 6bfb97ddc4dc2e855147c46565f7cce26ff76bfe Mon Sep 17 00:00:00 2001 From: jamesalbert Date: Tue, 21 Mar 2017 00:03:06 -0700 Subject: [PATCH 21/26] added some tests; fixed some errors --- tests/test_sqlalchemy_data_layer.py | 41 ++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/tests/test_sqlalchemy_data_layer.py b/tests/test_sqlalchemy_data_layer.py index 37ac73e..19866d0 100644 --- a/tests/test_sqlalchemy_data_layer.py +++ b/tests/test_sqlalchemy_data_layer.py @@ -760,41 +760,68 @@ def test_get_list_field_error(client, register_routes): def test_sqlalchemy_data_layer_without_session(person_model, person_list): with pytest.raises(Exception): - SqlalchemyDataLayer(model=person_model, resource=person_list) + SqlalchemyDataLayer(dict(model=person_model, resource=person_list)) def test_sqlalchemy_data_layer_without_model(session, person_list): with pytest.raises(Exception): - SqlalchemyDataLayer(session=session, resource=person_list) + SqlalchemyDataLayer(dict(session=session, resource=person_list)) + + +def test_sqlalchemy_data_layer_create_object_error(session, person_model, person_list): + with pytest.raises(JsonApiException): + dl = SqlalchemyDataLayer(dict(session=session, model=person_model, resource=person_list)) + dl.create_object(dict(), dict()) def test_sqlalchemy_data_layer_get_object_error(session, person_model): with pytest.raises(Exception): - dl = SqlalchemyDataLayer(session=session, model=person_model, id_field='error') + dl = SqlalchemyDataLayer(dict(session=session, model=person_model, id_field='error')) dl.get_object(**dict()) +def test_sqlalchemy_data_layer_update_object_error(session, person_model, person_list, monkeypatch): + def commit_mock(): + raise JsonApiException() + with pytest.raises(JsonApiException): + dl = SqlalchemyDataLayer(dict(session=session, model=person_model, resource=person_list)) + monkeypatch.setattr(dl.session, 'commit', commit_mock) + dl.update_object(dict(), dict(), dict()) + + +def test_sqlalchemy_data_layer_delete_object_error(session, person_model, person_list, monkeypatch): + def commit_mock(): + raise JsonApiException() + def delete_mock(obj): + pass + with pytest.raises(JsonApiException): + dl = SqlalchemyDataLayer(dict(session=session, model=person_model, resource=person_list)) + monkeypatch.setattr(dl.session, 'commit', commit_mock) + monkeypatch.setattr(dl.session, 'delete', delete_mock) + dl.delete_object(dict(), dict()) + + def test_sqlalchemy_data_layer_create_relationship_field_not_found(session, person_model): with pytest.raises(Exception): - dl = SqlalchemyDataLayer(session=session, model=person_model) + dl = SqlalchemyDataLayer(dict(session=session, model=person_model)) dl.create_relationship(dict(), 'error', '', **{'id': 1}) def test_sqlalchemy_data_layer_get_relationship_field_not_found(session, person_model): with pytest.raises(Exception): - dl = SqlalchemyDataLayer(session=session, model=person_model) + dl = SqlalchemyDataLayer(dict(session=session, model=person_model)) dl.get_relationship('error', '', '', **{'id': 1}) def test_sqlalchemy_data_layer_update_relationship_field_not_found(session, person_model): with pytest.raises(Exception): - dl = SqlalchemyDataLayer(session=session, model=person_model) + dl = SqlalchemyDataLayer(dict(session=session, model=person_model)) dl.update_relationship(dict(), 'error', '', **{'id': 1}) def test_sqlalchemy_data_layer_delete_relationship_field_not_found(session, person_model): with pytest.raises(Exception): - dl = SqlalchemyDataLayer(session=session, model=person_model) + dl = SqlalchemyDataLayer(dict(session=session, model=person_model)) dl.delete_relationship(dict(), 'error', '', **{'id': 1}) From 4379c5880b40e27f1e4dc26b0b79b04b1d1782fa Mon Sep 17 00:00:00 2001 From: jamesalbert Date: Tue, 21 Mar 2017 12:45:50 -0700 Subject: [PATCH 22/26] fixed syntax error --- flask_rest_jsonapi/data_layers/alchemy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flask_rest_jsonapi/data_layers/alchemy.py b/flask_rest_jsonapi/data_layers/alchemy.py index beaa45e..897e700 100644 --- a/flask_rest_jsonapi/data_layers/alchemy.py +++ b/flask_rest_jsonapi/data_layers/alchemy.py @@ -61,7 +61,7 @@ def get_object(self, view_kwargs): try: filter_field = getattr(self.model, id_field) except Exception: - raise Exception("{} has no attribute {}".format(self.model.__name__), id_field) + raise Exception("{} has no attribute {}".format(self.model.__name__, id_field)) url_field = getattr(self, 'url_field', 'id') filter_value = view_kwargs[url_field] From b077a84a9d49047735228cd0ad9e598d0ece1228 Mon Sep 17 00:00:00 2001 From: jamesalbert Date: Tue, 21 Mar 2017 12:46:27 -0700 Subject: [PATCH 23/26] added more tests; 95% coverage --- tests/test_sqlalchemy_data_layer.py | 102 ++++++++++++++++++++++++++-- 1 file changed, 96 insertions(+), 6 deletions(-) diff --git a/tests/test_sqlalchemy_data_layer.py b/tests/test_sqlalchemy_data_layer.py index 19866d0..712c363 100644 --- a/tests/test_sqlalchemy_data_layer.py +++ b/tests/test_sqlalchemy_data_layer.py @@ -12,6 +12,7 @@ from marshmallow_jsonapi import fields from flask_rest_jsonapi import Api, ResourceList, ResourceDetail, ResourceRelationship, JsonApiException +from flask_rest_jsonapi.exceptions import RelationNotFound, InvalidSort from flask_rest_jsonapi.querystring import QueryStringManager as QSManager from flask_rest_jsonapi.data_layers.alchemy import SqlalchemyDataLayer from flask_rest_jsonapi.data_layers.base import BaseDataLayer @@ -304,6 +305,21 @@ def register_routes(client, app, api_blueprint, person_list, person_detail, pers api.init_app(app) +@pytest.fixture(scope="module") +def get_object_mock(): + class get_object(object): + foo = type('foo', (object,), { + 'property': type('prop', (object,), { + 'mapper': type('map', (object,), { + 'class_': 'test' + })() + })() + })() + def __init__(self, kwargs): + pass + return get_object + + # test good cases def test_get_list(client, register_routes, person, person_2): with client: @@ -777,7 +793,7 @@ def test_sqlalchemy_data_layer_create_object_error(session, person_model, person def test_sqlalchemy_data_layer_get_object_error(session, person_model): with pytest.raises(Exception): dl = SqlalchemyDataLayer(dict(session=session, model=person_model, id_field='error')) - dl.get_object(**dict()) + dl.get_object(dict()) def test_sqlalchemy_data_layer_update_object_error(session, person_model, person_list, monkeypatch): @@ -804,25 +820,61 @@ def delete_mock(obj): def test_sqlalchemy_data_layer_create_relationship_field_not_found(session, person_model): with pytest.raises(Exception): dl = SqlalchemyDataLayer(dict(session=session, model=person_model)) - dl.create_relationship(dict(), 'error', '', **{'id': 1}) + dl.create_relationship(dict(), 'error', '', dict(id=1)) + + +def test_sqlalchemy_data_layer_create_relationship_error(session, person_model, get_object_mock, monkeypatch): + def commit_mock(): + raise JsonApiException() + with pytest.raises(JsonApiException): + dl = SqlalchemyDataLayer(dict(session=session, model=person_model)) + monkeypatch.setattr(dl.session, 'commit', commit_mock) + monkeypatch.setattr(dl, 'get_object', get_object_mock) + dl.create_relationship(dict(data=None), 'foo', '', dict(id=1)) def test_sqlalchemy_data_layer_get_relationship_field_not_found(session, person_model): - with pytest.raises(Exception): + with pytest.raises(RelationNotFound): dl = SqlalchemyDataLayer(dict(session=session, model=person_model)) - dl.get_relationship('error', '', '', **{'id': 1}) + dl.get_relationship('error', '', '', dict(id=1)) def test_sqlalchemy_data_layer_update_relationship_field_not_found(session, person_model): with pytest.raises(Exception): dl = SqlalchemyDataLayer(dict(session=session, model=person_model)) - dl.update_relationship(dict(), 'error', '', **{'id': 1}) + dl.update_relationship(dict(), 'error', '', dict(id=1)) + + +def test_sqlalchemy_data_layer_update_relationship_error(session, person_model, get_object_mock, monkeypatch): + def commit_mock(): + raise JsonApiException() + with pytest.raises(JsonApiException): + dl = SqlalchemyDataLayer(dict(session=session, model=person_model)) + monkeypatch.setattr(dl.session, 'commit', commit_mock) + monkeypatch.setattr(dl, 'get_object', get_object_mock) + dl.update_relationship(dict(data=None), 'foo', '', dict(id=1)) def test_sqlalchemy_data_layer_delete_relationship_field_not_found(session, person_model): with pytest.raises(Exception): dl = SqlalchemyDataLayer(dict(session=session, model=person_model)) - dl.delete_relationship(dict(), 'error', '', **{'id': 1}) + dl.delete_relationship(dict(), 'error', '', dict(id=1)) + + +def test_sqlalchemy_data_layer_delete_relationship_error(session, person_model, get_object_mock, monkeypatch): + def commit_mock(): + raise JsonApiException() + with pytest.raises(JsonApiException): + dl = SqlalchemyDataLayer(dict(session=session, model=person_model)) + monkeypatch.setattr(dl.session, 'commit', commit_mock) + monkeypatch.setattr(dl, 'get_object', get_object_mock) + dl.delete_relationship(dict(data=None), 'foo', '', dict(id=1)) + + +def test_sqlalchemy_data_layer_sort_query_error(session, person_model, monkeypatch): + with pytest.raises(InvalidSort): + dl = SqlalchemyDataLayer(dict(session=session, model=person_model)) + dl.sort_query(None, [dict(field='test')]) def test_post_list_incorrect_type(client, register_routes, computer): @@ -1304,6 +1356,44 @@ def test_base_data_layer(): base_dl.update_relationship(None, None, None, dict()) with pytest.raises(NotImplementedError): base_dl.delete_relationship(None, None, None, dict()) + with pytest.raises(NotImplementedError): + base_dl.query(dict()) + with pytest.raises(NotImplementedError): + base_dl.before_create_object(None, dict()) + with pytest.raises(NotImplementedError): + base_dl.after_create_object(None, None, dict()) + with pytest.raises(NotImplementedError): + base_dl.before_get_object(dict()) + with pytest.raises(NotImplementedError): + base_dl.after_get_object(None, dict()) + with pytest.raises(NotImplementedError): + base_dl.before_get_collection(None, dict()) + with pytest.raises(NotImplementedError): + base_dl.after_get_collection(None, None, dict()) + with pytest.raises(NotImplementedError): + base_dl.before_update_object(None, None, dict()) + with pytest.raises(NotImplementedError): + base_dl.after_update_object(None, None, dict()) + with pytest.raises(NotImplementedError): + base_dl.before_delete_object(None, dict()) + with pytest.raises(NotImplementedError): + base_dl.after_delete_object(None, dict()) + with pytest.raises(NotImplementedError): + base_dl.before_create_relationship(None, None, None, dict()) + with pytest.raises(NotImplementedError): + base_dl.after_create_relationship(None, None, None, None, None, dict()) + with pytest.raises(NotImplementedError): + base_dl.before_get_relationship(None, None, None, dict()) + with pytest.raises(NotImplementedError): + base_dl.after_get_relationship(None, None, None, None, None, dict()) + with pytest.raises(NotImplementedError): + base_dl.before_update_relationship(None, None, None, dict()) + with pytest.raises(NotImplementedError): + base_dl.after_update_relationship(None, None, None, None, None, dict()) + with pytest.raises(NotImplementedError): + base_dl.before_delete_relationship(None, None, None, dict()) + with pytest.raises(NotImplementedError): + base_dl.after_delete_relationship(None, None, None, None, None, dict()) def test_qs_manager(): From 1d8ff20efc186ecb57821b1420a58eaa42c0f4dc Mon Sep 17 00:00:00 2001 From: Pierre CHAISY Date: Wed, 22 Mar 2017 09:38:57 +0100 Subject: [PATCH 24/26] Bug fix --- flask_rest_jsonapi/data_layers/filtering/alchemy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flask_rest_jsonapi/data_layers/filtering/alchemy.py b/flask_rest_jsonapi/data_layers/filtering/alchemy.py index d3c097e..3f33f40 100644 --- a/flask_rest_jsonapi/data_layers/filtering/alchemy.py +++ b/flask_rest_jsonapi/data_layers/filtering/alchemy.py @@ -29,7 +29,7 @@ def __init__(self, model, filter_, resource, schema): self.schema = schema def resolve(self): - if 'or' not in self.filter_ and 'and' not in self.filter_: + if 'or' not in self.filter_ and 'and' not in self.filter_ and 'not' not in self.filter_: if self.val is None and self.field is None: raise InvalidFilters("Can't find value or field in a filter") From 954bd1d5e7a2ca9031d5b5eb650982839dacf4de Mon Sep 17 00:00:00 2001 From: Pierre CHAISY Date: Wed, 22 Mar 2017 13:58:25 +0100 Subject: [PATCH 25/26] bug fix --- flask_rest_jsonapi/data_layers/base.py | 14 ++++++++------ flask_rest_jsonapi/resource.py | 3 ++- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/flask_rest_jsonapi/data_layers/base.py b/flask_rest_jsonapi/data_layers/base.py index ef38e7f..98e2a04 100644 --- a/flask_rest_jsonapi/data_layers/base.py +++ b/flask_rest_jsonapi/data_layers/base.py @@ -30,14 +30,15 @@ def __init__(self, kwargs): :param dict kwargs: information about data layer instance """ + if kwargs.get('methods') is not None: + self.bound_additional_methods(kwargs['methods']) + kwargs.pop('methods') + kwargs.pop('class', None) for key, value in kwargs.items(): setattr(self, key, value) - if kwargs.get('methods') is not None: - self.bound_additional_methods() - def create_object(self, data, view_kwargs): """Create an object @@ -310,10 +311,11 @@ def after_delete_relationship(self, obj, updated, json_data, relationship_field, """ raise NotImplementedError - def bound_additional_methods(self): + def bound_additional_methods(self, methods): """Bound additional methods to current instance :param class meta: information from Meta class used to configure the data layer instance """ - for key, value in self.methods.items(): - setattr(self, key, types.MethodType(value, self)) + for key, value in methods.items(): + if key in self.ADDITIONAL_METHODS: + setattr(self, key, types.MethodType(value, self)) diff --git a/flask_rest_jsonapi/resource.py b/flask_rest_jsonapi/resource.py index 8dbf4df..a09e55d 100644 --- a/flask_rest_jsonapi/resource.py +++ b/flask_rest_jsonapi/resource.py @@ -32,7 +32,8 @@ def __new__(cls): .format(cls.__name__)) data_layer_cls = cls.data_layer.get('class', SqlalchemyDataLayer) - cls._data_layer = data_layer_cls(cls.data_layer) + data_layer_kwargs = copy(cls.data_layer) + cls._data_layer = data_layer_cls(data_layer_kwargs) cls._data_layer.resource = cls for method in getattr(cls, 'methods', ('GET', 'POST', 'PATCH', 'DELETE')): From 1a34946d6fe59be656d6074432254621f4289725 Mon Sep 17 00:00:00 2001 From: Pierre CHAISY Date: Wed, 22 Mar 2017 14:05:46 +0100 Subject: [PATCH 26/26] Bump version to 0.11.4 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 9cd4c1e..a983669 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ from setuptools import setup, find_packages -__version__ = '0.11.3' +__version__ = '0.11.4' setup(