File modernize-braces.patch of Package failed_python-django-braces
From 0031b635b03a4d25c240a9619e4ba5e6433c2697 Mon Sep 17 00:00:00 2001
From: Kenneth Love <klove@oreilly.com>
Date: Mon, 8 Nov 2021 16:29:37 -0800
Subject: [PATCH 01/11] New description
---
braces/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Index: django-braces-1.15.0/braces/__init__.py
===================================================================
--- django-braces-1.15.0.orig/braces/__init__.py
+++ django-braces-1.15.0/braces/__init__.py
@@ -2,7 +2,7 @@
django-braces mixins library
----------------------------
-Several mixins for making Django's generic class-based views more useful.
+Mixins to make Django's generic class-based views simpler.
:copyright: (c) 2013 by Kenneth Love and Chris Jones
:license: BSD 3-clause. See LICENSE for more details
Index: django-braces-1.15.0/braces/forms.py
===================================================================
--- django-braces-1.15.0.orig/braces/forms.py
+++ django-braces-1.15.0/braces/forms.py
@@ -1,4 +1,4 @@
-class UserKwargModelFormMixin(object):
+class UserKwargModelFormMixin:
"""
Generic model form mixin for popping user out of the kwargs and
attaching it to the instance.
@@ -9,6 +9,6 @@ class UserKwargModelFormMixin(object):
"""
def __init__(self, *args, **kwargs):
- self.user = kwargs.pop("user", None) # Pop the user off the
- # passed in kwargs.
+ """Remove the user from **kwargs and assign it on the object"""
+ self.user = kwargs.pop("user", None)
super(UserKwargModelFormMixin, self).__init__(*args, **kwargs)
Index: django-braces-1.15.0/braces/views/_access.py
===================================================================
--- django-braces-1.15.0.orig/braces/views/_access.py
+++ django-braces-1.15.0/braces/views/_access.py
@@ -1,6 +1,6 @@
import inspect
import datetime
-import re
+import urllib.parse
from django.conf import settings
from django.contrib.auth import REDIRECT_FIELD_NAME
@@ -18,10 +18,9 @@ from django.utils.encoding import force_
from django.utils.timezone import now
-class AccessMixin(object):
+class AccessMixin:
"""
- 'Abstract' mixin that gives access mixins the same customizable
- functionality.
+ Base access mixin. All other access mixins should extend this one.
"""
login_url = None
@@ -29,6 +28,10 @@ class AccessMixin(object):
redirect_field_name = REDIRECT_FIELD_NAME # Set by django.contrib.auth
redirect_unauthenticated_users = False
+ def __init__(self, *args, **kwargs):
+ self._class_name = self.__class__.__name__
+ super().__init__(*args, **kwargs)
+
def get_login_url(self):
"""
Override this method to customize the login_url.
@@ -36,8 +39,8 @@ class AccessMixin(object):
login_url = self.login_url or settings.LOGIN_URL
if not login_url:
raise ImproperlyConfigured(
- "Define {0}.login_url or settings.LOGIN_URL or override "
- "{0}.get_login_url().".format(self.__class__.__name__)
+ f"Define {self._class_name}.login_url or settings.LOGIN_URL or "
+ f"override {self._class_name}.get_login_url()."
)
return force_str(login_url)
@@ -48,11 +51,9 @@ class AccessMixin(object):
"""
if self.redirect_field_name is None:
raise ImproperlyConfigured(
- "{0} is missing the "
- "redirect_field_name. Define {0}.redirect_field_name or "
- "override {0}.get_redirect_field_name().".format(
- self.__class__.__name__
- )
+ f"{self._class_name} is missing the redirect_field_name. "
+ f"Define {self._class_name}.redirect_field_name or "
+ f"override {self._class_name}.get_redirect_field_name()."
)
return self.redirect_field_name
@@ -92,7 +93,7 @@ class AccessMixin(object):
class LoginRequiredMixin(AccessMixin):
"""
- View mixin which verifies that the user is authenticated.
+ Requires the user to be authenticated.
NOTE:
This should be the left-most mixin of a view, except when
@@ -104,21 +105,17 @@ class LoginRequiredMixin(AccessMixin):
if not request.user.is_authenticated:
return self.handle_no_permission(request)
- return super(LoginRequiredMixin, self).dispatch(
- request, *args, **kwargs
- )
+ return super().dispatch(request, *args, **kwargs)
-class AnonymousRequiredMixin(object):
+class AnonymousRequiredMixin(AccessMixin):
"""
- View mixin which redirects to a specified URL if authenticated.
- Can be useful if you wanted to prevent authenticated users from
- accessing signup pages etc.
+ Requires the user to be unauthenticated.
NOTE:
This should be the left-most mixin of a view.
- Example Usage
+ ## Example Usage
class SomeView(AnonymousRequiredMixin, ListView):
...
@@ -132,36 +129,31 @@ class AnonymousRequiredMixin(object):
def dispatch(self, request, *args, **kwargs):
if request.user.is_authenticated:
return HttpResponseRedirect(self.get_authenticated_redirect_url())
- return super(AnonymousRequiredMixin, self).dispatch(
- request, *args, **kwargs
- )
+ return super().dispatch(request, *args, **kwargs)
def get_authenticated_redirect_url(self):
"""Return the reversed authenticated redirect url."""
if not self.authenticated_redirect_url:
raise ImproperlyConfigured(
- "{0} is missing an authenticated_redirect_url "
- "url to redirect to. Define "
- "{0}.authenticated_redirect_url or override "
- "{0}.get_authenticated_redirect_url().".format(
- self.__class__.__name__
- )
+ f"{self._class_name} is missing an authenticated_redirect_url "
+ f"url to redirect to. Define {self._class_name}.authenticated_redirect_url "
+ f"or override {self._class_name}.get_authenticated_redirect_url()."
)
return resolve_url(self.authenticated_redirect_url)
class PermissionRequiredMixin(AccessMixin):
"""
- View mixin which verifies that the logged in user has the specified
- permission.
+ The request users must have certain permission(s)
+
+ ## Attributes
- Class Settings
`permission_required` - the permission to check for.
`login_url` - the login url of site
`redirect_field_name` - defaults to "next"
`raise_exception` - defaults to False - raise 403 if set to True
- Example Usage
+ ## Example Usage
class SomeView(PermissionRequiredMixin, ListView):
...
@@ -175,7 +167,7 @@ class PermissionRequiredMixin(AccessMixi
...
"""
- permission_required = None # Default required perms to none
+ permission_required = None # No permissions are required by default
object_level_permissions = False
def get_permission_required(self, request=None):
@@ -188,8 +180,8 @@ class PermissionRequiredMixin(AccessMixi
# view, or raise a configuration error.
if self.permission_required is None:
raise ImproperlyConfigured(
- '{0} requires the "permission_required" attribute to be '
- "set.".format(self.__class__.__name__)
+ f'{self._class_name} requires the "permission_required" '
+ "attribute to be set."
)
return self.permission_required
@@ -226,9 +218,7 @@ class PermissionRequiredMixin(AccessMixi
if not has_permission:
return self.handle_no_permission(request)
- return super(PermissionRequiredMixin, self).dispatch(
- request, *args, **kwargs
- )
+ return super().dispatch(request, *args, **kwargs)
class MultiplePermissionsRequiredMixin(PermissionRequiredMixin):
@@ -242,14 +232,14 @@ class MultiplePermissionsRequiredMixin(P
permissions in a different format, they should still work.
By specifying the `all` key, the user must have all of
- the permissions in the passed in list.
+ the permissions in the list.
- By specifying The `any` key , the user must have ONE of the set
+ By specifying the `any` key , the user must have at least one of the
permissions in the list.
Class Settings
`permissions` - This is required to be a dict with one or both
- keys of `all` and/or `any` containing a list or tuple of
+ keys of `all` and `any` containing a list or tuple of
permissions.
`login_url` - the login url of site
`redirect_field_name` - defaults to "next"
@@ -278,29 +268,25 @@ class MultiplePermissionsRequiredMixin(P
def check_permissions(self, request):
permissions = self.get_permission_required(request)
- perms_all = permissions.get("all") or None
- perms_any = permissions.get("any") or None
+ perms_all = permissions.get("all")
+ perms_any = permissions.get("any")
self._check_permissions_keys_set(perms_all, perms_any)
self._check_perms_keys("all", perms_all)
self._check_perms_keys("any", perms_any)
- # If perms_all, check that user has all permissions in the list/tuple
+ # Check that user has all permissions in the list/tuple
if perms_all:
+ # Why not `return request.user.has_perms(perms_all)`?
+ # There may be optional permissions below.
if not request.user.has_perms(perms_all):
return False
# If perms_any, check that user has at least one in the list/tuple
if perms_any:
- has_one_perm = False
- for perm in perms_any:
- if request.user.has_perm(perm):
- has_one_perm = True
- break
-
- if not has_one_perm:
+ any_perms = [request.user.has_perm(perm) for perm in perms_any]
+ if not any_perms or not any(any_perms):
return False
-
return True
def _check_permissions_attr(self):
@@ -309,8 +295,8 @@ class MultiplePermissionsRequiredMixin(P
"""
if self.permissions is None or not isinstance(self.permissions, dict):
raise ImproperlyConfigured(
- '{0} requires the "permissions" attribute to be set as a '
- "dict.".format(self.__class__.__name__)
+ f'{self._class_name} requires the `permissions` attribute'
+ "to be set as a dict."
)
def _check_permissions_keys_set(self, perms_all=None, perms_any=None):
@@ -321,10 +307,8 @@ class MultiplePermissionsRequiredMixin(P
"""
if perms_all is None and perms_any is None:
raise ImproperlyConfigured(
- '{0} requires the "permissions" attribute to be set to a '
- 'dict and the "any" or "all" key to be set.'.format(
- self.__class__.__name__
- )
+ f'{self._class_name} requires the `permissions` attribute to '
+ f"be set to a dict and the `any` or `all` key to be set."
)
def _check_perms_keys(self, key=None, perms=None):
@@ -334,8 +318,8 @@ class MultiplePermissionsRequiredMixin(P
"""
if perms and not isinstance(perms, (list, tuple)):
raise ImproperlyConfigured(
- "{0} requires the permisions dict {1} value to be a "
- "list or tuple.".format(self.__class__.__name__, key)
+ f"{self._class_name} requires the permissions dict {key} value "
+ "to be a list or tuple."
)
@@ -343,23 +327,25 @@ class GroupRequiredMixin(AccessMixin):
group_required = None
def get_group_required(self):
- if self.group_required is None or (
+ if any([
+ self.group_required is None,
not isinstance(self.group_required, (list, tuple, str))
- ):
+ ]):
raise ImproperlyConfigured(
- '{0} requires the "group_required" attribute to be set and be '
- "one of the following types: string, unicode, list or "
- "tuple".format(self.__class__.__name__)
+ f'{self._class_name} requires the `group_required` attribute '
+ "to be set and be a string, list, or tuple."
)
if not isinstance(self.group_required, (list, tuple)):
self.group_required = (self.group_required,)
return self.group_required
def check_membership(self, groups):
- """Check required group(s)"""
+ """Check for user's membership in required groups. Superusers are
+ automatically members"""
if self.request.user.is_superuser:
return True
+
user_groups = self.request.user.groups.values_list("name", flat=True)
return set(groups).intersection(set(user_groups))
@@ -372,15 +358,12 @@ class GroupRequiredMixin(AccessMixin):
if not in_group:
return self.handle_no_permission(request)
- return super(GroupRequiredMixin, self).dispatch(
- request, *args, **kwargs
- )
+ return super().dispatch(request, *args, **kwargs)
class UserPassesTestMixin(AccessMixin):
"""
- CBV Mixin allows you to define test that every user should pass
- to get access into view.
+ User must pass a test before being allowed access to the view.
Class Settings
`test_func` - This is required to be a method that takes user
@@ -392,10 +375,8 @@ class UserPassesTestMixin(AccessMixin):
def test_func(self, user):
raise NotImplementedError(
- "{0} is missing implementation of the "
- "test_func method. You should write one.".format(
- self.__class__.__name__
- )
+ f"{self._class_name} is missing implementation of the "
+ "`test_func` method. A function to test the user is required."
)
def get_test_func(self):
@@ -407,52 +388,44 @@ class UserPassesTestMixin(AccessMixin):
if not user_test_result:
return self.handle_no_permission(request)
- return super(UserPassesTestMixin, self).dispatch(
- request, *args, **kwargs
- )
+ return super().dispatch(request, *args, **kwargs)
class SuperuserRequiredMixin(AccessMixin):
"""
- Mixin allows you to require a user with `is_superuser` set to True.
+ Require users to be superusers to access the view.
"""
def dispatch(self, request, *args, **kwargs):
if not request.user.is_superuser:
return self.handle_no_permission(request)
- return super(SuperuserRequiredMixin, self).dispatch(
- request, *args, **kwargs
- )
+ return super().dispatch(request, *args, **kwargs)
class StaffuserRequiredMixin(AccessMixin):
"""
- Mixin allows you to require a user with `is_staff` set to True.
+ Require users to be marked as staff to access the view.
"""
def dispatch(self, request, *args, **kwargs):
if not request.user.is_staff:
return self.handle_no_permission(request)
- return super(StaffuserRequiredMixin, self).dispatch(
- request, *args, **kwargs
- )
+ return super().dispatch(request, *args, **kwargs)
-class SSLRequiredMixin(object):
+class SSLRequiredMixin:
"""
- Simple mixin that allows you to force a view to be accessed
- via https.
+ Require requests to be made over a secure connection.
"""
- raise_exception = False # Default whether to raise an exception to none
+ raise_exception = False
def dispatch(self, request, *args, **kwargs):
if getattr(settings, "DEBUG", False):
- return super(SSLRequiredMixin, self).dispatch(
- request, *args, **kwargs
- )
+ # Don't enforce the check during development
+ return super().dispatch(request, *args, **kwargs)
if not request.is_secure():
if self.raise_exception:
@@ -467,25 +440,23 @@ class SSLRequiredMixin(object):
def _build_https_url(self, request):
"""Get the full url, replace http with https"""
url = request.build_absolute_uri(request.get_full_path())
- return re.sub(r"^http", "https", url)
+ return urllib.parse.urlunsplit(
+ ("https",)+urllib.parse.urlsplit(url)[1:]
+ )
class RecentLoginRequiredMixin(LoginRequiredMixin):
"""
- Mixin allows you to require a login to be within a number of seconds.
+ Require the user to have logged in within a number of seconds.
"""
max_last_login_delta = 1800 # Defaults to 30 minutes
def dispatch(self, request, *args, **kwargs):
- resp = super(RecentLoginRequiredMixin, self).dispatch(
- request, *args, **kwargs
- )
+ resp = super().dispatch(request, *args, **kwargs)
if resp.status_code == 200:
delta = datetime.timedelta(seconds=self.max_last_login_delta)
if now() > (request.user.last_login + delta):
return logout_then_login(request, self.get_login_url())
- else:
- return resp
return resp
Index: django-braces-1.15.0/braces/views/_ajax.py
===================================================================
--- django-braces-1.15.0.orig/braces/views/_ajax.py
+++ django-braces-1.15.0/braces/views/_ajax.py
@@ -5,10 +5,12 @@ from django.core.serializers.json import
from django.http import HttpResponse, HttpResponseBadRequest
-class JSONResponseMixin(object):
+class JSONResponseMixin:
"""
- A mixin that allows you to easily serialize simple data such as a dict or
- Django models.
+ Basic serialized responses.
+
+ For anything more complicated than basic Python types or Django
+ models, please use something like django-rest-framework.
"""
content_type = None
@@ -19,24 +21,22 @@ class JSONResponseMixin(object):
if self.content_type is not None and not isinstance(
self.content_type, str
):
+ class_name = self.__class__.__name__
raise ImproperlyConfigured(
- "{0} is missing a content type. Define {0}.content_type, "
- "or override {0}.get_content_type().".format(
- self.__class__.__name__
- )
+ f"{class_name} is missing a content type. Define {class_name}"
+ ".content_type or override {class_name}.get_content_type()."
)
return self.content_type or "application/json"
def get_json_dumps_kwargs(self):
- if self.json_dumps_kwargs is None:
- self.json_dumps_kwargs = {}
- self.json_dumps_kwargs.setdefault("ensure_ascii", False)
- return self.json_dumps_kwargs
+ dumps_kwargs = getattr(self, "json_dumps_kwargs", None) or {}
+ dumps_kwargs.setdefault("ensure_ascii", False)
+ return dumps_kwargs
def render_json_response(self, context_dict, status=200):
"""
- Limited serialization for shipping plain data. Do not use for models
- or other complex or custom objects.
+ Limited serialization for shipping plain data.
+ Do not use for models or other complex objects.
"""
json_context = json.dumps(
context_dict,
@@ -56,7 +56,7 @@ class JSONResponseMixin(object):
return HttpResponse(json_data, content_type=self.get_content_type())
-class AjaxResponseMixin(object):
+class AjaxResponseMixin:
"""
Mixin allows you to define alternative methods for ajax requests. Similar
to the normal get, post, and put methods, you can use get_ajax, post_ajax,
@@ -64,12 +64,13 @@ class AjaxResponseMixin(object):
"""
def dispatch(self, request, *args, **kwargs):
- request_method = request.method.lower()
-
- if request.is_ajax() and request_method in self.http_method_names:
+ if all([
+ request.headers.get("x-requested-with") == "XMLHttpRequest",
+ request.method.lower() in self.http_method_names
+ ]):
handler = getattr(
self,
- "{0}_ajax".format(request_method),
+ f"{request.method.lower()}_ajax",
self.http_method_not_allowed,
)
self.request = request
@@ -77,9 +78,7 @@ class AjaxResponseMixin(object):
self.kwargs = kwargs
return handler(request, *args, **kwargs)
- return super(AjaxResponseMixin, self).dispatch(
- request, *args, **kwargs
- )
+ return super().dispatch(request, *args, **kwargs)
def get_ajax(self, request, *args, **kwargs):
return self.get(request, *args, **kwargs)
@@ -96,9 +95,11 @@ class AjaxResponseMixin(object):
class JsonRequestResponseMixin(JSONResponseMixin):
"""
- Extends JSONResponseMixin. Attempts to parse request as JSON. If request
- is properly formatted, the json is saved to self.request_json as a Python
- object. request_json will be None for imparsible requests.
+ Attempt to parse the request body as JSON.
+
+ If successful, self.request_json will contain the deserialized object.
+ Otherwise, self.request_json will be None.
+
Set the attribute require_json to True to return a 400 "Bad Request" error
for requests that don't contain JSON.
@@ -132,7 +133,7 @@ class JsonRequestResponseMixin(JSONRespo
def get_request_json(self):
try:
return json.loads(self.request.body.decode("utf-8"))
- except ValueError:
+ except (json.JSONDecodeError, ValueError):
return None
def dispatch(self, request, *args, **kwargs):
@@ -149,9 +150,7 @@ class JsonRequestResponseMixin(JSONRespo
]
):
return self.render_bad_request_response()
- return super(JsonRequestResponseMixin, self).dispatch(
- request, *args, **kwargs
- )
+ return super().dispatch(request, *args, **kwargs)
class JSONRequestResponseMixin(JsonRequestResponseMixin):
Index: django-braces-1.15.0/braces/views/_forms.py
===================================================================
--- django-braces-1.15.0.orig/braces/views/_forms.py
+++ django-braces-1.15.0/braces/views/_forms.py
@@ -9,7 +9,7 @@ from django.views.decorators.csrf import
from django.urls import reverse
-class CsrfExemptMixin(object):
+class CsrfExemptMixin:
"""
Exempts the view from CSRF requirements.
@@ -19,31 +19,32 @@ class CsrfExemptMixin(object):
@method_decorator(csrf_exempt)
def dispatch(self, *args, **kwargs):
- return super(CsrfExemptMixin, self).dispatch(*args, **kwargs)
+ return super().dispatch(*args, **kwargs)
-class UserFormKwargsMixin(object):
+class UserFormKwargsMixin:
"""
- CBV mixin which puts the user from the request into the form kwargs.
- Note: Using this mixin requires you to pop the `user` kwarg
- out of the dict in the super of your form's `__init__`.
+ Automatically include `request.user` in form kwargs.
+
+ ## Note
+ You will need to handle the `user` kwarg in your form. Usually
+ this means `user = kwargs.pop("user")` in your form's `__init__`.
"""
def get_form_kwargs(self):
- kwargs = super(UserFormKwargsMixin, self).get_form_kwargs()
+ kwargs = super().get_form_kwargs()
# Update the existing form kwargs dict with the request's user.
kwargs.update({"user": self.request.user})
return kwargs
-class SuccessURLRedirectListMixin(object):
+class SuccessURLRedirectListMixin:
"""
- Simple CBV mixin which sets the success url to the list view of
- a given app. Set success_list_url as a class attribute of your
- CBV and don't worry about overloading the get_success_url.
+ Automatically reverses `success_list_url` and returns that as
+ the `success_url` for a form view.
- This is only to be used for redirecting to a list page. If you need
- to reverse the url with kwargs, this is not the mixin to use.
+ This is meant to redirect to a view without arguments. If you need
+ to include arguments to `reverse`, you can omit this mixin.
"""
success_list_url = None # Default the success url to none
@@ -51,19 +52,20 @@ class SuccessURLRedirectListMixin(object
def get_success_url(self):
# Return the reversed success url.
if self.success_list_url is None:
+ class_name = self.__class__.__name__
raise ImproperlyConfigured(
- "{0} is missing a success_list_url "
- "name to reverse and redirect to. Define "
- "{0}.success_list_url or override "
- "{0}.get_success_url().".format(self.__class__.__name__)
+ f"{class_name} is missing a success_list_url attribute. "
+ f"Define {class_name}.success_list_url or override "
+ f"{class_name}.get_success_url()."
)
return reverse(self.success_list_url)
-class _MessageAPIWrapper(object):
+class _MessageAPIWrapper:
"""
- Wrap the django.contrib.messages.api module to automatically pass a given
- request object as the first parameter of function calls.
+ Wrapper for the django.contrib.messages.api module.
+ Automatically pass a request object as the first parameter of
+ message function calls.
"""
API = set(
@@ -86,59 +88,59 @@ class _MessageAPIWrapper(object):
setattr(self, name, partial(api_fn, request))
-class _MessageDescriptor(object):
+class _MessageDescriptor:
"""
A descriptor that binds the _MessageAPIWrapper to the view's
request.
"""
- def __get__(self, instance, owner):
+ def __get__(self, instance, *args, **kwargs):
return _MessageAPIWrapper(instance.request)
-class MessageMixin(object):
+class MessageMixin:
"""
Add a `messages` attribute on the view instance that wraps
- `django.contrib .messages`, automatically passing the current
+ `django.contrib.messages`, automatically passing the current
request object.
"""
messages = _MessageDescriptor()
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self._class_name = self.__class__.__name__
+
class FormValidMessageMixin(MessageMixin):
"""
- Mixin allows you to set static message which is displayed by
- Django's messages framework through a static property on the class
- or programmatically by overloading the get_form_valid_message method.
+ Set a string to be sent via Django's messages framework when a form
+ passes validation.
"""
form_valid_message = None # Default to None
def get_form_valid_message(self):
"""
- Validate that form_valid_message is set and is either a
- unicode or str object.
+ Validate that form_valid_message is set correctly
"""
if self.form_valid_message is None:
raise ImproperlyConfigured(
- "{0}.form_valid_message is not set. Define "
- "{0}.form_valid_message, or override "
- "{0}.get_form_valid_message().".format(self.__class__.__name__)
+ f"{self._class_name}.form_valid_message is not set. Define "
+ f"{self._class_name}.form_valid_message, or override "
+ f"{self._class_name}.get_form_valid_message()."
)
if not isinstance(self.form_valid_message, (str, Promise)):
raise ImproperlyConfigured(
- "{0}.form_valid_message must be a str or unicode "
- "object.".format(self.__class__.__name__)
+ f"{self._class_name}.form_valid_message must be a str or Promise."
)
return force_str(self.form_valid_message)
def form_valid(self, form):
"""
- Call the super first, so that when overriding
- get_form_valid_message, we have access to the newly saved object.
+ Set the "form valid" message for standard form validation
"""
response = super(FormValidMessageMixin, self).form_valid(form)
self.messages.success(
@@ -147,6 +149,9 @@ class FormValidMessageMixin(MessageMixin
return response
def delete(self, *args, **kwargs):
+ """
+ Set the "form valid" message for delete form validation
+ """
response = super(FormValidMessageMixin, self).delete(*args, **kwargs)
self.messages.success(
self.get_form_valid_message(), fail_silently=True
@@ -156,36 +161,34 @@ class FormValidMessageMixin(MessageMixin
class FormInvalidMessageMixin(MessageMixin):
"""
- Mixin allows you to set static message which is displayed by
- Django's messages framework through a static property on the class
- or programmatically by overloading the get_form_invalid_message method.
+ Set a string to be sent via Django's messages framework when a form
+ fails validation.
"""
form_invalid_message = None
def get_form_invalid_message(self):
"""
- Validate that form_invalid_message is set and is either a
- unicode or str object.
+ Validate that form_invalid_message is set correctly.
"""
if self.form_invalid_message is None:
raise ImproperlyConfigured(
- "{0}.form_invalid_message is not set. Define "
- "{0}.form_invalid_message, or override "
- "{0}.get_form_invalid_message().".format(
- self.__class__.__name__
- )
+ f"{self._class_name}.form_invalid_message is not set. Define "
+ f"{self._class_name}.form_invalid_message, or override "
+ f"{self._class_name}.get_form_invalid_message()."
)
if not isinstance(self.form_invalid_message, (str, Promise)):
raise ImproperlyConfigured(
- "{0}.form_invalid_message must be a str or unicode "
- "object.".format(self.__class__.__name__)
+ f"{self._class_name}.form_invalid_message must be a str or Promise."
)
return force_str(self.form_invalid_message)
def form_invalid(self, form):
+ """
+ Set the "form invalid" message for standard form validation
+ """
response = super(FormInvalidMessageMixin, self).form_invalid(form)
self.messages.error(
self.get_form_invalid_message(), fail_silently=True
@@ -195,8 +198,5 @@ class FormInvalidMessageMixin(MessageMix
class FormMessagesMixin(FormValidMessageMixin, FormInvalidMessageMixin):
"""
- Mixin is a shortcut to use both FormValidMessageMixin and
- FormInvalidMessageMixin.
+ Set messages to be sent whether a form is valid or invalid.
"""
-
- pass
Index: django-braces-1.15.0/braces/views/_other.py
===================================================================
--- django-braces-1.15.0.orig/braces/views/_other.py
+++ django-braces-1.15.0/braces/views/_other.py
@@ -101,9 +101,7 @@ class CanonicalSlugDetailMixin(object):
}
return redirect(current_urlpattern, **params)
- return super(CanonicalSlugDetailMixin, self).dispatch(
- request, *args, **kwargs
- )
+ return super().dispatch(request, *args, **kwargs)
def get_canonical_slug(self):
"""
@@ -116,11 +114,11 @@ class CanonicalSlugDetailMixin(object):
return self.get_object().slug
-class AllVerbsMixin(object):
+class AllVerbsMixin:
"""Call a single method for all HTTP verbs.
The name of the method should be specified using the class attribute
- ``all_handler``. The default value of this attribute is 'all'.
+ `all_handler`. The default value of this attribute is 'all'.
"""
all_handler = "all"
@@ -128,18 +126,16 @@ class AllVerbsMixin(object):
def dispatch(self, request, *args, **kwargs):
if not self.all_handler:
raise ImproperlyConfigured(
- "{0} requires the all_handler attribute to be set.".format(
- self.__class__.__name__
- )
+ f"{self.__class__.__name__} requires the all_handler attribute to be set."
)
handler = getattr(self, self.all_handler, self.http_method_not_allowed)
return handler(request, *args, **kwargs)
-class HeaderMixin(object):
+class HeaderMixin:
"""
- Add arbitrary HTTP headers to a response by specifying them in the
+ Add extra HTTP headers to a response by specifying them in the
``headers`` attribute or by overriding the ``get_headers()`` method.
"""
Index: django-braces-1.15.0/braces/views/_queries.py
===================================================================
--- django-braces-1.15.0.orig/braces/views/_queries.py
+++ django-braces-1.15.0/braces/views/_queries.py
@@ -3,10 +3,9 @@ import warnings
from django.core.exceptions import ImproperlyConfigured
-class SelectRelatedMixin(object):
+class SelectRelatedMixin:
"""
- Mixin allows you to provide a tuple or list of related models to
- perform a select_related on.
+ Automatically apply `select_related` for a list of relations.
"""
select_related = None # Default related fields to none
@@ -15,20 +14,19 @@ class SelectRelatedMixin(object):
if self.select_related is None:
# If no fields were provided, raise a configuration error
raise ImproperlyConfigured(
- "{0} is missing the select_related property. This must be "
- "a tuple or list.".format(self.__class__.__name__)
+ f"{self.__class__.__name__} is missing the select_related attribute."
)
if not isinstance(self.select_related, (tuple, list)):
# If the select_related argument is *not* a tuple or list,
# raise a configuration error.
raise ImproperlyConfigured(
- "{0}'s select_related property must be a tuple or "
- "list.".format(self.__class__.__name__)
+ f"{self.__class__.__name__}'s select_related property must be "
+ "a tuple or list."
)
# Get the current queryset of the view
- queryset = super(SelectRelatedMixin, self).get_queryset()
+ queryset = super().get_queryset()
if not self.select_related:
warnings.warn("The select_related attribute is empty")
@@ -37,10 +35,9 @@ class SelectRelatedMixin(object):
return queryset.select_related(*self.select_related)
-class PrefetchRelatedMixin(object):
+class PrefetchRelatedMixin:
"""
- Mixin allows you to provide a tuple or list of related models to
- perform a prefetch_related on.
+ Automatically apply `prefetch_related` for a list of relations.
"""
prefetch_related = None # Default prefetch fields to none
@@ -49,20 +46,18 @@ class PrefetchRelatedMixin(object):
if self.prefetch_related is None:
# If no fields were provided, raise a configuration error
raise ImproperlyConfigured(
- "{0} is missing the prefetch_related property. This must be "
- "a tuple or list.".format(self.__class__.__name__)
+ f"{self.__class__.__name__} is missing the prefetch_related attribute."
)
if not isinstance(self.prefetch_related, (tuple, list)):
# If the prefetch_related argument is *not* a tuple or list,
# raise a configuration error.
raise ImproperlyConfigured(
- "{0}'s prefetch_related property must be a tuple or "
- "list.".format(self.__class__.__name__)
+ f"{self.__class__.__name__}'s prefetch_related property must be a tuple or list."
)
# Get the current queryset of the view
- queryset = super(PrefetchRelatedMixin, self).get_queryset()
+ queryset = super().get_queryset()
if not self.prefetch_related:
warnings.warn("The prefetch_related attribute is empty")
@@ -71,9 +66,9 @@ class PrefetchRelatedMixin(object):
return queryset.prefetch_related(*self.prefetch_related)
-class OrderableListMixin(object):
+class OrderableListMixin:
"""
- Mixin allows your users to order records using GET parameters
+ Order the queryset based on GET parameters.
"""
orderable_columns = None
@@ -89,7 +84,7 @@ class OrderableListMixin(object):
* ``order_by`` - name of the field
* ``ordering`` - order of ordering, either ``asc`` or ``desc``
"""
- context = super(OrderableListMixin, self).get_context_data(**kwargs)
+ context = super().get_context_data(**kwargs)
context["order_by"] = self.order_by
context["ordering"] = self.ordering
return context
@@ -97,18 +92,14 @@ class OrderableListMixin(object):
def get_orderable_columns(self):
if not self.orderable_columns:
raise ImproperlyConfigured(
- "{0} needs the ordering columns defined.".format(
- self.__class__.__name__
- )
+ f"{self.__class__.__name__} needs the ordering columns defined."
)
return self.orderable_columns
def get_orderable_columns_default(self):
if not self.orderable_columns_default:
raise ImproperlyConfigured(
- "{0} needs the default ordering column defined.".format(
- self.__class__.__name__
- )
+ f"{self.__class__.__name__} needs the default ordering column defined."
)
return self.orderable_columns_default
@@ -118,9 +109,7 @@ class OrderableListMixin(object):
else:
if self.ordering_default not in ["asc", "desc"]:
raise ImproperlyConfigured(
- "{0} only allows asc or desc as ordering option".format(
- self.__class__.__name__
- )
+ f"{self.__class__.__name__} only allows asc or desc as ordering option"
)
return self.ordering_default
@@ -141,11 +130,10 @@ class OrderableListMixin(object):
self.order_by = order_by
self.ordering = self.get_ordering_default()
- if (
- order_by
- and self.request.GET.get("ordering", self.ordering) == "desc"
- ):
- order_by = "-" + order_by
+ if all([order_by,
+ self.request.GET.get("ordering", self.ordering) == "desc"
+ ]):
+ order_by = f"-{order_by}"
self.ordering = self.request.GET.get("ordering", self.ordering)
return queryset.order_by(order_by)
@@ -154,5 +142,5 @@ class OrderableListMixin(object):
"""
Returns ordered ``QuerySet``
"""
- unordered_queryset = super(OrderableListMixin, self).get_queryset()
+ unordered_queryset = super().get_queryset()
return self.get_ordered_queryset(unordered_queryset)
Index: django-braces-1.15.0/tests/test_other_mixins.py
===================================================================
--- django-braces-1.15.0.orig/tests/test_other_mixins.py
+++ django-braces-1.15.0/tests/test_other_mixins.py
@@ -562,7 +562,7 @@ class TestModelCanonicalSlugDetailView(t
class MessageMixinTests(test.TestCase):
def setUp(self):
self.rf = test.RequestFactory()
- self.middleware = MessageMiddleware()
+ self.middleware = MessageMiddleware("")
def get_request(self, *args, **kwargs):
request = self.rf.get("/")