def test_unsuppored_parametrize_args(): """Tests parametrizing a function with unsuppored arguments""" with pytest.raises(AssertionError): @arg.parametrize(val=arg.val('vals'), val2=arg.val('vals')) def nothing(val): pass
class GrantStaffObjectView(djarg.views.SuccessMessageMixin, djarg.views.ObjectFormView): model = User func = arg.defaults(user=arg.val('object'), granter=arg.val('request').user)(grant_staff_access) template_name = 'tests/grant_staff_access.html' form_class = GrantAccessObjectForm success_url = '.'
def test_lazy_evaluation_chaining(): """Verifies that we can chain calls to lazy objects""" assert arg.load(arg.val('value').upper(), value='aa') == 'AA' assert arg.load(arg.val('value').upper().lower(), value='Aa') == 'aa' assert arg.load(arg.val('func_val')(), func_val=lambda: 'ret') == 'ret' class MyClass: def __init__(self, val): self.val = val # Instantiate a class with a dynamic attribute and return an attribute # of that class assert arg.load(arg.init(MyClass, val=arg.val('a')).val, a='hi') == 'hi'
def test_parametrize_call_context(): """Tests that the proper call context is set during parameterization""" arg_names = [] arg_vals = [] arg_indexes = [] @contextlib.contextmanager def gather_parametrized_context(): arg_names.append(arg.call().parametrize_arg) arg_vals.append(arg.call().parametrize_arg_val) arg_indexes.append(arg.call().parametrize_arg_index) yield @arg.parametrize(val=arg.val('vals')) @arg.contexts(gather_parametrized_context) def double(val): return val * 2 assert double(vals=[1, 2, 3]) == [2, 4, 6] # Verify that context was properly set during the run assert arg_names == ['val', 'val', 'val'] assert arg_vals == [1, 2, 3] assert arg_indexes == [0, 1, 2]
def test_s_arg_wrapper(): """Tests the arg.s wrapper utility Simulates the same test scenario as test_validators_with_defaults() """ def fails(arg1): """A validator that always passes""" if arg1 == 'UPPER': raise ValueError def my_func(arg1): return arg1 my_func_runner = arg.s( arg.defaults(arg1=arg.val('arg1').upper()), arg.validators(fails) ) with pytest.raises(ValueError): my_func_runner(my_func)(arg1='upper') assert my_func_runner(my_func)(arg1='lower') == 'LOWER' assert isinstance(arg.s()(my_func), arg.Args) assert arg.s()(my_func)('hello') == 'hello'
class GrantAccessUserGranterStaff(forms.Form): user = djarg.forms.Field( forms.ModelChoiceField, queryset=User.objects.all(), help_text=arg.val('extra', default='hi'), ) granter = djarg.forms.Field(forms.ModelChoiceField, queryset=User.objects.all()) is_staff = djarg.forms.Field(forms.BooleanField, required=False)
def __init__(self, objects, *, qset=None, model=None, pk='pk'): super().__init__() assert isinstance(objects, str) if model is None and qset is None: raise ValueError('Must provide model or qset to djarg.qset') self._qset = qset if qset is not None else model._default_manager.all() self._objects = arg.val(objects) self._pk = pk
class GrantAccessForm(forms.Form): user = djarg.forms.Field( forms.ModelChoiceField, queryset=User.objects.all(), help_text=arg.val('help_text', default=''), ) granter = forms.ModelChoiceField(queryset=User.objects.all()) is_staff = djarg.forms.Field(forms.BooleanField, required=False) source = djarg.forms.Field(forms.CharField)
def test_grant_staff_access_drf_action(api_client, mocker): """Run the GrantStaffAccess DRF action""" actor = ddf.G(auth_models.User, is_superuser=True) actor.set_password('password') actor.save() user = ddf.G(auth_models.User, is_staff=False) grant_staff_access = daf.registry.get('tests.grant_staff_access') detail_view_url_name = ( 'user-' + grant_staff_access.interfaces['rest_framework.detail_action'].url_name) url = urls.reverse(detail_view_url_name, kwargs={'pk': user.id}) api_client.force_login(actor) # Perform a run where form validation fails resp = api_client.post(url, data={'date_granted': 'invalid'}) assert resp.status_code == 400 assert resp.json() == {'date_granted': ['Enter a valid date/time.']} # Perform a successful run resp = api_client.post(url, data={'is_staff': True}) assert resp.status_code == 200 assert resp.json() == { 'email': user.email, 'id': user.id, 'username': user.username, 'is_staff': True, } # Make sure refetching for serialization works mocker.patch.object(GrantStaffAccessObjectDRFAction, 'refetch_for_serialization', False) resp = api_client.post(url, data={'is_staff': True}) assert resp.json() == { 'email': user.email, 'id': user.id, 'username': user.username, 'is_staff': True, } # Make sure refetching for serialization works even without using # a parametrized wrapper mocker.patch.object( daf.actions.ObjectAction, 'wrapper', arg.defaults(user=arg.val('object')), ) resp = api_client.post(url, data={'is_staff': True}) assert resp.json() == { 'email': user.email, 'id': user.id, 'username': user.username, 'is_staff': True, }
def wrapper(cls): return arg.s( arg.contexts(trapped_errors=daf.contrib.raise_trapped_errors), arg.defaults( objects=arg.first( 'objects', daf.contrib.single_list('object'), daf.contrib.single_list(cls.object_arg), ) ), arg.defaults(objects=djarg.qset('objects', qset=cls.queryset)), arg.parametrize(**{cls.object_arg: arg.val('objects')}), arg.contexts(daf.contrib.trap_errors), super().wrapper, )
class GrantStaffObjectsView(djarg.views.SuccessMessageMixin, djarg.views.ObjectsFormView): model = User func = arg.s( arg.contexts(error_collector=raise_trapped_errors), arg.parametrize(user=arg.val('objects')), arg.contexts(trap_errors), )(grant_staff_access) template_name = 'tests/grant_staff_access.html' form_class = GrantAccessObjectForm success_url = '.' success_message = '{granter} successfully granted staff access to users.' def get_default_args(self): return {**super().get_default_args(), **{'granter': self.request.user}}
def test_parametrize(): """Tests parametrizing a function""" @arg.parametrize(val=arg.val('vals')) def double(val): return val * 2 assert double(vals=[1, 2, 3]) == [2, 4, 6] # This should result in a lazy bind error with pytest.raises(arg.BindError): double(val=1) # Partial runs should be able to ignore parametrization assert double.partial(val=1) == 2
class GrantStaffObjectWizardView(djarg.views.SuccessMessageMixin, djarg.views.SessionObjectWizardView): model = User func = arg.defaults(user=arg.val('object'))(grant_staff_access) template_name = 'tests/grant_staff_access_wizard.html' form_list = [ # We no longer need the first step. The user is provided by the # object view GrantAccessStep2, GrantAccessStep3, GrantAccessStep4, ] success_url = '.' def get_success_message(self, args, results): return f'Successfully granted access to {args["object"]}.'
def test_first(): """Tests arg.first utility for lazily loading the first loadable value""" assert arg.load(arg.first(arg.val('a'), arg.val('b')), b=2) == 2 assert arg.load(arg.first(arg.val('a'), arg.val('b')), a=3) == 3 with pytest.raises(arg.BindError): arg.load(arg.first(arg.val('a'), arg.val('b')), c=3) with pytest.raises(TypeError): arg.first(1, 2, 3) assert arg.load(arg.first(lambda a: '1', lambda b: '2'), b='val') == '2' assert ( arg.load(arg.first(arg.val('a'), arg.val('b'), default='nothing'), c=3) == 'nothing' ) assert arg.load(arg.first('a', 'b', 'c', 'd'), c=2, d=3) == 2
def test_validators_with_defaults(): """ Tests processing defaults before validators """ def check_that_upper_is_invalid(arg1): if arg1 == 'UPPER': raise ValueError @arg.defaults(arg1=arg.val('arg1').upper()) @arg.validators(check_that_upper_is_invalid) def my_func(arg1): return arg1 with pytest.raises(ValueError): my_func(arg1='upper') assert my_func(arg1='lower') == 'LOWER'
def wrapper(cls): arg_decs = [] if cls.select_for_update is not None: # pragma: no branch arg_decs = [arg.contexts(transaction.atomic)] arg_decs += [ arg.contexts(trapped_errors=daf.contrib.raise_trapped_errors), arg.defaults(objects=arg.first( 'objects', daf.contrib.single_list('object'), daf.contrib.single_list(cls.object_arg), )), arg.defaults(objects=djarg.qset( 'objects', qset=cls.queryset, select_for_update=cls.select_for_update, )), arg.parametrize(**{cls.object_arg: arg.val('objects')}), arg.contexts(daf.contrib.trap_errors), super().wrapper, ] return arg.s(*arg_decs)
import arg from django import forms from django.core import exceptions import daf.actions import daf.rest_framework import daf.views def list_error(username): """Helps test strange error messages that are raised in the test suite""" if username == 'list_error': raise exceptions.ValidationError(['list', 'error']) @arg.defaults(user=arg.first('user', arg.val('request').user)) @arg.validators(list_error) def basic(user, username): """ Update a username """ user.username = username user.save() return user class Basic(daf.actions.Action): """Basic action""" app_label = 'tests' callable = basic
def test_val(): """Tests the arg.val utility function for lazily obtaining values""" assert arg.load(arg.val('arg_name'), arg_name=1) == 1 with pytest.raises(arg.BindError): assert arg.load(arg.val('arg_name'), missing_arg=2) assert arg.load(arg.val('arg_name', 1), missing_arg=2) == 1
"""A basic action for granting staff access to a user. For integration tests""" import arg from django import forms import daf.actions import daf.admin import daf.rest_framework import daf.tests.models as test_models def cannot_have_aaa_as_my_field(my_model): if my_model.my_field == 'aaa': raise ValueError('"my_field" is "aaa". Cannot update') @arg.defaults(actor=arg.first('actor', arg.val('request').user)) @arg.validators(cannot_have_aaa_as_my_field) def update_my_field(actor, my_model, my_field): my_model.my_field = my_field my_model.save() return my_model class UpdateMyField(daf.actions.ObjectAction): """Updates my_field on MyModel""" callable = update_my_field object_arg = 'my_model' model = test_models.MyModel
"""A basic action for granting staff access to a user. For integration tests""" import arg from django import forms import django.contrib.auth.models as auth_models import djarg import djarg.views from daf import actions from daf import views @arg.defaults( users=djarg.qset('objects', model=auth_models.User), actor=arg.first('actor', arg.val('request').user), ) @arg.parametrize(user=arg.val('users')) def bulk_grant_staff_access(actor, user, is_staff): """ Grant staff access to a user via an actor. """ user.is_staff = is_staff user.save() return user class BulkGrantStaffAccess(actions.ModelAction): """Grants staff access to a user""" app_label = 'tests' name = 'bulk_grant_staff_access' callable = bulk_grant_staff_access
class GrantAccessStep1(forms.Form): user = djarg.forms.Field( forms.ModelChoiceField, queryset=User.objects.all(), help_text=arg.val('extra', default='hi'), )
def granter_must_be_superuser_and_staff(granter): if not granter.is_superuser or not granter.is_staff: raise ValueError(f'Granter must be superuser and staff.') def granter_cant_be_user(granter, user): if user == granter: raise ValueError('The granter cannot be the user being granted.') def validate_source(source): if source == 'BAD': raise exceptions.ValidationError('bad source name used') @arg.defaults(source=arg.val('source').upper()) @arg.validators( granter_must_be_superuser_and_staff, granter_cant_be_user, validate_source, check_username, ) def grant_staff_access(user, granter, is_staff, source): if user.username == 'run_error': raise RuntimeError('Test runtime error!') user.is_staff = is_staff user.save() class GrantAccessForm(forms.Form):