Chore: Adds additional rules for Ruff linter (#5660)

This commit is contained in:
Trenton H 2024-02-05 13:46:59 -08:00 committed by GitHub
parent fb82aa0ee1
commit 4813a7bc70
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 117 additions and 99 deletions

View File

@ -1,7 +1,29 @@
# https://beta.ruff.rs/docs/settings/ # https://docs.astral.sh/ruff/settings/
# https://beta.ruff.rs/docs/rules/ # https://docs.astral.sh/ruff/rules/
extend-select = ["I", "W", "UP", "COM", "DJ", "EXE", "ISC", "ICN", "G201", "INP", "PIE", "RSE", "SIM", "TID", "PLC", "PLE", "RUF"] extend-select = [
# TODO PTH "W", # https://docs.astral.sh/ruff/rules/#pycodestyle-e-w
"I", # https://docs.astral.sh/ruff/rules/#isort-i
"UP", # https://docs.astral.sh/ruff/rules/#pyupgrade-up
"COM", # https://docs.astral.sh/ruff/rules/#flake8-commas-com
"DJ", # https://docs.astral.sh/ruff/rules/#flake8-django-dj
"EXE", # https://docs.astral.sh/ruff/rules/#flake8-executable-exe
"ISC", # https://docs.astral.sh/ruff/rules/#flake8-implicit-str-concat-isc
"ICN", # https://docs.astral.sh/ruff/rules/#flake8-import-conventions-icn
"G201", # https://docs.astral.sh/ruff/rules/#flake8-logging-format-g
"INP", # https://docs.astral.sh/ruff/rules/#flake8-no-pep420-inp
"PIE", # https://docs.astral.sh/ruff/rules/#flake8-pie-pie
"Q", # https://docs.astral.sh/ruff/rules/#flake8-quotes-q
"RSE", # https://docs.astral.sh/ruff/rules/#flake8-raise-rse
"T20", # https://docs.astral.sh/ruff/rules/#flake8-print-t20
"SIM", # https://docs.astral.sh/ruff/rules/#flake8-simplify-sim
"TID", # https://docs.astral.sh/ruff/rules/#flake8-tidy-imports-tid
"TCH", # https://docs.astral.sh/ruff/rules/#flake8-type-checking-tch
"PLC", # https://docs.astral.sh/ruff/rules/#pylint-pl
"PLE", # https://docs.astral.sh/ruff/rules/#pylint-pl
"RUF", # https://docs.astral.sh/ruff/rules/#ruff-specific-rules-ruf
"FLY", # https://docs.astral.sh/ruff/rules/#flynt-fly
]
# TODO PTH https://docs.astral.sh/ruff/rules/#flake8-use-pathlib-pth
ignore = ["DJ001", "SIM105", "RUF012"] ignore = ["DJ001", "SIM105", "RUF012"]
fix = true fix = true
line-length = 88 line-length = 88
@ -13,9 +35,9 @@ show-fixes = true
[per-file-ignores] [per-file-ignores]
".github/scripts/*.py" = ["E501", "INP001", "SIM117"] ".github/scripts/*.py" = ["E501", "INP001", "SIM117"]
"docker/wait-for-redis.py" = ["INP001"] "docker/wait-for-redis.py" = ["INP001", "T201"]
"*/tests/*.py" = ["E501", "SIM117"] "*/tests/*.py" = ["E501", "SIM117"]
"*/migrations/*.py" = ["E501", "SIM"] "*/migrations/*.py" = ["E501", "SIM", "T201"]
"src/paperless_tesseract/tests/test_parser.py" = ["RUF001"] "src/paperless_tesseract/tests/test_parser.py" = ["RUF001"]
"src/documents/models.py" = ["SIM115"] "src/documents/models.py" = ["SIM115"]

View File

@ -90,7 +90,6 @@ def set_suggestions_cache(
""" """
if classifier is not None: if classifier is not None:
doc_key = get_suggestion_cache_key(document_id) doc_key = get_suggestion_cache_key(document_id)
print(classifier.last_auto_type_hash)
cache.set( cache.set(
doc_key, doc_key,
SuggestionCacheData( SuggestionCacheData(

View File

@ -4,11 +4,14 @@ import pickle
import re import re
import warnings import warnings
from collections.abc import Iterator from collections.abc import Iterator
from datetime import datetime
from hashlib import sha256 from hashlib import sha256
from pathlib import Path from typing import TYPE_CHECKING
from typing import Optional from typing import Optional
if TYPE_CHECKING:
from datetime import datetime
from pathlib import Path
from django.conf import settings from django.conf import settings
from django.core.cache import cache from django.core.cache import cache
from sklearn.exceptions import InconsistentVersionWarning from sklearn.exceptions import InconsistentVersionWarning

View File

@ -69,8 +69,6 @@ class Command(ProgressBarMixin, BaseCommand):
def handle(self, *args, **options): def handle(self, *args, **options):
self.handle_progress_bar_mixin(**options) self.handle_progress_bar_mixin(**options)
# Detect if we support color
color = self.style.ERROR("test") != "test"
if options["inbox_only"]: if options["inbox_only"]:
queryset = Document.objects.filter(tags__is_inbox_tag=True) queryset = Document.objects.filter(tags__is_inbox_tag=True)
@ -96,7 +94,8 @@ class Command(ProgressBarMixin, BaseCommand):
use_first=options["use_first"], use_first=options["use_first"],
suggest=options["suggest"], suggest=options["suggest"],
base_url=options["base_url"], base_url=options["base_url"],
color=color, stdout=self.stdout,
style_func=self.style,
) )
if options["document_type"]: if options["document_type"]:
@ -108,7 +107,8 @@ class Command(ProgressBarMixin, BaseCommand):
use_first=options["use_first"], use_first=options["use_first"],
suggest=options["suggest"], suggest=options["suggest"],
base_url=options["base_url"], base_url=options["base_url"],
color=color, stdout=self.stdout,
style_func=self.style,
) )
if options["tags"]: if options["tags"]:
@ -119,7 +119,8 @@ class Command(ProgressBarMixin, BaseCommand):
replace=options["overwrite"], replace=options["overwrite"],
suggest=options["suggest"], suggest=options["suggest"],
base_url=options["base_url"], base_url=options["base_url"],
color=color, stdout=self.stdout,
style_func=self.style,
) )
if options["storage_path"]: if options["storage_path"]:
set_storage_path( set_storage_path(
@ -130,5 +131,6 @@ class Command(ProgressBarMixin, BaseCommand):
use_first=options["use_first"], use_first=options["use_first"],
suggest=options["suggest"], suggest=options["suggest"],
base_url=options["base_url"], base_url=options["base_url"],
color=color, stdout=self.stdout,
style_func=self.style,
) )

View File

@ -19,7 +19,7 @@ def _process_document(doc_id):
if parser_class: if parser_class:
parser = parser_class(logging_group=None) parser = parser_class(logging_group=None)
else: else:
print(f"{document} No parser for mime type {document.mime_type}") print(f"{document} No parser for mime type {document.mime_type}") # noqa: T201
return return
try: try:

View File

@ -5,7 +5,9 @@ from typing import Union
from asgiref.sync import async_to_sync from asgiref.sync import async_to_sync
from channels.layers import get_channel_layer from channels.layers import get_channel_layer
from channels_redis.pubsub import RedisPubSubChannelLayer
if TYPE_CHECKING:
from channels_redis.pubsub import RedisPubSubChannelLayer
class ProgressStatusOptions(str, enum.Enum): class ProgressStatusOptions(str, enum.Enum):

View File

@ -18,7 +18,6 @@ from django.db import close_old_connections
from django.db import models from django.db import models
from django.db.models import Q from django.db.models import Q
from django.dispatch import receiver from django.dispatch import receiver
from django.utils import termcolors
from django.utils import timezone from django.utils import timezone
from filelock import FileLock from filelock import FileLock
@ -54,6 +53,26 @@ def add_inbox_tags(sender, document: Document, logging_group=None, **kwargs):
document.tags.add(*inbox_tags) document.tags.add(*inbox_tags)
def _suggestion_printer(
stdout,
style_func,
suggestion_type: str,
document: Document,
selected: MatchingModel,
base_url: Optional[str] = None,
):
"""
Smaller helper to reduce duplication when just outputting suggestions to the console
"""
doc_str = str(document)
if base_url is not None:
stdout.write(style_func.SUCCESS(doc_str))
stdout.write(style_func.SUCCESS(f"{base_url}/documents/{document.pk}"))
else:
stdout.write(style_func.SUCCESS(f"{doc_str} [{document.pk}]"))
stdout.write(f"Suggest {suggestion_type}: {selected}")
def set_correspondent( def set_correspondent(
sender, sender,
document: Document, document: Document,
@ -63,7 +82,8 @@ def set_correspondent(
use_first=True, use_first=True,
suggest=False, suggest=False,
base_url=None, base_url=None,
color=False, stdout=None,
style_func=None,
**kwargs, **kwargs,
): ):
if document.correspondent and not replace: if document.correspondent and not replace:
@ -90,23 +110,14 @@ def set_correspondent(
if selected or replace: if selected or replace:
if suggest: if suggest:
if base_url: _suggestion_printer(
print( stdout,
termcolors.colorize(str(document), fg="green") style_func,
if color "correspondent",
else str(document), document,
) selected,
print(f"{base_url}/documents/{document.pk}") base_url,
else: )
print(
(
termcolors.colorize(str(document), fg="green")
if color
else str(document)
)
+ f" [{document.pk}]",
)
print(f"Suggest correspondent {selected}")
else: else:
logger.info( logger.info(
f"Assigning correspondent {selected} to {document}", f"Assigning correspondent {selected} to {document}",
@ -126,7 +137,8 @@ def set_document_type(
use_first=True, use_first=True,
suggest=False, suggest=False,
base_url=None, base_url=None,
color=False, stdout=None,
style_func=None,
**kwargs, **kwargs,
): ):
if document.document_type and not replace: if document.document_type and not replace:
@ -154,23 +166,14 @@ def set_document_type(
if selected or replace: if selected or replace:
if suggest: if suggest:
if base_url: _suggestion_printer(
print( stdout,
termcolors.colorize(str(document), fg="green") style_func,
if color "document type",
else str(document), document,
) selected,
print(f"{base_url}/documents/{document.pk}") base_url,
else: )
print(
(
termcolors.colorize(str(document), fg="green")
if color
else str(document)
)
+ f" [{document.pk}]",
)
print(f"Suggest document type {selected}")
else: else:
logger.info( logger.info(
f"Assigning document type {selected} to {document}", f"Assigning document type {selected} to {document}",
@ -189,7 +192,8 @@ def set_tags(
replace=False, replace=False,
suggest=False, suggest=False,
base_url=None, base_url=None,
color=False, stdout=None,
style_func=None,
**kwargs, **kwargs,
): ):
if replace: if replace:
@ -212,26 +216,16 @@ def set_tags(
] ]
if not relevant_tags and not extra_tags: if not relevant_tags and not extra_tags:
return return
doc_str = style_func.SUCCESS(str(document))
if base_url: if base_url:
print( stdout.write(doc_str)
termcolors.colorize(str(document), fg="green") stdout.write(f"{base_url}/documents/{document.pk}")
if color
else str(document),
)
print(f"{base_url}/documents/{document.pk}")
else: else:
print( stdout.write(doc_str + style_func.SUCCESS(f" [{document.pk}]"))
(
termcolors.colorize(str(document), fg="green")
if color
else str(document)
)
+ f" [{document.pk}]",
)
if relevant_tags: if relevant_tags:
print("Suggest tags: " + ", ".join([t.name for t in relevant_tags])) stdout.write("Suggest tags: " + ", ".join([t.name for t in relevant_tags]))
if extra_tags: if extra_tags:
print("Extra tags: " + ", ".join([t.name for t in extra_tags])) stdout.write("Extra tags: " + ", ".join([t.name for t in extra_tags]))
else: else:
if not relevant_tags: if not relevant_tags:
return return
@ -254,7 +248,8 @@ def set_storage_path(
use_first=True, use_first=True,
suggest=False, suggest=False,
base_url=None, base_url=None,
color=False, stdout=None,
style_func=None,
**kwargs, **kwargs,
): ):
if document.storage_path and not replace: if document.storage_path and not replace:
@ -285,23 +280,14 @@ def set_storage_path(
if selected or replace: if selected or replace:
if suggest: if suggest:
if base_url: _suggestion_printer(
print( stdout,
termcolors.colorize(str(document), fg="green") style_func,
if color "storage directory",
else str(document), document,
) selected,
print(f"{base_url}/documents/{document.pk}") base_url,
else: )
print(
(
termcolors.colorize(str(document), fg="green")
if color
else str(document)
)
+ f" [{document.pk}]",
)
print(f"Suggest storage directory {selected}")
else: else:
logger.info( logger.info(
f"Assigning storage path {selected} to {document}", f"Assigning storage path {selected} to {document}",

View File

@ -246,8 +246,6 @@ class TestBulkDownload(DirectoriesMixin, APITestCase):
self.doc3.title = "Title 2 - Doc 3" self.doc3.title = "Title 2 - Doc 3"
self.doc3.save() self.doc3.save()
print(self.doc3.archive_path)
print(self.doc3.archive_filename)
response = self.client.post( response = self.client.post(
self.ENDPOINT, self.ENDPOINT,

View File

@ -88,10 +88,10 @@ class ConsumerThreadMixin(DocumentConsumeDelayMixin):
): ):
eq = filecmp.cmp(input_doc.original_file, self.sample_file, shallow=False) eq = filecmp.cmp(input_doc.original_file, self.sample_file, shallow=False)
if not eq: if not eq:
print("Consumed an INVALID file.") print("Consumed an INVALID file.") # noqa: T201
raise ConsumerError("Incomplete File READ FAILED") raise ConsumerError("Incomplete File READ FAILED")
else: else:
print("Consumed a perfectly valid file.") print("Consumed a perfectly valid file.") # noqa: T201
def slow_write_file(self, target, incomplete=False): def slow_write_file(self, target, incomplete=False):
with open(self.sample_file, "rb") as f: with open(self.sample_file, "rb") as f:
@ -102,11 +102,11 @@ class ConsumerThreadMixin(DocumentConsumeDelayMixin):
with open(target, "wb") as f: with open(target, "wb") as f:
# this will take 2 seconds, since the file is about 20k. # this will take 2 seconds, since the file is about 20k.
print("Start writing file.") print("Start writing file.") # noqa: T201
for b in chunked(1000, pdf_bytes): for b in chunked(1000, pdf_bytes):
f.write(b) f.write(b)
sleep(0.1) sleep(0.1)
print("file completed.") print("file completed.") # noqa: T201
@override_settings( @override_settings(

View File

@ -196,7 +196,7 @@ class TestFuzzyMatchCommand(TestCase):
self.assertEqual(Document.objects.count(), 3) self.assertEqual(Document.objects.count(), 3)
stdout, _ = self.call_command("--delete") stdout, _ = self.call_command("--delete")
print(stdout)
lines = [x.strip() for x in stdout.split("\n") if len(x.strip())] lines = [x.strip() for x in stdout.split("\n") if len(x.strip())]
self.assertEqual(len(lines), 3) self.assertEqual(len(lines), 3)
self.assertEqual( self.assertEqual(

View File

@ -1,16 +1,19 @@
from datetime import timedelta from datetime import timedelta
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING
from unittest import mock from unittest import mock
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.db.models import QuerySet
from django.utils import timezone from django.utils import timezone
from guardian.shortcuts import assign_perm from guardian.shortcuts import assign_perm
from guardian.shortcuts import get_groups_with_perms from guardian.shortcuts import get_groups_with_perms
from guardian.shortcuts import get_users_with_perms from guardian.shortcuts import get_users_with_perms
from rest_framework.test import APITestCase from rest_framework.test import APITestCase
if TYPE_CHECKING:
from django.db.models import QuerySet
from documents import tasks from documents import tasks
from documents.data_models import ConsumableDocument from documents.data_models import ConsumableDocument
from documents.data_models import DocumentSource from documents.data_models import DocumentSource

View File

@ -340,7 +340,6 @@ class DummyProgressManager:
def __init__(self, filename: str, task_id: Optional[str] = None) -> None: def __init__(self, filename: str, task_id: Optional[str] = None) -> None:
self.filename = filename self.filename = filename
self.task_id = task_id self.task_id = task_id
print("hello world")
self.payloads = [] self.payloads = []
def __enter__(self): def __enter__(self):

View File

@ -1,3 +1,5 @@
import logging
from django.conf import settings from django.conf import settings
from django.contrib import auth from django.contrib import auth
from django.contrib.auth.middleware import PersistentRemoteUserMiddleware from django.contrib.auth.middleware import PersistentRemoteUserMiddleware
@ -6,6 +8,8 @@ from django.http import HttpRequest
from django.utils.deprecation import MiddlewareMixin from django.utils.deprecation import MiddlewareMixin
from rest_framework import authentication from rest_framework import authentication
logger = logging.getLogger("paperless.auth")
class AutoLoginMiddleware(MiddlewareMixin): class AutoLoginMiddleware(MiddlewareMixin):
def process_request(self, request: HttpRequest): def process_request(self, request: HttpRequest):
@ -35,7 +39,7 @@ class AngularApiAuthenticationOverride(authentication.BaseAuthentication):
and request.headers["Referer"].startswith("http://localhost:4200/") and request.headers["Referer"].startswith("http://localhost:4200/")
): ):
user = User.objects.filter(is_staff=True).first() user = User.objects.filter(is_staff=True).first()
print(f"Auto-Login with user {user}") logger.debug(f"Auto-Login with user {user}")
return (user, None) return (user, None)
else: else:
return None return None