Remove test dependency on django guardian

An ObjectPermissionBackend is added which is similar to the one
in guardian.backends.ObjectPermissionBackend for test support.
The differences are that:
  - Permissions can only be assigned to groups
  - The object permissions are stored in a defaultdict
  - Permissions can only be assigned using app_label.codename

This allows DRF to be released without waiting for django-guardian
to update.
This commit is contained in:
James Meakin 2021-05-16 17:22:21 +02:00
parent 3875d3284e
commit dc35f9e408
4 changed files with 44 additions and 26 deletions

View File

@ -2,7 +2,6 @@
coreapi==2.3.1
coreschema==0.0.4
django-filter>=2.4.0,<3.0
django-guardian>=2.3.0,<2.4
markdown==3.3;python_version>="3.6"
markdown==3.2.2;python_version=="3.5"
psycopg2-binary>=2.8.5,<2.9

View File

@ -0,0 +1,35 @@
from collections import defaultdict
from django.contrib.auth.models import Permission
def assign_perm(perm, group, obj=None):
if "." not in perm:
raise ValueError("perm must be in the format 'app_label.codename'")
if obj:
ObjectPermissionBackend.assign_perm(perm, group, obj)
else:
# Assign global permissions if there is no object
app_label, codename = perm.split(".", 1)
perm = Permission.objects.get(
content_type__app_label=app_label, codename=codename
)
group.permissions.add(perm)
class ObjectPermissionBackend:
# Stores the set of groups that have the given permission for the given object
object_perms = defaultdict(lambda: defaultdict(set))
def authenticate(self, *_, **__):
return None
@classmethod
def assign_perm(cls, perm, group, obj):
cls.object_perms[obj][perm].add(group)
def has_perm(self, user_obj, perm, obj=None):
groups_with_obj_perm = self.object_perms[obj][perm]
users_groups = {*user_obj.groups.all()}
return bool(groups_with_obj_perm.intersection(users_groups))

View File

@ -19,6 +19,10 @@ def pytest_configure(config):
from django.conf import settings
settings.configure(
AUTHENTICATION_BACKENDS=(
'django.contrib.auth.backends.ModelBackend',
'tests.authentication.backends.ObjectPermissionBackend',
),
DEBUG_PROPAGATE_EXCEPTIONS=True,
DATABASES={
'default': {
@ -70,21 +74,6 @@ def pytest_configure(config):
),
)
# guardian is optional
try:
import guardian # NOQA
except ImportError:
pass
else:
settings.ANONYMOUS_USER_ID = -1
settings.AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
'guardian.backends.ObjectPermissionBackend',
)
settings.INSTALLED_APPS += (
'guardian',
)
if config.getoption('--no-pkgroot'):
sys.path.pop(0)

View File

@ -1,8 +1,6 @@
import base64
import unittest
from unittest import mock
from django.conf import settings
from django.contrib.auth.models import AnonymousUser, Group, Permission, User
from django.db import models
from django.test import TestCase
@ -14,6 +12,7 @@ from rest_framework import (
)
from rest_framework.routers import DefaultRouter
from rest_framework.test import APIRequestFactory
from tests.authentication.backends import assign_perm
from tests.models import BasicModel
factory = APIRequestFactory()
@ -299,14 +298,11 @@ class GetQuerysetObjectPermissionInstanceView(generics.RetrieveUpdateDestroyAPIV
get_queryset_object_permissions_view = GetQuerysetObjectPermissionInstanceView.as_view()
@unittest.skipUnless('guardian' in settings.INSTALLED_APPS, 'django-guardian not installed')
class ObjectPermissionsIntegrationTests(TestCase):
"""
Integration tests for the object level permissions API.
"""
def setUp(self):
from guardian.shortcuts import assign_perm
# create users
create = User.objects.create_user
users = {
@ -320,14 +316,13 @@ class ObjectPermissionsIntegrationTests(TestCase):
everyone = Group.objects.create(name='everyone')
model_name = BasicPermModel._meta.model_name
app_label = BasicPermModel._meta.app_label
f = '{}_{}'.format
f = '{}.{}_{}'.format
perms = {
'view': f('view', model_name),
'change': f('change', model_name),
'delete': f('delete', model_name)
'view': f(app_label, 'view', model_name),
'change': f(app_label, 'change', model_name),
'delete': f(app_label, 'delete', model_name)
}
for perm in perms.values():
perm = '{}.{}'.format(app_label, perm)
assign_perm(perm, everyone)
everyone.user_set.add(*users.values())