Skip to content
This repository has been archived by the owner on Jul 21, 2022. It is now read-only.

Commit

Permalink
Merge e94df79 into fbc04b6
Browse files Browse the repository at this point in the history
  • Loading branch information
justanr committed Apr 16, 2018
2 parents fbc04b6 + e94df79 commit 3c1a28e
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 2 deletions.
16 changes: 15 additions & 1 deletion src/flask_allows/allows.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from functools import wraps
import warnings

from flask import current_app, request
from werkzeug import LocalProxy
Expand Down Expand Up @@ -104,7 +105,7 @@ def fulfill(self, requirements, identity=None):
identity.
"""
identity = identity or self._identity_loader()
return all(r(identity, request) for r in requirements)
return all(_call_requirement(r, identity, request) for r in requirements)


def __get_allows():
Expand All @@ -119,5 +120,18 @@ def _make_callable(func_or_value):
return lambda *a, **k: func_or_value
return func_or_value

def _call_requirement(req, user, request):
try:
return req(user)
except TypeError:
warnings.warn(
"Passing request to requirements is now deprecated"
" and will be removed in 1.0",
DeprecationWarning,
stacklevel=2
)

return req(user, request)


_allows = LocalProxy(__get_allows, name="flask-allows")
4 changes: 3 additions & 1 deletion src/flask_allows/requirements.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import operator
from abc import ABCMeta, abstractmethod
from flask._compat import with_metaclass
from .allows import _call_requirement


class Requirement(with_metaclass(ABCMeta)):
Expand All @@ -9,12 +10,13 @@ class Requirement(with_metaclass(ABCMeta)):
useful for requirements that have complex logic that is too much to fit
inside of a single function.
"""

@abstractmethod
def fulfill(self, user, request):
return NotImplemented

def __call__(self, user, request):
return self.fulfill(user, request)
return _call_requirement(self.fulfill, user, request)

def __repr__(self):
return '<{}()>'.format(self.__class__.__name__)
Expand Down
26 changes: 26 additions & 0 deletions test/test_allows.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,20 @@
from werkzeug.exceptions import Forbidden


def test_warns_about_request_deprecation_with_old_style_requirement(member):
import warnings
allows = Allows(identity_loader=lambda: member)

with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always', DeprecationWarning)
allows.fulfill([lambda u, r: True])
warnings.simplefilter('default', DeprecationWarning)

assert len(w) == 1
assert issubclass(w[0].category, DeprecationWarning)
assert "Passing request to requirements is now deprecated" in str(w[0].message)


def test_Allows_defaults():
allows = Allows()
assert allows._identity_loader is None and allows.throws is Forbidden
Expand Down Expand Up @@ -139,3 +153,15 @@ def stub():

with pytest.raises(Forbidden):
stub()


def test_allows_can_call_requirements_with_old_and_new_style_arguments(member):
allows = Allows(identity_loader=lambda: member)

def new_style(user):
return True

def old_style(user, request):
return True

assert allows.fulfill([new_style, old_style])
8 changes: 8 additions & 0 deletions test/test_requirement.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,11 @@ def test_NotConditional_many_all_false(never, member, request):

def test_NotConditional_many_mixed(always, never, member, request):
assert Not(always, never)(member, request)


def test_supports_new_style_requirements(member, request):
class SomeRequirement(Requirement):
def fulfill(self, user):
return True

assert SomeRequirement()(member, request)

0 comments on commit 3c1a28e

Please sign in to comment.