mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-09-01 23:47:15 +00:00
Chore: enable flake8-datetimez (DTZ) ruff rules
Full category (10/10 codes are all default in ruff 0.16). Of 54 hits, 46 were in test fixture code constructing naive datetimes for comparison/input purposes only - added DTZ to the existing per-file-ignores for */tests/*.py alongside E501/SIM117. The 8 production hits: - documents/consumer.py, documents/views.py (index_last_modified): suppressed with noqa - timezone.make_aware() requires a naive datetime, so wrapping fromtimestamp() in tz= would break it - documents/double_sided.py (x2): switched to datetime.now(tz=UTC).timestamp() - behavior-identical since .timestamp() returns the same epoch value regardless of the attached tz, but now explicit - documents/views.py (x2, upload temp file mtime): suppressed with noqa - mktime() requires a local time tuple, so an aware/UTC now() would introduce a timezone-offset bug - documents/workflows/ai.py (AI suggested date parsing): suppressed with noqa - only .date() is used, time/tz is discarded - paperless_mail/mail.py (IMAP fetch date filter): switched date.today() to timezone.localdate(), which respects settings.TIME_ZONE instead of the system clock - a real correctness improvement when they differ - paperless_mail/views.py (placeholder name string): switched datetime.datetime.now() to timezone.now(), matching the app's existing aware-datetime convention
This commit is contained in:
@@ -220,6 +220,7 @@ extend-select = [
|
||||
"COM", # https://docs.astral.sh/ruff/rules/#flake8-commas-com
|
||||
"D419", # https://docs.astral.sh/ruff/rules/#pydocstyle-d
|
||||
"DJ", # https://docs.astral.sh/ruff/rules/#flake8-django-dj
|
||||
"DTZ", # https://docs.astral.sh/ruff/rules/#flake8-datetimez-dtz
|
||||
"EXE", # https://docs.astral.sh/ruff/rules/#flake8-executable-exe
|
||||
"FA", # https://docs.astral.sh/ruff/rules/#flake8-future-annotations-fa
|
||||
"FBT", # https://docs.astral.sh/ruff/rules/#flake8-boolean-trap-fbt
|
||||
@@ -304,6 +305,7 @@ per-file-ignores."*/migrations/*.py" = [
|
||||
]
|
||||
# Testing
|
||||
per-file-ignores."*/tests/*.py" = [
|
||||
"DTZ",
|
||||
"E501",
|
||||
"SIM117",
|
||||
]
|
||||
|
||||
@@ -856,7 +856,7 @@ class ConsumerPlugin(
|
||||
else:
|
||||
stats = Path(self.input_doc.original_file).stat()
|
||||
create_date = timezone.make_aware(
|
||||
datetime.datetime.fromtimestamp(stats.st_mtime),
|
||||
datetime.datetime.fromtimestamp(stats.st_mtime), # noqa: DTZ006 - make_aware() requires a naive datetime
|
||||
)
|
||||
self.log.debug(f"Creation date from st_mtime: {create_date}")
|
||||
|
||||
|
||||
@@ -78,7 +78,9 @@ class CollatePlugin(NoCleanupPluginMixin, NoSetupPluginMixin, ConsumeTaskPlugin)
|
||||
stats = staging.stat()
|
||||
# if the file is older than the timeout, we don't consider
|
||||
# it valid
|
||||
if (dt.datetime.now().timestamp() - stats.st_mtime) > TIMEOUT_SECONDS:
|
||||
if (
|
||||
dt.datetime.now(tz=dt.UTC).timestamp() - stats.st_mtime
|
||||
) > TIMEOUT_SECONDS:
|
||||
logger.warning("Outdated double sided staging file exists, deleting it")
|
||||
staging.unlink()
|
||||
else:
|
||||
@@ -134,7 +136,7 @@ class CollatePlugin(NoCleanupPluginMixin, NoSetupPluginMixin, ConsumeTaskPlugin)
|
||||
shutil.move(pdf_file, staging)
|
||||
# update access to modification time so we know if the file
|
||||
# is outdated when another file gets uploaded
|
||||
timestamp = dt.datetime.now().timestamp()
|
||||
timestamp = dt.datetime.now(tz=dt.UTC).timestamp()
|
||||
os.utime(staging, (timestamp, timestamp))
|
||||
logger.info(
|
||||
"Got scan with odd numbered pages of double-sided scan, moved it to %s",
|
||||
|
||||
@@ -2062,7 +2062,7 @@ class DocumentViewSet(
|
||||
doc_name, doc_data = serializer.validated_data.get("document")
|
||||
version_label = serializer.validated_data.get("version_label")
|
||||
|
||||
t = int(mktime(datetime.now().timetuple()))
|
||||
t = int(mktime(datetime.now().timetuple())) # noqa: DTZ005 - mktime() requires a local time tuple
|
||||
|
||||
settings.SCRATCH_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
@@ -3332,7 +3332,7 @@ class PostDocumentView(GenericAPIView[Any]):
|
||||
cf = serializer.validated_data.get("custom_fields")
|
||||
from_webui = serializer.validated_data.get("from_webui")
|
||||
|
||||
t = int(mktime(datetime.now().timetuple()))
|
||||
t = int(mktime(datetime.now().timetuple())) # noqa: DTZ005 - mktime() requires a local time tuple
|
||||
|
||||
settings.SCRATCH_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
@@ -5251,7 +5251,9 @@ class SystemStatusView(PassUserMixin):
|
||||
index_dir = settings.INDEX_DIR
|
||||
mtimes = [p.stat().st_mtime for p in index_dir.iterdir() if p.is_file()]
|
||||
index_last_modified = (
|
||||
make_aware(datetime.fromtimestamp(max(mtimes))) if mtimes else None
|
||||
make_aware(datetime.fromtimestamp(max(mtimes))) # noqa: DTZ006 - make_aware() requires a naive datetime
|
||||
if mtimes
|
||||
else None
|
||||
)
|
||||
except Exception:
|
||||
index_status = "ERROR"
|
||||
|
||||
@@ -47,7 +47,7 @@ def resolve_date(dates: list[str]) -> date | None:
|
||||
"""
|
||||
for value in dates:
|
||||
try:
|
||||
return datetime.strptime(value, "%Y-%m-%d").date()
|
||||
return datetime.strptime(value, "%Y-%m-%d").date() # noqa: DTZ007 - only the calendar date is used, time/tz is discarded
|
||||
except (TypeError, ValueError):
|
||||
logger.debug("Ignoring unparsable suggested date %s", value)
|
||||
return None
|
||||
|
||||
@@ -7,7 +7,6 @@ import ssl
|
||||
import tempfile
|
||||
import traceback
|
||||
import unicodedata
|
||||
from datetime import date
|
||||
from datetime import timedelta
|
||||
from fnmatch import fnmatch
|
||||
from pathlib import Path
|
||||
@@ -406,7 +405,7 @@ def make_criterias(rule: MailRule, *, supports_gmail_labels: bool):
|
||||
Returns criteria to be applied to MailBox.fetch for the given rule.
|
||||
"""
|
||||
|
||||
maximum_age = date.today() - timedelta(days=rule.maximum_age)
|
||||
maximum_age = timezone.localdate() - timedelta(days=rule.maximum_age)
|
||||
criterias = {}
|
||||
if rule.maximum_age > 0:
|
||||
criterias["date_gte"] = maximum_age
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import datetime
|
||||
import logging
|
||||
from datetime import timedelta
|
||||
from http import HTTPStatus
|
||||
@@ -87,7 +86,7 @@ class MailAccountViewSet(PassUserMixin, ModelViewSet[MailAccount]):
|
||||
@action(methods=["post"], detail=False)
|
||||
def test(self, request):
|
||||
logger = logging.getLogger("paperless_mail")
|
||||
request.data["name"] = datetime.datetime.now().isoformat()
|
||||
request.data["name"] = timezone.now().isoformat()
|
||||
serializer = self.get_serializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
existing_account = None
|
||||
|
||||
Reference in New Issue
Block a user