Skip to content

Commit

Permalink
Fix Namespace decorators
Browse files Browse the repository at this point in the history
  • Loading branch information
dmvass committed Jun 15, 2018
1 parent 9032694 commit 7873b9d
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 10 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Changelog
Current
-------

- Nothing yet
- Fix Namespace decorators (:issue:`475`)

0.11.0 (2018-05-16)
-------------------
Expand Down
23 changes: 14 additions & 9 deletions flask_restplus/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import difflib
import inspect
from itertools import chain
import logging
import operator
import re
Expand Down Expand Up @@ -200,8 +201,8 @@ def _init_app(self, app):
app.handle_user_exception = partial(self.error_router, app.handle_user_exception)

if len(self.resources) > 0:
for resource, urls, kwargs in self.resources:
self._register_view(app, resource, *urls, **kwargs)
for resource, namespace, urls, kwargs in self.resources:
self._register_view(app, resource, namespace, *urls, **kwargs)

self._register_apidoc(app)
self._validate = self._validate if self._validate is not None else app.config.get('RESTPLUS_VALIDATE', False)
Expand Down Expand Up @@ -238,6 +239,7 @@ def _register_specs(self, app_or_blueprint):
self._register_view(
app_or_blueprint,
SwaggerView,
self.default_namespace,
'/swagger.json',
endpoint=endpoint,
resource_class_args=(self, )
Expand All @@ -258,12 +260,12 @@ def register_resource(self, namespace, resource, *urls, **kwargs):
self.endpoints.add(endpoint)

if self.app is not None:
self._register_view(self.app, resource, *urls, **kwargs)
self._register_view(self.app, resource, namespace, *urls, **kwargs)
else:
self.resources.append((resource, urls, kwargs))
self.resources.append((resource, namespace, urls, kwargs))
return endpoint

def _register_view(self, app, resource, *urls, **kwargs):
def _register_view(self, app, resource, namespace, *urls, **kwargs):
endpoint = kwargs.pop('endpoint', None) or camel_to_dash(resource.__name__)
resource_class_args = kwargs.pop('resource_class_args', ())
resource_class_kwargs = kwargs.pop('resource_class_kwargs', {})
Expand All @@ -272,17 +274,20 @@ def _register_view(self, app, resource, *urls, **kwargs):
if endpoint in getattr(app, 'view_functions', {}):
previous_view_class = app.view_functions[endpoint].__dict__['view_class']

# if you override the endpoint with a different class, avoid the collision by raising an exception
# if you override the endpoint with a different class, avoid the
# collision by raising an exception
if previous_view_class != resource:
msg = 'This endpoint (%s) is already set to the class %s.' % (endpoint, previous_view_class.__name__)
raise ValueError(msg)
msg = 'This endpoint (%s) is already set to the class %s.'
raise ValueError(msg % (endpoint, previous_view_class.__name__))

resource.mediatypes = self.mediatypes_method() # Hacky
resource.endpoint = endpoint

resource_func = self.output(resource.as_view(endpoint, self, *resource_class_args,
**resource_class_kwargs))

for decorator in self.decorators:
# Apply Namespace and Api decorators to a resource
for decorator in chain(namespace.decorators, self.decorators):
resource_func = decorator(resource_func)

for url in urls:
Expand Down
18 changes: 18 additions & 0 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -319,3 +319,21 @@ def test_ordered_namespace(self, app):
ns = api.namespace('ns', 'Test namespace')

assert ns.ordered

def test_decorators(self, app, mocker):
decorator1 = mocker.Mock(return_value=lambda x: x)
decorator2 = mocker.Mock(return_value=lambda x: x)
decorator3 = mocker.Mock(return_value=lambda x: x)

class TestResource(restplus.Resource):
method_decorators = []

api = restplus.Api(decorators=[decorator1])
ns = api.namespace('test_ns', decorators=[decorator2, decorator3])

ns.add_resource(TestResource, '/test', endpoint='test')
api.init_app(app)

assert decorator1.called is True
assert decorator2.called is True
assert decorator3.called is True

0 comments on commit 7873b9d

Please sign in to comment.