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("/")
openSUSE Build Service is sponsored by