Browse Source

Resolve all line-too-long errors raised by pylint

rafalp 6 years ago
parent
commit
3cf45e5908
57 changed files with 362 additions and 238 deletions
  1. 8 13
      misago/categories/forms.py
  2. 0 4
      misago/categories/views/permsadmin.py
  3. 4 4
      misago/legal/forms.py
  4. 3 1
      misago/markup/tests/test_api.py
  5. 8 6
      misago/markup/tests/test_mentions.py
  6. 4 1
      misago/search/tests/test_searchproviders.py
  7. 2 1
      misago/threads/api/attachments.py
  8. 4 2
      misago/threads/api/postingendpoint/__init__.py
  9. 3 1
      misago/threads/api/postingendpoint/attachments.py
  10. 5 2
      misago/threads/api/postingendpoint/category.py
  11. 3 1
      misago/threads/api/postingendpoint/participants.py
  12. 4 2
      misago/threads/api/threadendpoints/editor.py
  13. 2 1
      misago/threads/api/threadendpoints/patch.py
  14. 12 10
      misago/threads/forms.py
  15. 2 2
      misago/threads/mergeconflict.py
  16. 1 1
      misago/threads/paginator.py
  17. 46 53
      misago/threads/permissions/bestanswers.py
  18. 4 2
      misago/threads/serializers/moderation.py
  19. 3 1
      misago/threads/serializers/poll.py
  20. 6 8
      misago/threads/templatetags/misago_poststags.py
  21. 2 1
      misago/threads/tests/test_attachments_api.py
  22. 9 3
      misago/threads/tests/test_attachments_middleware.py
  23. 7 2
      misago/threads/tests/test_mergeconflict.py
  24. 4 1
      misago/threads/tests/test_privatethread_patch_api.py
  25. 4 2
      misago/threads/tests/test_privatethread_start_api.py
  26. 3 1
      misago/threads/tests/test_sync_unread_private_threads.py
  27. 61 40
      misago/threads/tests/test_thread_patch_api.py
  28. 6 2
      misago/threads/tests/test_thread_pollcreate_api.py
  29. 3 1
      misago/threads/tests/test_thread_pollvotes_api.py
  30. 4 1
      misago/threads/tests/test_thread_postmerge_api.py
  31. 6 2
      misago/threads/tests/test_thread_postpatch_api.py
  32. 2 1
      misago/threads/tests/test_thread_postsplit_api.py
  33. 18 5
      misago/threads/tests/test_threads_editor_api.py
  34. 2 1
      misago/threads/tests/test_threads_merge_api.py
  35. 3 1
      misago/threads/tests/test_threadview.py
  36. 4 0
      misago/threads/validators.py
  37. 2 1
      misago/threads/views/admin/attachmenttypes.py
  38. 13 13
      misago/users/forms/admin.py
  39. 2 2
      misago/users/forms/auth.py
  40. 2 1
      misago/users/management/commands/prepareuserdatadownloads.py
  41. 5 5
      misago/users/profilefields/default.py
  42. 5 7
      misago/users/serializers/moderation.py
  43. 2 2
      misago/users/serializers/options.py
  44. 2 1
      misago/users/social/backendsnames.py
  45. 8 4
      misago/users/social/pipeline.py
  46. 3 1
      misago/users/tests/test_auth_api.py
  47. 4 1
      misago/users/tests/test_bio_profilefield.py
  48. 13 4
      misago/users/tests/test_datadownloads.py
  49. 3 1
      misago/users/tests/test_forgottenpassword_views.py
  50. 1 0
      misago/users/tests/test_profilefields.py
  51. 4 4
      misago/users/tests/test_social_pipeline.py
  52. 3 2
      misago/users/tests/test_twitter_profilefield.py
  53. 4 1
      misago/users/tests/test_user_create_api.py
  54. 3 1
      misago/users/tests/test_user_requestdatadownload_api.py
  55. 3 1
      misago/users/tests/test_useradmin_views.py
  56. 16 5
      misago/users/tests/test_users_api.py
  57. 2 1
      misago/users/views/forgottenpassword.py

+ 8 - 13
misago/categories/forms.py

@@ -55,7 +55,8 @@ class CategoryFormBase(forms.ModelForm):
         label=_("CSS class"),
         label=_("CSS class"),
         required=False,
         required=False,
         help_text=_(
         help_text=_(
-            "Optional CSS class used to customize this category appearance from templates."
+            "Optional CSS class used to customize this "
+            "category's appearance from templates."
         ),
         ),
     )
     )
     is_closed = YesNoSwitch(
     is_closed = YesNoSwitch(
@@ -65,13 +66,6 @@ class CategoryFormBase(forms.ModelForm):
             "Only members with valid permissions can post in closed categories."
             "Only members with valid permissions can post in closed categories."
         ),
         ),
     )
     )
-    css_class = forms.CharField(
-        label=_("CSS class"),
-        required=False,
-        help_text=_(
-            "Optional CSS class used to customize this category appearance from templates."
-        ),
-    )
     require_threads_approval = YesNoSwitch(
     require_threads_approval = YesNoSwitch(
         label=_("Threads"),
         label=_("Threads"),
         required=False,
         required=False,
@@ -90,23 +84,24 @@ class CategoryFormBase(forms.ModelForm):
         label=_("Edits"),
         label=_("Edits"),
         required=False,
         required=False,
         help_text=_(
         help_text=_(
-            "Will make all edited replies return to unapproved state for moderator to review."
+            "Will make all edited replies return to unapproved state "
+            "for moderator to review."
         ),
         ),
     )
     )
     prune_started_after = forms.IntegerField(
     prune_started_after = forms.IntegerField(
         label=_("Thread age"),
         label=_("Thread age"),
         min_value=0,
         min_value=0,
         help_text=_(
         help_text=_(
-            "Prune thread if number of days since its creation is greater than specified. "
-            "Enter 0 to disable this pruning criteria."
+            "Prune thread if number of days since its creation is greater than "
+            "specified. Enter 0 to disable this pruning criteria."
         ),
         ),
     )
     )
     prune_replied_after = forms.IntegerField(
     prune_replied_after = forms.IntegerField(
         label=_("Last reply"),
         label=_("Last reply"),
         min_value=0,
         min_value=0,
         help_text=_(
         help_text=_(
-            "Prune thread if number of days since last reply is greater than specified. "
-            "Enter 0 to disable this pruning criteria."
+            "Prune thread if number of days since last reply is greater than "
+            "specified. Enter 0 to disable this pruning criteria."
         ),
         ),
     )
     )
 
 

+ 0 - 4
misago/categories/views/permsadmin.py

@@ -87,8 +87,6 @@ class DeleteCategoryRole(CategoryRoleAdmin, generic.ButtonView):
 
 
 
 
 class CategoryPermissions(CategoryAdmin, generic.ModelFormView):
 class CategoryPermissions(CategoryAdmin, generic.ModelFormView):
-    """category roles view for assinging roles to category, add link to it in categories list"""
-
     templates_dir = "misago/admin/categoryroles"
     templates_dir = "misago/admin/categoryroles"
     template = "categoryroles.html"
     template = "categoryroles.html"
 
 
@@ -148,8 +146,6 @@ CategoriesList.add_item_action(
 
 
 
 
 class RoleCategoriesACL(RoleAdmin, generic.ModelFormView):
 class RoleCategoriesACL(RoleAdmin, generic.ModelFormView):
-    """role categories view for assinging categories to role, add link to it in user roles list"""
-
     templates_dir = "misago/admin/categoryroles"
     templates_dir = "misago/admin/categoryroles"
     template = "rolecategories.html"
     template = "rolecategories.html"
 
 

+ 4 - 4
misago/legal/forms.py

@@ -16,10 +16,10 @@ class AgreementForm(forms.ModelForm):
     is_active = forms.BooleanField(
     is_active = forms.BooleanField(
         label=_("Set as active for its type"),
         label=_("Set as active for its type"),
         help_text=_(
         help_text=_(
-            "If other agreement is already active for this type, it will be unset and replaced "
-            "with this one. "
-            "Misago will ask users who didn't accept this agreement to do so before allowing them "
-            "to continue using the site's features."
+            "If other agreement is already active for this type, it will be unset "
+            "and replaced with this one. "
+            "Misago will ask users who didn't accept this agreement to do so "
+            "before allowing them to continue using the site's features."
         ),
         ),
         required=False,
         required=False,
     )
     )

+ 3 - 1
misago/markup/tests/test_api.py

@@ -81,7 +81,9 @@ class ParseMarkupApiTests(AuthenticatedUserTestCase):
         self.assertEqual(
         self.assertEqual(
             response.json(),
             response.json(),
             {
             {
-                "detail": "Posted message should be at least 5 characters long (it has 3)."
+                "detail": (
+                    "Posted message should be at least 5 characters long (it has 3)."
+                )
             },
             },
         )
         )
 
 

+ 8 - 6
misago/markup/tests/test_mentions.py

@@ -59,9 +59,10 @@ class MentionsTests(AuthenticatedUserTestCase):
             self.user.username
             self.user.username
         )
         )
 
 
-        after = '<p>Hello <a href="{0}">@{1}</a> and <a href="{0}">@{1}</a>, how is it going?</p>'.format(
-            self.user.get_absolute_url(), self.user.username
-        )
+        after = (
+            # pylint: disable=line-too-long
+            '<p>Hello <a href="{0}">@{1}</a> and <a href="{0}">@{1}</a>, how is it going?</p>'
+        ).format(self.user.get_absolute_url(), self.user.username)
 
 
         result = {"parsed_text": before, "mentions": []}
         result = {"parsed_text": before, "mentions": []}
 
 
@@ -75,9 +76,10 @@ class MentionsTests(AuthenticatedUserTestCase):
             self.user.username
             self.user.username
         )
         )
 
 
-        after = '<p>Hello <a href="{0}">@{1}</a></p><p><a href="{0}">@{1}</a>, how is it going?</p>'.format(
-            self.user.get_absolute_url(), self.user.username
-        )
+        after = (
+            # pylint: disable=line-too-long
+            '<p>Hello <a href="{0}">@{1}</a></p><p><a href="{0}">@{1}</a>, how is it going?</p>'
+        ).format(self.user.get_absolute_url(), self.user.username)
 
 
         result = {"parsed_text": before, "mentions": []}
         result = {"parsed_text": before, "mentions": []}
 
 

+ 4 - 1
misago/search/tests/test_searchproviders.py

@@ -53,7 +53,10 @@ class SearchProvidersTests(TestCase):
         self.assertEqual(searchproviders.get_providers("REQUEST")[0].request, "REQUEST")
         self.assertEqual(searchproviders.get_providers("REQUEST")[0].request, "REQUEST")
 
 
     def test_get_allowed_providers(self):
     def test_get_allowed_providers(self):
-        """get_allowed_providers returns only providers that didn't raise in allow_search"""
+        """
+        allowed providers getter returns only providers that didn't raise an exception 
+        in allow_search
+        """
         searchproviders = SearchProviders([])
         searchproviders = SearchProviders([])
 
 
         searchproviders._initialized = True
         searchproviders._initialized = True

+ 2 - 1
misago/threads/api/attachments.py

@@ -101,7 +101,8 @@ def validate_filesize(upload, filetype, hard_limit):
 
 
     if filetype.size_limit and upload.size > filetype.size_limit * 1024:
     if filetype.size_limit and upload.size > filetype.size_limit * 1024:
         message = _(
         message = _(
-            "You can't upload files of this type larger than %(limit)s (your file has %(upload)s)."
+            "You can't upload files of this type larger "
+            "than %(limit)s (your file has %(upload)s)."
         )
         )
         raise ValidationError(
         raise ValidationError(
             message
             message

+ 4 - 2
misago/threads/api/postingendpoint/__init__.py

@@ -118,7 +118,8 @@ class PostingEndpoint:
                 obj.pre_save(self._serializers.get(middleware))
                 obj.pre_save(self._serializers.get(middleware))
         except PostingInterrupt as e:
         except PostingInterrupt as e:
             raise ValueError(
             raise ValueError(
-                "Posting process can only be interrupted from within interrupt_posting method"
+                "Posting process can only be interrupted "
+                "from within interrupt_posting method"
             )
             )
 
 
         try:
         try:
@@ -134,7 +135,8 @@ class PostingEndpoint:
                 obj.post_save(self._serializers.get(middleware))
                 obj.post_save(self._serializers.get(middleware))
         except PostingInterrupt as e:
         except PostingInterrupt as e:
             raise ValueError(
             raise ValueError(
-                "Posting process can only be interrupted from within interrupt_posting method"
+                "Posting process can only be interrupted "
+                "from within interrupt_posting method"
             )
             )
 
 
 
 

+ 3 - 1
misago/threads/api/postingendpoint/attachments.py

@@ -59,7 +59,8 @@ class AttachmentsSerializer(serializers.Serializer):
                     self.removed_attachments.append(attachment)
                     self.removed_attachments.append(attachment)
                 else:
                 else:
                     message = _(
                     message = _(
-                        'You don\'t have permission to remove "%(attachment)s" attachment.'
+                        "You don't have permission to remove "
+                        '"%(attachment)s" attachment.'
                     )
                     )
                     raise serializers.ValidationError(
                     raise serializers.ValidationError(
                         message % {"attachment": attachment.filename}
                         message % {"attachment": attachment.filename}
@@ -123,6 +124,7 @@ class AttachmentsSerializer(serializers.Serializer):
 def validate_attachments_count(data):
 def validate_attachments_count(data):
     total_attachments = len(data)
     total_attachments = len(data)
     if total_attachments > settings.MISAGO_POST_ATTACHMENTS_LIMIT:
     if total_attachments > settings.MISAGO_POST_ATTACHMENTS_LIMIT:
+        # pylint: disable=line-too-long
         message = ngettext(
         message = ngettext(
             "You can't attach more than %(limit_value)s file to single post (added %(show_value)s).",
             "You can't attach more than %(limit_value)s file to single post (added %(show_value)s).",
             "You can't attach more than %(limit_value)s flies to single post (added %(show_value)s).",
             "You can't attach more than %(limit_value)s flies to single post (added %(show_value)s).",

+ 5 - 2
misago/threads/api/postingendpoint/category.py

@@ -13,7 +13,9 @@ from ...threadtypes import trees_map
 
 
 
 
 class CategoryMiddleware(PostingMiddleware):
 class CategoryMiddleware(PostingMiddleware):
-    """middleware that validates category id and sets category on thread and post instances"""
+    """
+    middleware that validates category id and sets category on thread and post instances
+    """
 
 
     def use_this_middleware(self):
     def use_this_middleware(self):
         if self.mode == PostingEndpoint.START:
         if self.mode == PostingEndpoint.START:
@@ -66,7 +68,8 @@ class CategorySerializer(serializers.Serializer):
         except Category.DoesNotExist:
         except Category.DoesNotExist:
             raise serializers.ValidationError(
             raise serializers.ValidationError(
                 _(
                 _(
-                    "Selected category doesn't exist or you don't have permission to browse it."
+                    "Selected category doesn't exist or "
+                    "you don't have permission to browse it."
                 )
                 )
             )
             )
         except PermissionDenied as e:
         except PermissionDenied as e:

+ 3 - 1
misago/threads/api/postingendpoint/participants.py

@@ -49,7 +49,8 @@ class ParticipantsSerializer(serializers.Serializer):
             if clean_name == self.context["user"].slug:
             if clean_name == self.context["user"].slug:
                 raise serializers.ValidationError(
                 raise serializers.ValidationError(
                     _(
                     _(
-                        "You can't include yourself on the list of users to invite to new thread."
+                        "You can't include yourself on the "
+                        "list of users to invite to new thread."
                     )
                     )
                 )
                 )
 
 
@@ -61,6 +62,7 @@ class ParticipantsSerializer(serializers.Serializer):
 
 
         max_participants = self.context["user_acl"]["max_private_thread_participants"]
         max_participants = self.context["user_acl"]["max_private_thread_participants"]
         if max_participants and len(clean_usernames) > max_participants:
         if max_participants and len(clean_usernames) > max_participants:
+            # pylint: disable=line-too-long
             message = ngettext(
             message = ngettext(
                 "You can't add more than %(users)s user to private thread (you've added %(added)s).",
                 "You can't add more than %(users)s user to private thread (you've added %(added)s).",
                 "You can't add more than %(users)s users to private thread (you've added %(added)s).",
                 "You can't add more than %(users)s users to private thread (you've added %(added)s).",

+ 4 - 2
misago/threads/api/threadendpoints/editor.py

@@ -47,7 +47,8 @@ def thread_start_editor(request):
             }
             }
         )
         )
 
 
-    # list only categories that allow new threads, or contains subcategory that allows one
+    # list only categories that allow new threads,
+    # or contains subcategory that allows one
     cleaned_categories = []
     cleaned_categories = []
     for category in reversed(categories):
     for category in reversed(categories):
         if category["id"] in available:
         if category["id"] in available:
@@ -56,7 +57,8 @@ def thread_start_editor(request):
     if not cleaned_categories:
     if not cleaned_categories:
         raise PermissionDenied(
         raise PermissionDenied(
             _(
             _(
-                "No categories that allow new threads are available to you at the moment."
+                "No categories that allow new threads "
+                "are available to you at the moment."
             )
             )
         )
         )
 
 

+ 2 - 1
misago/threads/api/threadendpoints/patch.py

@@ -272,7 +272,8 @@ def patch_unmark_best_answer(request, thread, value):
     if not post.is_best_answer:
     if not post.is_best_answer:
         raise PermissionDenied(
         raise PermissionDenied(
             _(
             _(
-                "This post can't be unmarked because it's not currently marked as best answer."
+                "This post can't be unmarked because "
+                "it's not currently marked as best answer."
             )
             )
         )
         )
 
 

+ 12 - 10
misago/threads/forms.py

@@ -61,10 +61,12 @@ class AttachmentTypeForm(forms.ModelForm):
         }
         }
         help_texts = {
         help_texts = {
             "extensions": _(
             "extensions": _(
-                "List of comma separated file extensions associated with this attachment type."
+                "List of comma separated file extensions associated with this "
+                "attachment type."
             ),
             ),
             "mimetypes": _(
             "mimetypes": _(
-                "Optional list of comma separated mime types associated with this attachment type."
+                "Optional list of comma separated mime types associated with this "
+                "attachment type."
             ),
             ),
             "size_limit": _(
             "size_limit": _(
                 "Maximum allowed uploaded file size for this type, in kb. "
                 "Maximum allowed uploaded file size for this type, in kb. "
@@ -72,16 +74,16 @@ class AttachmentTypeForm(forms.ModelForm):
             ),
             ),
             "status": _("Controls this attachment type availability on your site."),
             "status": _("Controls this attachment type availability on your site."),
             "limit_uploads_to": _(
             "limit_uploads_to": _(
-                "If you wish to limit option to upload files of this type to users with specific "
-                "roles, select them on this list. Otherwhise don't select any roles to allow all "
-                "users with permission to upload attachments to be able to upload attachments of "
-                "this type."
+                "If you wish to limit option to upload files of this type to users "
+                "with specific roles, select them on this list. Otherwhise don't "
+                "select any roles to allow all users with permission to upload "
+                "attachments to be able to upload attachments of this type."
             ),
             ),
             "limit_downloads_to": _(
             "limit_downloads_to": _(
-                "If you wish to limit option to download files of this type to users with "
-                "specific roles, select them on this list. Otherwhise don't select any roles to "
-                "allow all users with permission to download attachments to be able to download "
-                "attachments of this type."
+                "If you wish to limit option to download files of this type to users "
+                "with specific roles, select them on this list. Otherwhise don't "
+                "select any roles to allow all users with permission to download "
+                "attachments to be able to download attachments of this type."
             ),
             ),
         }
         }
         widgets = {
         widgets = {

+ 2 - 2
misago/threads/mergeconflict.py

@@ -82,8 +82,8 @@ class PollMergeHandler(MergeConflictHandler):
 
 
 class MergeConflict:
 class MergeConflict:
     """
     """
-    Utility class single point of entry for detecting merge conflicts on different properties
-    and validating user resolutions.
+    Utility class single point of entry for detecting merge conflicts on different
+    properties and validating user resolutions.
     """
     """
 
 
     HANDLERS = (BestAnswerMergeHandler, PollMergeHandler)
     HANDLERS = (BestAnswerMergeHandler, PollMergeHandler)

+ 1 - 1
misago/threads/paginator.py

@@ -2,7 +2,7 @@ from django.core.paginator import Paginator
 
 
 
 
 class PostsPaginator(Paginator):
 class PostsPaginator(Paginator):
-    """paginator that returns that makes last item on page repeat as first item on next page."""
+    """paginator that makes last item on page repeat as first item on next page."""
 
 
     def __init__(self, object_list, per_page, orphans=0, allow_empty_first_page=True):
     def __init__(self, object_list, per_page, orphans=0, allow_empty_first_page=True):
         per_page = int(per_page) - 1
         per_page = int(per_page) - 1

+ 46 - 53
misago/threads/permissions/bestanswers.py

@@ -44,7 +44,8 @@ class CategoryPermissionsForm(forms.Form):
             "Time limit for changing marked best answer in owned thread, in minutes"
             "Time limit for changing marked best answer in owned thread, in minutes"
         ),
         ),
         help_text=_(
         help_text=_(
-            "Enter 0 to don't limit time for changing marked best answer in owned thread."
+            "Enter 0 to don't limit time for changing marked best answer in "
+            "owned thread."
         ),
         ),
         initial=0,
         initial=0,
         min_value=0,
         min_value=0,
@@ -137,7 +138,8 @@ def allow_mark_best_answer(user_acl, target):
     if not category_acl.get("can_mark_best_answers"):
     if not category_acl.get("can_mark_best_answers"):
         raise PermissionDenied(
         raise PermissionDenied(
             _(
             _(
-                'You don\'t have permission to mark best answers in the "%(category)s" category.'
+                "You don't have permission to mark best answers in the "
+                '"%(category)s" category.'
             )
             )
             % {"category": target.category}
             % {"category": target.category}
         )
         )
@@ -148,8 +150,8 @@ def allow_mark_best_answer(user_acl, target):
     ):
     ):
         raise PermissionDenied(
         raise PermissionDenied(
             _(
             _(
-                "You don't have permission to mark best answer in this thread because you didn't "
-                "start it."
+                "You don't have permission to mark best answer in this thread "
+                "because you didn't start it."
             )
             )
         )
         )
 
 
@@ -157,16 +159,16 @@ def allow_mark_best_answer(user_acl, target):
         if target.category.is_closed:
         if target.category.is_closed:
             raise PermissionDenied(
             raise PermissionDenied(
                 _(
                 _(
-                    "You don't have permission to mark best answer in this thread because its "
-                    'category "%(category)s" is closed.'
+                    "You don't have permission to mark best answer in this thread "
+                    'because its category "%(category)s" is closed.'
                 )
                 )
                 % {"category": target.category}
                 % {"category": target.category}
             )
             )
         if target.is_closed:
         if target.is_closed:
             raise PermissionDenied(
             raise PermissionDenied(
                 _(
                 _(
-                    "You can't mark best answer in this thread because it's closed and you don't "
-                    "have permission to open it."
+                    "You can't mark best answer in this thread because it's closed "
+                    "and you don't have permission to open it."
                 )
                 )
             )
             )
 
 
@@ -183,8 +185,8 @@ def allow_change_best_answer(user_acl, target):
     if not category_acl.get("can_change_marked_answers"):
     if not category_acl.get("can_change_marked_answers"):
         raise PermissionDenied(
         raise PermissionDenied(
             _(
             _(
-                "You don't have permission to change this thread's marked answer because it's "
-                'in the "%(category)s" category.'
+                "You don't have permission to change this thread's marked answer "
+                'because it\'s in the "%(category)s" category.'
             )
             )
             % {"category": target.category}
             % {"category": target.category}
         )
         )
@@ -193,31 +195,26 @@ def allow_change_best_answer(user_acl, target):
         if user_acl["user_id"] != target.starter_id:
         if user_acl["user_id"] != target.starter_id:
             raise PermissionDenied(
             raise PermissionDenied(
                 _(
                 _(
-                    "You don't have permission to change this thread's marked answer because you "
-                    "are not a thread starter."
+                    "You don't have permission to change this thread's marked answer "
+                    "because you are not a thread starter."
                 )
                 )
             )
             )
         if not has_time_to_change_answer(user_acl, target):
         if not has_time_to_change_answer(user_acl, target):
+            # pylint: disable=line-too-long
+            message = ngettext(
+                "You don't have permission to change best answer that was marked for more than %(minutes)s minute.",
+                "You don't have permission to change best answer that was marked for more than %(minutes)s minutes.",
+                category_acl["best_answer_change_time"],
+            )
             raise PermissionDenied(
             raise PermissionDenied(
-                ngettext(
-                    (
-                        "You don't have permission to change best answer that was marked for more "
-                        "than %(minutes)s minute."
-                    ),
-                    (
-                        "You don't have permission to change best answer that was marked for more "
-                        "than %(minutes)s minutes."
-                    ),
-                    category_acl["best_answer_change_time"],
-                )
-                % {"minutes": category_acl["best_answer_change_time"]}
+                message % {"minutes": category_acl["best_answer_change_time"]}
             )
             )
 
 
     if target.best_answer_is_protected and not category_acl["can_protect_posts"]:
     if target.best_answer_is_protected and not category_acl["can_protect_posts"]:
         raise PermissionDenied(
         raise PermissionDenied(
             _(
             _(
-                "You don't have permission to change this thread's best answer because "
-                "a moderator has protected it."
+                "You don't have permission to change this thread's best answer "
+                "because a moderator has protected it."
             )
             )
         )
         )
 
 
@@ -237,8 +234,8 @@ def allow_unmark_best_answer(user_acl, target):
     if not category_acl.get("can_change_marked_answers"):
     if not category_acl.get("can_change_marked_answers"):
         raise PermissionDenied(
         raise PermissionDenied(
             _(
             _(
-                'You don\'t have permission to unmark threads answers in the "%(category)s" '
-                "category."
+                "You don't have permission to unmark threads answers in "
+                'the "%(category)s" category.'
             )
             )
             % {"category": target.category}
             % {"category": target.category}
         )
         )
@@ -247,48 +244,43 @@ def allow_unmark_best_answer(user_acl, target):
         if user_acl["user_id"] != target.starter_id:
         if user_acl["user_id"] != target.starter_id:
             raise PermissionDenied(
             raise PermissionDenied(
                 _(
                 _(
-                    "You don't have permission to unmark this best answer because you are not a "
-                    "thread starter."
+                    "You don't have permission to unmark this best answer "
+                    "because you are not a thread starter."
                 )
                 )
             )
             )
         if not has_time_to_change_answer(user_acl, target):
         if not has_time_to_change_answer(user_acl, target):
+            # pylint: disable=line-too-long
+            message = ngettext(
+                "You don't have permission to unmark best answer that was marked for more than %(minutes)s minute.",
+                "You don't have permission to unmark best answer that was marked for more than %(minutes)s minutes.",
+                category_acl["best_answer_change_time"],
+            )
             raise PermissionDenied(
             raise PermissionDenied(
-                ngettext(
-                    (
-                        "You don't have permission to unmark best answer that was marked for more "
-                        "than %(minutes)s minute."
-                    ),
-                    (
-                        "You don't have permission to unmark best answer that was marked for more "
-                        "than %(minutes)s minutes."
-                    ),
-                    category_acl["best_answer_change_time"],
-                )
-                % {"minutes": category_acl["best_answer_change_time"]}
+                message % {"minutes": category_acl["best_answer_change_time"]}
             )
             )
 
 
     if not category_acl["can_close_threads"]:
     if not category_acl["can_close_threads"]:
         if target.category.is_closed:
         if target.category.is_closed:
             raise PermissionDenied(
             raise PermissionDenied(
                 _(
                 _(
-                    "You don't have permission to unmark this best answer because its category "
-                    '"%(category)s" is closed.'
+                    "You don't have permission to unmark this best answer "
+                    'because its category "%(category)s" is closed.'
                 )
                 )
                 % {"category": target.category}
                 % {"category": target.category}
             )
             )
         if target.is_closed:
         if target.is_closed:
             raise PermissionDenied(
             raise PermissionDenied(
                 _(
                 _(
-                    "You can't unmark this thread's best answer because it's closed and you "
-                    "don't have permission to open it."
+                    "You can't unmark this thread's best answer "
+                    "because it's closed and you don't have permission to open it."
                 )
                 )
             )
             )
 
 
     if target.best_answer_is_protected and not category_acl["can_protect_posts"]:
     if target.best_answer_is_protected and not category_acl["can_protect_posts"]:
         raise PermissionDenied(
         raise PermissionDenied(
             _(
             _(
-                "You don't have permission to unmark this thread's best answer because a "
-                "moderator has protected it."
+                "You don't have permission to unmark this thread's best answer "
+                "because a moderator has protected it."
             )
             )
         )
         )
 
 
@@ -308,7 +300,8 @@ def allow_mark_as_best_answer(user_acl, target):
     if not category_acl.get("can_mark_best_answers"):
     if not category_acl.get("can_mark_best_answers"):
         raise PermissionDenied(
         raise PermissionDenied(
             _(
             _(
-                'You don\'t have permission to mark best answers in the "%(category)s" category.'
+                "You don't have permission to mark best answers "
+                'in the "%(category)s" category.'
             )
             )
             % {"category": target.category}
             % {"category": target.category}
         )
         )
@@ -319,8 +312,8 @@ def allow_mark_as_best_answer(user_acl, target):
     ):
     ):
         raise PermissionDenied(
         raise PermissionDenied(
             _(
             _(
-                "You don't have permission to mark best answer in this thread because you "
-                "didn't start it."
+                "You don't have permission to mark best answer in this thread "
+                "because you didn't start it."
             )
             )
         )
         )
 
 
@@ -338,8 +331,8 @@ def allow_mark_as_best_answer(user_acl, target):
     if target.is_protected and not category_acl["can_protect_posts"]:
     if target.is_protected and not category_acl["can_protect_posts"]:
         raise PermissionDenied(
         raise PermissionDenied(
             _(
             _(
-                "You don't have permission to mark this post as best answer because a moderator "
-                "has protected it."
+                "You don't have permission to mark this post as best answer "
+                "because a moderator has protected it."
             )
             )
         )
         )
 
 

+ 4 - 2
misago/threads/serializers/moderation.py

@@ -163,7 +163,8 @@ class MergePostsSerializer(serializers.Serializer):
             if posts[0].is_first_post and post.is_best_answer:
             if posts[0].is_first_post and post.is_best_answer:
                 raise serializers.ValidationError(
                 raise serializers.ValidationError(
                     _(
                     _(
-                        "Post marked as best answer can't be merged with thread's first post."
+                        "Post marked as best answer can't be merged with "
+                        "thread's first post."
                     )
                     )
                 )
                 )
 
 
@@ -311,7 +312,8 @@ class NewThreadSerializer(serializers.Serializer):
             if weight == 2:
             if weight == 2:
                 raise ValidationError(
                 raise ValidationError(
                     _(
                     _(
-                        "You don't have permission to pin threads globally in this category."
+                        "You don't have permission to pin threads globally "
+                        "in this category."
                     )
                     )
                 )
                 )
             else:
             else:

+ 3 - 1
misago/threads/serializers/poll.py

@@ -117,6 +117,7 @@ class EditPollSerializer(serializers.ModelSerializer):
             )
             )
 
 
         if total_choices > MAX_POLL_OPTIONS:
         if total_choices > MAX_POLL_OPTIONS:
+            # pylint: disable=line-too-long
             message = ngettext(
             message = ngettext(
                 "You can't add more than %(limit_value)s option to a single poll (added %(show_value)s).",
                 "You can't add more than %(limit_value)s option to a single poll (added %(show_value)s).",
                 "You can't add more than %(limit_value)s options to a single poll (added %(show_value)s).",
                 "You can't add more than %(limit_value)s options to a single poll (added %(show_value)s).",
@@ -130,7 +131,8 @@ class EditPollSerializer(serializers.ModelSerializer):
         if data["allowed_choices"] > len(data["choices"]):
         if data["allowed_choices"] > len(data["choices"]):
             raise serializers.ValidationError(
             raise serializers.ValidationError(
                 _(
                 _(
-                    "Number of allowed choices can't be greater than number of all choices."
+                    "Number of allowed choices can't be "
+                    "greater than number of all choices."
                 )
                 )
             )
             )
         return data
         return data

+ 6 - 8
misago/threads/templatetags/misago_poststags.py

@@ -25,16 +25,14 @@ def likes_label(post):
     if not hidden_likes:
     if not hidden_likes:
         return _("%(users)s like this.") % {"users": usernames_string}
         return _("%(users)s like this.") % {"users": usernames_string}
 
 
+    label = ngettext(
+        "%(users)s and %(likes)s other user like this.",
+        "%(users)s and %(likes)s other users like this.",
+        hidden_likes,
+    )
     formats = {"users": usernames_string, "likes": hidden_likes}
     formats = {"users": usernames_string, "likes": hidden_likes}
 
 
-    return (
-        ngettext(
-            "%(users)s and %(likes)s other user like this.",
-            "%(users)s and %(likes)s other users like this.",
-            hidden_likes,
-        )
-        % formats
-    )
+    return label % formats
 
 
 
 
 def humanize_usernames_list(usernames):
 def humanize_usernames_list(usernames):

+ 2 - 1
misago/threads/tests/test_attachments_api.py

@@ -158,7 +158,8 @@ class AttachmentsApiTestCase(AuthenticatedUserTestCase):
                 response.json(),
                 response.json(),
                 {
                 {
                     "detail": (
                     "detail": (
-                        "You can't upload files larger than 100.0\xa0KB (your file has 253.9\xa0KB)."
+                        "You can't upload files larger than 100.0\xa0KB "
+                        "(your file has 253.9\xa0KB)."
                     )
                     )
                 },
                 },
             )
             )

+ 9 - 3
misago/threads/tests/test_attachments_middleware.py

@@ -107,7 +107,9 @@ class AttachmentsMiddlewareTests(AuthenticatedUserTestCase):
 
 
     @patch_attachments_acl()
     @patch_attachments_acl()
     def test_get_initial_attachments(self):
     def test_get_initial_attachments(self):
-        """get_initial_attachments returns list of attachments already existing on post"""
+        """
+        get_initial_attachments returns list of attachments already existing on post
+        """
         user_acl = useracl.get_user_acl(self.user, cache_versions)
         user_acl = useracl.get_user_acl(self.user, cache_versions)
         middleware = AttachmentsMiddleware(
         middleware = AttachmentsMiddleware(
             request=Mock(data={}),
             request=Mock(data={}),
@@ -132,7 +134,9 @@ class AttachmentsMiddlewareTests(AuthenticatedUserTestCase):
 
 
     @patch_attachments_acl()
     @patch_attachments_acl()
     def test_get_new_attachments(self):
     def test_get_new_attachments(self):
-        """get_initial_attachments returns list of attachments already existing on post"""
+        """
+        get_initial_attachments returns list of attachments already existing on post
+        """
         user_acl = useracl.get_user_acl(self.user, cache_versions)
         user_acl = useracl.get_user_acl(self.user, cache_versions)
         middleware = AttachmentsMiddleware(
         middleware = AttachmentsMiddleware(
             request=Mock(data={}),
             request=Mock(data={}),
@@ -160,7 +164,9 @@ class AttachmentsMiddlewareTests(AuthenticatedUserTestCase):
 
 
     @patch_attachments_acl({"can_delete_other_users_attachments": False})
     @patch_attachments_acl({"can_delete_other_users_attachments": False})
     def test_cant_delete_attachment(self):
     def test_cant_delete_attachment(self):
-        """middleware validates if we have permission to delete other users attachments"""
+        """
+        middleware validates if we have permission to delete other users attachments
+        """
         attachment = self.mock_attachment(user=False, post=self.post)
         attachment = self.mock_attachment(user=False, post=self.post)
         self.assertIsNone(attachment.uploader)
         self.assertIsNone(attachment.uploader)
 
 

+ 7 - 2
misago/threads/tests/test_mergeconflict.py

@@ -75,7 +75,9 @@ class MergeConflictTests(TestCase):
         self.assertFalse(merge_conflict.is_merge_conflict())
         self.assertFalse(merge_conflict.is_merge_conflict())
 
 
     def test_three_best_answers_one_poll_two_plain_conflict(self):
     def test_three_best_answers_one_poll_two_plain_conflict(self):
-        """three threads with best answer, thread with poll and two plain threads conflict"""
+        """
+        three threads with best answer, thread with poll and two plain threads conflict
+        """
         best_answers = [self.create_best_answer_thread() for i in range(3)]
         best_answers = [self.create_best_answer_thread() for i in range(3)]
         polls = [self.create_poll_thread()]
         polls = [self.create_poll_thread()]
         threads = (
         threads = (
@@ -133,7 +135,10 @@ class MergeConflictTests(TestCase):
         )
         )
 
 
     def test_one_best_answer_three_polls_two_plain_conflict(self):
     def test_one_best_answer_three_polls_two_plain_conflict(self):
-        """one thread with best answer, three threads with poll and two plain threads conflict"""
+        """
+        one thread with best answer, three threads with poll
+        and two plain threads conflict
+        """
         best_answers = [self.create_best_answer_thread()]
         best_answers = [self.create_best_answer_thread()]
         polls = [self.create_poll_thread() for i in range(3)]
         polls = [self.create_poll_thread() for i in range(3)]
         threads = (
         threads = (

+ 4 - 1
misago/threads/tests/test_privatethread_patch_api.py

@@ -168,7 +168,10 @@ class PrivateThreadAddParticipantApiTests(PrivateThreadPatchApiTestCase):
         )
         )
 
 
     def test_add_user(self):
     def test_add_user(self):
-        """adding user to thread add user to thread as participant, sets event and emails him"""
+        """
+        adding user to thread add user to thread as participant,
+        sets event and emails him
+        """
         ThreadParticipant.objects.set_owner(self.thread, self.user)
         ThreadParticipant.objects.set_owner(self.thread, self.user)
 
 
         self.patch(
         self.patch(

+ 4 - 2
misago/threads/tests/test_privatethread_start_api.py

@@ -112,7 +112,8 @@ class StartPrivateThreadTests(AuthenticatedUserTestCase):
             response.json(),
             response.json(),
             {
             {
                 "to": [
                 "to": [
-                    "You can't include yourself on the list of users to invite to new thread."
+                    "You can't include yourself on the list "
+                    "of users to invite to new thread."
                 ]
                 ]
             },
             },
         )
         )
@@ -149,7 +150,8 @@ class StartPrivateThreadTests(AuthenticatedUserTestCase):
             response.json(),
             response.json(),
             {
             {
                 "to": [
                 "to": [
-                    "You can't add more than 3 users to private thread (you've added 50)."
+                    "You can't add more than 3 users to private thread "
+                    "(you've added 50)."
                 ]
                 ]
             },
             },
         )
         )

+ 3 - 1
misago/threads/tests/test_sync_unread_private_threads.py

@@ -29,7 +29,9 @@ class SyncUnreadPrivateThreadsTestCase(PrivateThreadsTestCase):
         self.assertEqual(self.user.unread_private_threads, 1)
         self.assertEqual(self.user.unread_private_threads, 1)
 
 
     def test_middleware_counts_unread_thread(self):
     def test_middleware_counts_unread_thread(self):
-        """middleware counts thread with unread reply, post read flags user for recount"""
+        """
+        middleware counts thread with unread reply, post read flags user for recount
+        """
         self.user.sync_unread_private_threads = True
         self.user.sync_unread_private_threads = True
         self.user.save()
         self.user.save()
 
 

+ 61 - 40
misago/threads/tests/test_thread_patch_api.py

@@ -30,7 +30,9 @@ class ThreadAddAclApiTests(ThreadPatchApiTestCase):
         self.assertTrue(response_json["acl"])
         self.assertTrue(response_json["acl"])
 
 
     def test_add_acl_false(self):
     def test_add_acl_false(self):
-        """if value is false, api won't add acl to the response, but will set empty key"""
+        """
+        if value is false, api won't add acl to the response, but will set empty key
+        """
         response = self.patch(
         response = self.patch(
             self.api_link, [{"op": "add", "path": "acl", "value": False}]
             self.api_link, [{"op": "add", "path": "acl", "value": False}]
         )
         )
@@ -1048,7 +1050,8 @@ class ThreadMarkBestAnswerApiTests(ThreadPatchApiTestCase):
             {
             {
                 "id": self.thread.id,
                 "id": self.thread.id,
                 "detail": [
                 "detail": [
-                    'You don\'t have permission to mark best answers in the "First category" category.'
+                    "You don't have permission to mark best answers "
+                    'in the "First category" category.'
                 ],
                 ],
             },
             },
         )
         )
@@ -1071,8 +1074,8 @@ class ThreadMarkBestAnswerApiTests(ThreadPatchApiTestCase):
             {
             {
                 "id": self.thread.id,
                 "id": self.thread.id,
                 "detail": [
                 "detail": [
-                    "You don't have permission to mark best answer in this thread because you didn't "
-                    "start it."
+                    "You don't have permission to mark best answer in this thread "
+                    "because you didn't start it."
                 ],
                 ],
             },
             },
         )
         )
@@ -1108,8 +1111,8 @@ class ThreadMarkBestAnswerApiTests(ThreadPatchApiTestCase):
             {
             {
                 "id": self.thread.id,
                 "id": self.thread.id,
                 "detail": [
                 "detail": [
-                    "You don't have permission to mark best answer in this thread because its "
-                    'category "First category" is closed.'
+                    "You don't have permission to mark best answer in this thread "
+                    'because its category "First category" is closed.'
                 ],
                 ],
             },
             },
         )
         )
@@ -1149,8 +1152,8 @@ class ThreadMarkBestAnswerApiTests(ThreadPatchApiTestCase):
             {
             {
                 "id": self.thread.id,
                 "id": self.thread.id,
                 "detail": [
                 "detail": [
-                    "You can't mark best answer in this thread because it's closed and you don't have "
-                    "permission to open it."
+                    "You can't mark best answer in this thread because it's closed and "
+                    "you don't have permission to open it."
                 ],
                 ],
             },
             },
         )
         )
@@ -1356,8 +1359,8 @@ class ThreadMarkBestAnswerApiTests(ThreadPatchApiTestCase):
             {
             {
                 "id": self.thread.id,
                 "id": self.thread.id,
                 "detail": [
                 "detail": [
-                    "You don't have permission to mark this post as best answer because a moderator "
-                    "has protected it."
+                    "You don't have permission to mark this post as best answer "
+                    "because a moderator has protected it."
                 ],
                 ],
             },
             },
         )
         )
@@ -1441,7 +1444,9 @@ class ThreadChangeBestAnswerApiTests(ThreadPatchApiTestCase):
 
 
     @patch_category_acl({"can_mark_best_answers": 0, "can_change_marked_answers": 2})
     @patch_category_acl({"can_mark_best_answers": 0, "can_change_marked_answers": 2})
     def test_change_best_answer_no_permission_to_mark(self):
     def test_change_best_answer_no_permission_to_mark(self):
-        """api validates permission to mark best answers before allowing answer change"""
+        """
+        api validates permission to mark best answers before allowing answer change
+        """
         best_answer = test.reply_thread(self.thread)
         best_answer = test.reply_thread(self.thread)
 
 
         response = self.patch(
         response = self.patch(
@@ -1454,7 +1459,8 @@ class ThreadChangeBestAnswerApiTests(ThreadPatchApiTestCase):
             {
             {
                 "id": self.thread.id,
                 "id": self.thread.id,
                 "detail": [
                 "detail": [
-                    'You don\'t have permission to mark best answers in the "First category" category.'
+                    "You don't have permission to mark best answers in the "
+                    '"First category" category.'
                 ],
                 ],
             },
             },
         )
         )
@@ -1477,8 +1483,8 @@ class ThreadChangeBestAnswerApiTests(ThreadPatchApiTestCase):
             {
             {
                 "id": self.thread.id,
                 "id": self.thread.id,
                 "detail": [
                 "detail": [
-                    "You don't have permission to change this thread's marked answer because it's "
-                    'in the "First category" category.'
+                    "You don't have permission to change this thread's marked answer "
+                    'because it\'s in the "First category" category.'
                 ],
                 ],
             },
             },
         )
         )
@@ -1501,8 +1507,8 @@ class ThreadChangeBestAnswerApiTests(ThreadPatchApiTestCase):
             {
             {
                 "id": self.thread.id,
                 "id": self.thread.id,
                 "detail": [
                 "detail": [
-                    "You don't have permission to change this thread's marked answer because you are "
-                    "not a thread starter."
+                    "You don't have permission to change this thread's marked answer "
+                    "because you are not a thread starter."
                 ],
                 ],
             },
             },
         )
         )
@@ -1528,7 +1534,9 @@ class ThreadChangeBestAnswerApiTests(ThreadPatchApiTestCase):
         }
         }
     )
     )
     def test_change_best_answer_timelimit_out_of_time(self):
     def test_change_best_answer_timelimit_out_of_time(self):
-        """api validates permission for starter to change best answers within timelimit"""
+        """
+        api validates permission for starter to change best answers within timelimit
+        """
         best_answer = test.reply_thread(self.thread)
         best_answer = test.reply_thread(self.thread)
 
 
         self.thread.best_answer_marked_on = timezone.now() - timedelta(minutes=6)
         self.thread.best_answer_marked_on = timezone.now() - timedelta(minutes=6)
@@ -1545,8 +1553,8 @@ class ThreadChangeBestAnswerApiTests(ThreadPatchApiTestCase):
             {
             {
                 "id": self.thread.id,
                 "id": self.thread.id,
                 "detail": [
                 "detail": [
-                    "You don't have permission to change best answer that was marked for more than "
-                    "5 minutes."
+                    "You don't have permission to change best answer that was marked "
+                    "for more than 5 minutes."
                 ],
                 ],
             },
             },
         )
         )
@@ -1562,7 +1570,9 @@ class ThreadChangeBestAnswerApiTests(ThreadPatchApiTestCase):
         }
         }
     )
     )
     def test_change_best_answer_timelimit(self):
     def test_change_best_answer_timelimit(self):
-        """api validates permission for starter to change best answers within timelimit"""
+        """
+        api validates permission for starter to change best answers within timelimit
+        """
         best_answer = test.reply_thread(self.thread)
         best_answer = test.reply_thread(self.thread)
 
 
         self.thread.best_answer_marked_on = timezone.now() - timedelta(minutes=1)
         self.thread.best_answer_marked_on = timezone.now() - timedelta(minutes=1)
@@ -1599,8 +1609,8 @@ class ThreadChangeBestAnswerApiTests(ThreadPatchApiTestCase):
             {
             {
                 "id": self.thread.id,
                 "id": self.thread.id,
                 "detail": [
                 "detail": [
-                    "You don't have permission to change this thread's best answer because a "
-                    "moderator has protected it."
+                    "You don't have permission to change this thread's best answer "
+                    "because a moderator has protected it."
                 ],
                 ],
             },
             },
         )
         )
@@ -1727,7 +1737,8 @@ class ThreadUnmarkBestAnswerApiTests(ThreadPatchApiTestCase):
             {
             {
                 "id": self.thread.id,
                 "id": self.thread.id,
                 "detail": [
                 "detail": [
-                    "This post can't be unmarked because it's not currently marked as best answer."
+                    "This post can't be unmarked because it's not currently marked "
+                    "as best answer."
                 ],
                 ],
             },
             },
         )
         )
@@ -1748,8 +1759,8 @@ class ThreadUnmarkBestAnswerApiTests(ThreadPatchApiTestCase):
             {
             {
                 "id": self.thread.id,
                 "id": self.thread.id,
                 "detail": [
                 "detail": [
-                    'You don\'t have permission to unmark threads answers in the "First category" '
-                    "category."
+                    "You don't have permission to unmark threads answers in "
+                    'the "First category" category.'
                 ],
                 ],
             },
             },
         )
         )
@@ -1770,8 +1781,8 @@ class ThreadUnmarkBestAnswerApiTests(ThreadPatchApiTestCase):
             {
             {
                 "id": self.thread.id,
                 "id": self.thread.id,
                 "detail": [
                 "detail": [
-                    "You don't have permission to unmark this best answer because you are not a "
-                    "thread starter."
+                    "You don't have permission to unmark this best answer because "
+                    "you are not a thread starter."
                 ],
                 ],
             },
             },
         )
         )
@@ -1797,7 +1808,9 @@ class ThreadUnmarkBestAnswerApiTests(ThreadPatchApiTestCase):
         }
         }
     )
     )
     def test_unmark_best_answer_timelimit(self):
     def test_unmark_best_answer_timelimit(self):
-        """api validates if starter has permission to unmark best answer within time limit"""
+        """
+        api validates if starter has permission to unmark best answer within time limit
+        """
         self.thread.best_answer_marked_on = timezone.now() - timedelta(minutes=6)
         self.thread.best_answer_marked_on = timezone.now() - timedelta(minutes=6)
         self.thread.starter = self.user
         self.thread.starter = self.user
         self.thread.save()
         self.thread.save()
@@ -1812,8 +1825,8 @@ class ThreadUnmarkBestAnswerApiTests(ThreadPatchApiTestCase):
             {
             {
                 "id": self.thread.id,
                 "id": self.thread.id,
                 "detail": [
                 "detail": [
-                    "You don't have permission to unmark best answer that was marked for more than "
-                    "5 minutes."
+                    "You don't have permission to unmark best answer that was marked "
+                    "for more than 5 minutes."
                 ],
                 ],
             },
             },
         )
         )
@@ -1839,7 +1852,9 @@ class ThreadUnmarkBestAnswerApiTests(ThreadPatchApiTestCase):
         }
         }
     )
     )
     def test_unmark_best_answer_closed_category_no_permission(self):
     def test_unmark_best_answer_closed_category_no_permission(self):
-        """api validates if user has permission to unmark best answer in closed category"""
+        """
+        api validates if user has permission to unmark best answer in closed category
+        """
         self.category.is_closed = True
         self.category.is_closed = True
         self.category.save()
         self.category.save()
 
 
@@ -1853,8 +1868,8 @@ class ThreadUnmarkBestAnswerApiTests(ThreadPatchApiTestCase):
             {
             {
                 "id": self.thread.id,
                 "id": self.thread.id,
                 "detail": [
                 "detail": [
-                    "You don't have permission to unmark this best answer because its category "
-                    '"First category" is closed.'
+                    "You don't have permission to unmark this best answer because "
+                    'its category "First category" is closed.'
                 ],
                 ],
             },
             },
         )
         )
@@ -1870,7 +1885,9 @@ class ThreadUnmarkBestAnswerApiTests(ThreadPatchApiTestCase):
         }
         }
     )
     )
     def test_unmark_best_answer_closed_category(self):
     def test_unmark_best_answer_closed_category(self):
-        """api validates if user has permission to unmark best answer in closed category"""
+        """
+        api validates if user has permission to unmark best answer in closed category
+        """
         self.category.is_closed = True
         self.category.is_closed = True
         self.category.save()
         self.category.save()
 
 
@@ -1888,7 +1905,9 @@ class ThreadUnmarkBestAnswerApiTests(ThreadPatchApiTestCase):
         }
         }
     )
     )
     def test_unmark_best_answer_closed_thread_no_permission(self):
     def test_unmark_best_answer_closed_thread_no_permission(self):
-        """api validates if user has permission to unmark best answer in closed thread"""
+        """
+        api validates if user has permission to unmark best answer in closed thread
+        """
         self.thread.is_closed = True
         self.thread.is_closed = True
         self.thread.save()
         self.thread.save()
 
 
@@ -1902,8 +1921,8 @@ class ThreadUnmarkBestAnswerApiTests(ThreadPatchApiTestCase):
             {
             {
                 "id": self.thread.id,
                 "id": self.thread.id,
                 "detail": [
                 "detail": [
-                    "You can't unmark this thread's best answer because it's closed and you don't "
-                    "have permission to open it."
+                    "You can't unmark this thread's best answer because it's closed "
+                    "and you don't have permission to open it."
                 ],
                 ],
             },
             },
         )
         )
@@ -1919,7 +1938,9 @@ class ThreadUnmarkBestAnswerApiTests(ThreadPatchApiTestCase):
         }
         }
     )
     )
     def test_unmark_best_answer_closed_thread(self):
     def test_unmark_best_answer_closed_thread(self):
-        """api validates if user has permission to unmark best answer in closed thread"""
+        """
+        api validates if user has permission to unmark best answer in closed thread
+        """
         self.thread.is_closed = True
         self.thread.is_closed = True
         self.thread.save()
         self.thread.save()
 
 
@@ -1951,8 +1972,8 @@ class ThreadUnmarkBestAnswerApiTests(ThreadPatchApiTestCase):
             {
             {
                 "id": self.thread.id,
                 "id": self.thread.id,
                 "detail": [
                 "detail": [
-                    "You don't have permission to unmark this thread's best answer because a "
-                    "moderator has protected it."
+                    "You don't have permission to unmark this thread's best answer "
+                    "because a moderator has protected it."
                 ],
                 ],
             },
             },
         )
         )

+ 6 - 2
misago/threads/tests/test_thread_pollcreate_api.py

@@ -90,7 +90,9 @@ class ThreadPollCreateTests(ThreadPollApiTestCase):
 
 
     @patch_user_acl({"can_start_polls": 1})
     @patch_user_acl({"can_start_polls": 1})
     def test_other_user_thread_no_permission(self):
     def test_other_user_thread_no_permission(self):
-        """api validates that user has permission to start poll in other user's thread"""
+        """
+        api validates that user has permission to start poll in other user's thread
+        """
         self.thread.starter = None
         self.thread.starter = None
         self.thread.save()
         self.thread.save()
 
 
@@ -102,7 +104,9 @@ class ThreadPollCreateTests(ThreadPollApiTestCase):
 
 
     @patch_user_acl({"can_start_polls": 2})
     @patch_user_acl({"can_start_polls": 2})
     def test_other_user_thread(self):
     def test_other_user_thread(self):
-        """api validates that user has permission to start poll in other user's thread"""
+        """
+        api validates that user has permission to start poll in other user's thread
+        """
         self.thread.starter = None
         self.thread.starter = None
         self.thread.save()
         self.thread.save()
 
 

+ 3 - 1
misago/threads/tests/test_thread_pollvotes_api.py

@@ -243,7 +243,9 @@ class ThreadPostVotesTests(ThreadPollApiTestCase):
         )
         )
 
 
     def test_revote(self):
     def test_revote(self):
-        """api validates if user is trying to change vote in poll that disallows revoting"""
+        """
+        api validates if user is trying to change vote in poll that disallows revoting
+        """
         response = self.post(self.api_link, data=["lorem", "ipsum"])
         response = self.post(self.api_link, data=["lorem", "ipsum"])
         self.assertEqual(response.status_code, 403)
         self.assertEqual(response.status_code, 403)
         self.assertEqual(
         self.assertEqual(

+ 4 - 1
misago/threads/tests/test_thread_postmerge_api.py

@@ -414,7 +414,10 @@ class ThreadPostMergeApiTestCase(AuthenticatedUserTestCase):
         self.assertEqual(
         self.assertEqual(
             response.json(),
             response.json(),
             {
             {
-                "detail": "Post marked as best answer can't be merged with thread's first post."
+                "detail": (
+                    "Post marked as best answer can't be "
+                    "merged with thread's first post."
+                )
             },
             },
         )
         )
 
 

+ 6 - 2
misago/threads/tests/test_thread_postpatch_api.py

@@ -42,7 +42,9 @@ class PostAddAclApiTests(ThreadPostPatchApiTestCase):
         self.assertTrue(response_json["acl"])
         self.assertTrue(response_json["acl"])
 
 
     def test_add_acl_false(self):
     def test_add_acl_false(self):
-        """if value is false, api won't add acl to the response, but will set empty key"""
+        """
+        if value is false, api won't add acl to the response, but will set empty key
+        """
         response = self.patch(
         response = self.patch(
             self.api_link, [{"op": "add", "path": "acl", "value": False}]
             self.api_link, [{"op": "add", "path": "acl", "value": False}]
         )
         )
@@ -879,7 +881,9 @@ class EventAddAclApiTests(ThreadEventPatchApiTestCase):
         self.assertTrue(response_json["acl"])
         self.assertTrue(response_json["acl"])
 
 
     def test_add_acl_false(self):
     def test_add_acl_false(self):
-        """if value is false, api won't add acl to the response, but will set empty key"""
+        """
+        if value is false, api won't add acl to the response, but will set empty key
+        """
         response = self.patch(
         response = self.patch(
             self.api_link, [{"op": "add", "path": "acl", "value": False}]
             self.api_link, [{"op": "add", "path": "acl", "value": False}]
         )
         )

+ 2 - 1
misago/threads/tests/test_thread_postsplit_api.py

@@ -407,7 +407,8 @@ class ThreadPostSplitApiTestCase(AuthenticatedUserTestCase):
             response_json,
             response_json,
             {
             {
                 "weight": [
                 "weight": [
-                    "You don't have permission to pin threads globally in this category."
+                    "You don't have permission to pin threads "
+                    "globally in this category."
                 ]
                 ]
             },
             },
         )
         )

+ 18 - 5
misago/threads/tests/test_threads_editor_api.py

@@ -49,7 +49,10 @@ class ThreadPostEditorApiTests(EditorApiTestCase):
         self.assertEqual(
         self.assertEqual(
             response.json(),
             response.json(),
             {
             {
-                "detail": "No categories that allow new threads are available to you at the moment."
+                "detail": (
+                    "No categories that allow new threads are available "
+                    "to you at the moment."
+                )
             },
             },
         )
         )
 
 
@@ -61,7 +64,10 @@ class ThreadPostEditorApiTests(EditorApiTestCase):
         self.assertEqual(
         self.assertEqual(
             response.json(),
             response.json(),
             {
             {
-                "detail": "No categories that allow new threads are available to you at the moment."
+                "detail": (
+                    "No categories that allow new threads are available "
+                    "to you at the moment."
+                )
             },
             },
         )
         )
 
 
@@ -76,7 +82,10 @@ class ThreadPostEditorApiTests(EditorApiTestCase):
         self.assertEqual(
         self.assertEqual(
             response.json(),
             response.json(),
             {
             {
-                "detail": "No categories that allow new threads are available to you at the moment."
+                "detail": (
+                    "No categories that allow new threads are available "
+                    "to you at the moment."
+                )
             },
             },
         )
         )
 
 
@@ -258,7 +267,9 @@ class ThreadReplyEditorApiTests(EditorApiTestCase):
             self.assertEqual(
             self.assertEqual(
                 response.json(),
                 response.json(),
                 {
                 {
-                    "detail": "This category is closed. You can't reply to threads in it."
+                    "detail": (
+                        "This category is closed. You can't reply to threads in it."
+                    )
                 },
                 },
             )
             )
 
 
@@ -511,7 +522,9 @@ class EditReplyEditorApiTests(EditorApiTestCase):
 
 
     @patch_category_acl({"can_hide_threads": 1, "can_edit_posts": 2})
     @patch_category_acl({"can_hide_threads": 1, "can_edit_posts": 2})
     def test_edit_first_post_hidden(self):
     def test_edit_first_post_hidden(self):
-        """endpoint returns valid configuration for editor of hidden thread's first post"""
+        """
+        endpoint returns valid configuration for editor of hidden thread's first post
+        """
         self.thread.is_hidden = True
         self.thread.is_hidden = True
         self.thread.save()
         self.thread.save()
         self.thread.first_post.is_hidden = True
         self.thread.first_post.is_hidden = True

+ 2 - 1
misago/threads/tests/test_threads_merge_api.py

@@ -371,7 +371,8 @@ class ThreadsMergeApiTests(ThreadsApiTestCase):
             response.json(),
             response.json(),
             {
             {
                 "weight": [
                 "weight": [
-                    "You don't have permission to pin threads globally in this category."
+                    "You don't have permission to pin threads globally "
+                    "in this category."
                 ]
                 ]
             },
             },
         )
         )

+ 3 - 1
misago/threads/tests/test_threadview.py

@@ -191,7 +191,9 @@ class ThreadPostsVisibilityTests(ThreadViewTestCase):
             self.assertContains(response, post.parsed)
             self.assertContains(response, post.parsed)
 
 
     def test_unapproved_post_visibility(self):
     def test_unapproved_post_visibility(self):
-        """unapproved post renders for its author and users with perm to approve content"""
+        """
+        unapproved post renders for its author and users with perm to approve content
+        """
         post = test.reply_thread(self.thread, is_unapproved=True)
         post = test.reply_thread(self.thread, is_unapproved=True)
 
 
         # post is hdden because we aren't its author nor user with permission to approve
         # post is hdden because we aren't its author nor user with permission to approve

+ 4 - 0
misago/threads/validators.py

@@ -45,6 +45,7 @@ def validate_thread_title_length(settings, value):
         raise ValidationError(_("You have to enter an thread title."))
         raise ValidationError(_("You have to enter an thread title."))
 
 
     if value_len < settings.thread_title_length_min:
     if value_len < settings.thread_title_length_min:
+        # pylint: disable=line-too-long
         message = ngettext(
         message = ngettext(
             "Thread title should be at least %(limit_value)s character long (it has %(show_value)s).",
             "Thread title should be at least %(limit_value)s character long (it has %(show_value)s).",
             "Thread title should be at least %(limit_value)s characters long (it has %(show_value)s).",
             "Thread title should be at least %(limit_value)s characters long (it has %(show_value)s).",
@@ -56,6 +57,7 @@ def validate_thread_title_length(settings, value):
         )
         )
 
 
     if value_len > settings.thread_title_length_max:
     if value_len > settings.thread_title_length_max:
+        # pylint: disable=line-too-long
         message = ngettext(
         message = ngettext(
             "Thread title cannot be longer than %(limit_value)s character (it has %(show_value)s).",
             "Thread title cannot be longer than %(limit_value)s character (it has %(show_value)s).",
             "Thread title cannot be longer than %(limit_value)s characters (it has %(show_value)s).",
             "Thread title cannot be longer than %(limit_value)s characters (it has %(show_value)s).",
@@ -74,6 +76,7 @@ def validate_post_length(settings, value):
         raise ValidationError(_("You have to enter a message."))
         raise ValidationError(_("You have to enter a message."))
 
 
     if value_len < settings.post_length_min:
     if value_len < settings.post_length_min:
+        # pylint: disable=line-too-long
         message = ngettext(
         message = ngettext(
             "Posted message should be at least %(limit_value)s character long (it has %(show_value)s).",
             "Posted message should be at least %(limit_value)s character long (it has %(show_value)s).",
             "Posted message should be at least %(limit_value)s characters long (it has %(show_value)s).",
             "Posted message should be at least %(limit_value)s characters long (it has %(show_value)s).",
@@ -84,6 +87,7 @@ def validate_post_length(settings, value):
         )
         )
 
 
     if settings.post_length_max and value_len > settings.post_length_max:
     if settings.post_length_max and value_len > settings.post_length_max:
+        # pylint: disable=line-too-long
         message = ngettext(
         message = ngettext(
             "Posted message cannot be longer than %(limit_value)s character (it has %(show_value)s).",
             "Posted message cannot be longer than %(limit_value)s character (it has %(show_value)s).",
             "Posted message cannot be longer than %(limit_value)s characters (it has %(show_value)s).",
             "Posted message cannot be longer than %(limit_value)s characters (it has %(show_value)s).",

+ 2 - 1
misago/threads/views/admin/attachmenttypes.py

@@ -44,7 +44,8 @@ class DeleteAttachmentType(AttachmentTypeAdmin, generic.ButtonView):
     def check_permissions(self, request, target):
     def check_permissions(self, request, target):
         if target.attachment_set.exists():
         if target.attachment_set.exists():
             message = _(
             message = _(
-                'Attachment type "%(name)s" has associated attachments and can\'t be deleted.'
+                'Attachment type "%(name)s" has '
+                "associated attachments and can't be deleted."
             )
             )
             return message % {"name": target.name}
             return message % {"name": target.name}
 
 

+ 13 - 13
misago/users/forms/admin.py

@@ -215,14 +215,12 @@ class EditUserForm(UserBaseForm):
 
 
         length_limit = self.settings.signature_length_max
         length_limit = self.settings.signature_length_max
         if len(data) > length_limit:
         if len(data) > length_limit:
-            raise forms.ValidationError(
-                ngettext(
-                    "Signature can't be longer than %(limit)s character.",
-                    "Signature can't be longer than %(limit)s characters.",
-                    length_limit,
-                )
-                % {"limit": length_limit}
+            message = ngettext(
+                "Signature can't be longer than %(limit)s character.",
+                "Signature can't be longer than %(limit)s characters.",
+                length_limit,
             )
             )
+            raise forms.ValidationError(message % {"limit": length_limit})
 
 
         return data
         return data
 
 
@@ -504,9 +502,10 @@ class BanForm(forms.ModelForm):
     registration_only = YesNoSwitch(
     registration_only = YesNoSwitch(
         label=_("Restrict this ban to registrations"),
         label=_("Restrict this ban to registrations"),
         help_text=_(
         help_text=_(
-            "Changing this to yes will make this ban check be only performed on registration "
-            "step. This is good if you want to block certain registrations like ones from "
-            "recently comprimised e-mail providers, without harming existing users."
+            "Changing this to yes will make this ban check be only performed on "
+            "registration step. This is good if you want to block certain "
+            "registrations like ones from recently comprimised e-mail providers, "
+            "without harming existing users."
         ),
         ),
     )
     )
     banned_value = forms.CharField(
     banned_value = forms.CharField(
@@ -628,9 +627,10 @@ class RequestDataDownloadsForm(forms.Form):
         label=_("Usernames or emails"),
         label=_("Usernames or emails"),
         help_text=_(
         help_text=_(
             "Enter every item in new line. Duplicates will be ignored. "
             "Enter every item in new line. Duplicates will be ignored. "
-            "This field is case insensitive. Depending on site configuration and amount of data "
-            "to archive it may take up to few days for requests to complete. E-mail "
-            "will notification will be sent to every user once their download is ready."
+            "This field is case insensitive. Depending on site configuration and "
+            "amount of data to archive it may take up to few days for requests to "
+            "complete. E-mail will notification will be sent to every user once their "
+            "download is ready."
         ),
         ),
         widget=forms.Textarea,
         widget=forms.Textarea,
     )
     )

+ 2 - 2
misago/users/forms/auth.py

@@ -18,8 +18,8 @@ class MisagoAuthMixin:
             "You have to activate your account before you will be able to sign in."
             "You have to activate your account before you will be able to sign in."
         ),
         ),
         "inactive_admin": _(
         "inactive_admin": _(
-            "Your account has to be activated by site administrator before you will be able "
-            "to sign in."
+            "Your account has to be activated by site administrator "
+            "before you will be able to sign in."
         ),
         ),
     }
     }
 
 

+ 2 - 1
misago/users/management/commands/prepareuserdatadownloads.py

@@ -29,6 +29,7 @@ class Command(BaseCommand):
 
 
         cache_versions = get_cache_versions()
         cache_versions = get_cache_versions()
         dynamic_settings = DynamicSettings(cache_versions)
         dynamic_settings = DynamicSettings(cache_versions)
+        expires_in = settings.MISAGO_USER_DATA_DOWNLOADS_EXPIRE_IN_HOURS
 
 
         downloads_prepared = 0
         downloads_prepared = 0
         queryset = DataDownload.objects.select_related("user")
         queryset = DataDownload.objects.select_related("user")
@@ -45,7 +46,7 @@ class Command(BaseCommand):
                     "misago/emails/data_download",
                     "misago/emails/data_download",
                     context={
                     context={
                         "data_download": data_download,
                         "data_download": data_download,
-                        "expires_in": settings.MISAGO_USER_DATA_DOWNLOADS_EXPIRE_IN_HOURS,
+                        "expires_in": expires_in,
                         "settings": dynamic_settings,
                         "settings": dynamic_settings,
                     },
                     },
                 )
                 )

+ 5 - 5
misago/users/profilefields/default.py

@@ -48,8 +48,8 @@ class SkypeIdField(basefields.TextProfileField):
     fieldname = "skype"
     fieldname = "skype"
     label = _("Skype ID")
     label = _("Skype ID")
     help_text = _(
     help_text = _(
-        "Entering your Skype ID in this field may invite other users to contact you over "
-        "the Skype instead of via private threads."
+        "Entering your Skype ID in this field may invite other users to "
+        "contact you over the Skype instead of via private threads."
     )
     )
 
 
 
 
@@ -59,9 +59,9 @@ class TwitterHandleField(basefields.TextProfileField):
 
 
     def get_help_text(self, user):
     def get_help_text(self, user):
         return _(
         return _(
-            "If you own Twitter account, here you may enter your Twitter handle for other users "
-            'to find you. Starting your handle with "@" sign is optional. Either "@%(slug)s" or '
-            '"%(slug)s" are valid values.'
+            "If you own Twitter account, here you may enter your Twitter handle for "
+            'other users to find you. Starting your handle with "@" sign is optional. '
+            'Either "@%(slug)s" or "%(slug)s" are valid values.'
         ) % {"slug": user.slug}
         ) % {"slug": user.slug}
 
 
     def get_value_display_data(self, request, user, value):
     def get_value_display_data(self, request, user, value):

+ 5 - 7
misago/users/serializers/moderation.py

@@ -32,13 +32,11 @@ class ModerateSignatureSerializer(serializers.ModelSerializer):
     def validate_signature(self, value):
     def validate_signature(self, value):
         length_limit = settings.signature_length_max
         length_limit = settings.signature_length_max
         if len(value) > length_limit:
         if len(value) > length_limit:
-            raise serializers.ValidationError(
-                ngettext(
-                    "Signature can't be longer than %(limit)s character.",
-                    "Signature can't be longer than %(limit)s characters.",
-                    length_limit,
-                )
-                % {"limit": length_limit}
+            message = ngettext(
+                "Signature can't be longer than %(limit)s character.",
+                "Signature can't be longer than %(limit)s characters.",
+                length_limit,
             )
             )
+            raise serializers.ValidationError(message % {"limit": length_limit})
 
 
         return value
         return value

+ 2 - 2
misago/users/serializers/options.py

@@ -118,8 +118,8 @@ class DeleteOwnAccountSerializer(serializers.Serializer):
 
 
     def mark_account_for_deletion(self, request):
     def mark_account_for_deletion(self, request):
         """
         """
-        Deleting user account can be costful, so just mark account for deletion, deactivate it
-        and sign user out.
+        Deleting user account can be costful, so just mark account for deletion,
+        deactivate it and sign user out.
         """
         """
         profile = self.context["user"]
         profile = self.context["user"]
         allow_delete_own_account(request.user, profile)
         allow_delete_own_account(request.user, profile)

+ 2 - 1
misago/users/social/backendsnames.py

@@ -1,6 +1,7 @@
 """
 """
 Python Social Auth doesn't provide information about proper names for OAuth sites,
 Python Social Auth doesn't provide information about proper names for OAuth sites,
-so we are using this file for overrides whenever name is different than `provider.name.title`
+so we are using this file to define those for displaying the UI.
+If provider is not defined here, it's name is created with `provider.name.title()`
 """
 """
 
 
 BACKENDS_NAMES = {
 BACKENDS_NAMES = {

+ 8 - 4
misago/users/social/pipeline.py

@@ -31,7 +31,9 @@ User = get_user_model()
 
 
 
 
 def validate_ip_not_banned(strategy, details, backend, user=None, *args, **kwargs):
 def validate_ip_not_banned(strategy, details, backend, user=None, *args, **kwargs):
-    """Pipeline step that interrupts pipeline if found user is non-staff and IP banned"""
+    """
+    Pipeline step that interrupts pipeline if found user is non-staff and IP banned
+    """
     if not user or user.is_staff:
     if not user or user.is_staff:
         return None
         return None
 
 
@@ -85,8 +87,8 @@ def associate_by_email(strategy, details, backend, user=None, *args, **kwargs):
         raise SocialAuthFailed(
         raise SocialAuthFailed(
             backend,
             backend,
             _(
             _(
-                "Your account has to be activated by site administrator before you will be able to "
-                "sign in with %(backend)s."
+                "Your account has to be activated by site administrator "
+                "before you will be able to sign in with %(backend)s."
             )
             )
             % {"backend": backend_name},
             % {"backend": backend_name},
         )
         )
@@ -169,7 +171,9 @@ def create_user(strategy, details, backend, user=None, *args, **kwargs):
 
 
 @partial
 @partial
 def create_user_with_form(strategy, details, backend, user=None, *args, **kwargs):
 def create_user_with_form(strategy, details, backend, user=None, *args, **kwargs):
-    """Alternatively to create_user lets user confirm account creation before authenticating"""
+    """
+    create_user lets user confirm account creation by entering final username or email
+    """
     if user:
     if user:
         return None
         return None
 
 

+ 3 - 1
misago/users/tests/test_auth_api.py

@@ -581,6 +581,8 @@ class ChangePasswordApiTests(TestCase):
         self.assertEqual(
         self.assertEqual(
             response.json(),
             response.json(),
             {
             {
-                "detail": "This password is too short. It must contain at least 7 characters."
+                "detail": (
+                    "This password is too short. It must contain at least 7 characters."
+                )
             },
             },
         )
         )

+ 4 - 1
misago/users/tests/test_bio_profilefield.py

@@ -140,7 +140,10 @@ class BioProfileFieldTests(AdminTestCase):
                         {
                         {
                             "fieldname": "bio",
                             "fieldname": "bio",
                             "name": "Bio",
                             "name": "Bio",
-                            "html": "<p>I am Bob!</p>\n\n<p>This is &lt;b&gt;my&lt;/b&gt; bio!</p>",
+                            "html": (
+                                "<p>I am Bob!</p>\n\n"
+                                "<p>This is &lt;b&gt;my&lt;/b&gt; bio!</p>"
+                            ),
                         }
                         }
                     ],
                     ],
                 },
                 },

+ 13 - 4
misago/users/tests/test_datadownloads.py

@@ -176,7 +176,9 @@ class PrepareUserDataDownload(AuthenticatedUserTestCase):
         self.assert_download_is_valid()
         self.assert_download_is_valid()
 
 
     def test_prepare_download_with_username_changed_by_deleted_user(self):
     def test_prepare_download_with_username_changed_by_deleted_user(self):
-        """function creates data download for user with username changed by deleted user"""
+        """
+        function creates data download for user with username changed by deleted user
+        """
         self.user.record_name_change(self.user, "aerith", "alice")
         self.user.record_name_change(self.user, "aerith", "alice")
         self.user.namechanges.update(changed_by=None)
         self.user.namechanges.update(changed_by=None)
 
 
@@ -271,7 +273,10 @@ class RequestUserDataDownloadTests(AuthenticatedUserTestCase):
         self.assertEqual(data_download.status, DataDownload.STATUS_PENDING)
         self.assertEqual(data_download.status, DataDownload.STATUS_PENDING)
 
 
     def test_util_creates_data_download_for_user_explicit_requester(self):
     def test_util_creates_data_download_for_user_explicit_requester(self):
-        """request_user_data_download created valid data download for user with other requester"""
+        """
+        request_user_data_download created valid data download
+        for user with other requester
+        """
         requester = self.get_superuser()
         requester = self.get_superuser()
         data_download = request_user_data_download(self.user, requester)
         data_download = request_user_data_download(self.user, requester)
 
 
@@ -283,7 +288,9 @@ class RequestUserDataDownloadTests(AuthenticatedUserTestCase):
 
 
 class UserHasRequestedDataDownloadTests(AuthenticatedUserTestCase):
 class UserHasRequestedDataDownloadTests(AuthenticatedUserTestCase):
     def test_util_returns_false_for_no_download(self):
     def test_util_returns_false_for_no_download(self):
-        """user_has_data_download_request returns false if user has no requests in progress"""
+        """
+        user_has_data_download_request returns false if user has no requests in progress
+        """
         self.assertFalse(user_has_data_download_request(self.user))
         self.assertFalse(user_has_data_download_request(self.user))
 
 
     def test_util_returns_false_for_ready_download(self):
     def test_util_returns_false_for_ready_download(self):
@@ -311,7 +318,9 @@ class UserHasRequestedDataDownloadTests(AuthenticatedUserTestCase):
         self.assertTrue(user_has_data_download_request(self.user))
         self.assertTrue(user_has_data_download_request(self.user))
 
 
     def test_util_returns_true_for_processing_download(self):
     def test_util_returns_true_for_processing_download(self):
-        """user_has_data_download_request returns true if user has processing download"""
+        """
+        user_has_data_download_request returns true if user has processing download
+        """
         data_download = request_user_data_download(self.user)
         data_download = request_user_data_download(self.user)
         data_download.status = DataDownload.STATUS_PROCESSING
         data_download.status = DataDownload.STATUS_PROCESSING
         data_download.save()
         data_download.save()

+ 3 - 1
misago/users/tests/test_forgottenpassword_views.py

@@ -20,7 +20,9 @@ class ForgottenPasswordViewsTests(UserTestCase):
         self.assertEqual(response.status_code, 200)
         self.assertEqual(response.status_code, 200)
 
 
     def test_authenticated_request_unusable_password_view_returns_200(self):
     def test_authenticated_request_unusable_password_view_returns_200(self):
-        """request new password view returns 200 for authenticated with unusable password"""
+        """
+        request new password view returns 200 for authenticated with unusable password
+        """
         user = self.get_authenticated_user()
         user = self.get_authenticated_user()
         user.set_password(None)
         user.set_password(None)
         user.save()
         user.save()

+ 1 - 0
misago/users/tests/test_profilefields.py

@@ -89,6 +89,7 @@ class ProfileFieldsLoadTests(TestCase):
                 {
                 {
                     "name": "Other test",
                     "name": "Other test",
                     "fields": [
                     "fields": [
+                        # pylint: disable=line-too-long
                         "misago.users.tests.testfiles.profilefields.RepeatedFieldnameField"
                         "misago.users.tests.testfiles.profilefields.RepeatedFieldnameField"
                     ],
                     ],
                 },
                 },

+ 4 - 4
misago/users/tests/test_social_pipeline.py

@@ -122,8 +122,8 @@ class AssociateByEmailTests(PipelineTestCase):
             self.assertEqual(
             self.assertEqual(
                 e.message,
                 e.message,
                 (
                 (
-                    "The e-mail address associated with your GitHub account is not available for "
-                    "use on this site."
+                    "The e-mail address associated with your GitHub account "
+                    "is not available for use on this site."
                 ),
                 ),
             )
             )
 
 
@@ -139,8 +139,8 @@ class AssociateByEmailTests(PipelineTestCase):
             self.assertEqual(
             self.assertEqual(
                 e.message,
                 e.message,
                 (
                 (
-                    "Your account has to be activated by site administrator before you will be "
-                    "able to sign in with GitHub."
+                    "Your account has to be activated by site administrator "
+                    "before you will be able to sign in with GitHub."
                 ),
                 ),
             )
             )
 
 

+ 3 - 2
misago/users/tests/test_twitter_profilefield.py

@@ -196,8 +196,9 @@ class TwitterProfileFieldTests(AdminTestCase):
                 "fieldname": "twitter",
                 "fieldname": "twitter",
                 "label": "Twitter handle",
                 "label": "Twitter handle",
                 "help_text": (
                 "help_text": (
-                    "If you own Twitter account, here you may enter your Twitter handle for other users to find you. "
-                    'Starting your handle with "@" sign is optional. Either "@testsuperuser" or "testsuperuser" are '
+                    "If you own Twitter account, here you may enter your Twitter "
+                    'handle for other users to find you. Starting your handle with "@" '
+                    'sign is optional. Either "@testsuperuser" or "testsuperuser" are '
                     "valid values."
                     "valid values."
                 ),
                 ),
                 "input": {"type": "text"},
                 "input": {"type": "text"},

+ 4 - 1
misago/users/tests/test_user_create_api.py

@@ -261,7 +261,10 @@ class UserCreateTests(UserTestCase):
             {
             {
                 "email": ["This email is not allowed."],
                 "email": ["This email is not allowed."],
                 "password": [
                 "password": [
-                    "This password is too short. It must contain at least 7 characters.",
+                    (
+                        "This password is too short. "
+                        "It must contain at least 7 characters."
+                    ),
                     "This password is entirely numeric.",
                     "This password is entirely numeric.",
                 ],
                 ],
             },
             },

+ 3 - 1
misago/users/tests/test_user_requestdatadownload_api.py

@@ -47,7 +47,9 @@ class UserRequestDataDownload(AuthenticatedUserTestCase):
         self.assertEqual(
         self.assertEqual(
             response.json(),
             response.json(),
             {
             {
-                "detail": "You can't have more than one data download request at single time."
+                "detail": (
+                    "You can't have more than one data download request at single time."
+                )
             },
             },
         )
         )
 
 

+ 3 - 1
misago/users/tests/test_useradmin_views.py

@@ -898,7 +898,9 @@ class UserAdminViewsTests(AdminTestCase):
         self.assertTrue(updated_user.has_usable_password())
         self.assertTrue(updated_user.has_usable_password())
 
 
     def test_edit_keep_unusable_password(self):
     def test_edit_keep_unusable_password(self):
-        """admin edit form handles unusable passwords and lets admin leave them unchanged"""
+        """
+        admin edit form handles unusable passwords and lets admin leave them unchanged
+        """
         test_user = create_test_user("User", "user@example.com")
         test_user = create_test_user("User", "user@example.com")
         self.assertFalse(test_user.has_usable_password())
         self.assertFalse(test_user.has_usable_password())
 
 

+ 16 - 5
misago/users/tests/test_users_api.py

@@ -454,7 +454,10 @@ class UserBanTests(AuthenticatedUserTestCase):
 
 
 
 
 class UserDeleteOwnAccountTests(AuthenticatedUserTestCase):
 class UserDeleteOwnAccountTests(AuthenticatedUserTestCase):
-    """tests for user request own account delete RPC (POST to /api/users/1/delete-own-account/)"""
+    """
+    tests for user request own account delete RPC
+    (POST to /api/users/1/delete-own-account/)
+    """
 
 
     def setUp(self):
     def setUp(self):
         super().setUp()
         super().setUp()
@@ -462,7 +465,9 @@ class UserDeleteOwnAccountTests(AuthenticatedUserTestCase):
 
 
     @override_settings(MISAGO_ENABLE_DELETE_OWN_ACCOUNT=False)
     @override_settings(MISAGO_ENABLE_DELETE_OWN_ACCOUNT=False)
     def test_delete_own_account_feature_disabled(self):
     def test_delete_own_account_feature_disabled(self):
-        """raises 403 error when attempting to delete own account but feature is disabled"""
+        """
+        raises 403 error when attempting to delete own account but feature is disabled
+        """
         response = self.client.post(self.api_link, {"password": self.USER_PASSWORD})
         response = self.client.post(self.api_link, {"password": self.USER_PASSWORD})
 
 
         self.assertEqual(response.status_code, 403)
         self.assertEqual(response.status_code, 403)
@@ -482,7 +487,9 @@ class UserDeleteOwnAccountTests(AuthenticatedUserTestCase):
         self.assertEqual(
         self.assertEqual(
             response.json(),
             response.json(),
             {
             {
-                "detail": "You can't delete your account because you are an administrator."
+                "detail": (
+                    "You can't delete your account because you are an administrator."
+                )
             },
             },
         )
         )
 
 
@@ -500,7 +507,9 @@ class UserDeleteOwnAccountTests(AuthenticatedUserTestCase):
         self.assertEqual(
         self.assertEqual(
             response.json(),
             response.json(),
             {
             {
-                "detail": "You can't delete your account because you are an administrator."
+                "detail": (
+                    "You can't delete your account because you are an administrator."
+                )
             },
             },
         )
         )
 
 
@@ -509,7 +518,9 @@ class UserDeleteOwnAccountTests(AuthenticatedUserTestCase):
         self.assertFalse(self.user.is_deleting_account)
         self.assertFalse(self.user.is_deleting_account)
 
 
     def test_delete_own_account_invalid_password(self):
     def test_delete_own_account_invalid_password(self):
-        """raises 400 error when attempting to delete own account with invalid password"""
+        """
+        raises 400 error when attempting to delete own account with invalid password
+        """
         response = self.client.post(self.api_link, {"password": "hello"})
         response = self.client.post(self.api_link, {"password": "hello"})
         self.assertEqual(response.status_code, 400)
         self.assertEqual(response.status_code, 400)
         self.assertEqual(
         self.assertEqual(

+ 2 - 1
misago/users/views/forgottenpassword.py

@@ -36,7 +36,8 @@ def reset_password_form(request, pk, token):
     try:
     try:
         if request.user.is_authenticated and request.user.id != requesting_user.id:
         if request.user.is_authenticated and request.user.id != requesting_user.id:
             message = _(
             message = _(
-                "%(user)s, your link has expired. Please request new link and try again."
+                "%(user)s, your link has expired. "
+                "Please request new link and try again."
             )
             )
             raise ResetError(message % {"user": requesting_user.username})
             raise ResetError(message % {"user": requesting_user.username})