Fix Python 3.10 compatibility (Issue #269)

Replace datetime.UTC with timezone.utc for Python 3.10 support.
datetime.UTC was added in Python 3.11, but requirements state 3.10+.

Closes #269
This commit is contained in:
maziggy
2026-02-05 07:46:22 +01:00
parent 87cf0e83e9
commit 819ab896bd
7 changed files with 26 additions and 25 deletions
+3 -3
View File
@@ -1,6 +1,6 @@
"""API routes for pending uploads (virtual printer queue mode)."""
from datetime import UTC, datetime
from datetime import datetime, timezone
from pathlib import Path
from fastapi import APIRouter, Depends, HTTPException
@@ -107,7 +107,7 @@ async def archive_all_pending(
if archive:
pending.status = "archived"
pending.archived_id = archive.id
pending.archived_at = datetime.now(UTC)
pending.archived_at = datetime.now(timezone.utc)
archived += 1
# Clean up temp file
@@ -219,7 +219,7 @@ async def archive_pending_upload(
# Update pending record
pending.status = "archived"
pending.archived_id = archive.id
pending.archived_at = datetime.now(UTC)
pending.archived_at = datetime.now(timezone.utc)
if request:
pending.tags = request.tags
pending.notes = request.notes
+2 -2
View File
@@ -1,7 +1,7 @@
import asyncio
import logging
from contextlib import asynccontextmanager
from datetime import UTC, datetime, timedelta
from datetime import datetime, timedelta, timezone
from logging.handlers import RotatingFileHandler
@@ -1027,7 +1027,7 @@ async def on_print_start(printer_id: int, data: dict):
if existing_archive:
# Check if archive is stale (older than 4 hours) - likely a failed/cancelled print
# that didn't get properly updated
archive_age = datetime.now(UTC) - existing_archive.created_at.replace(tzinfo=UTC)
archive_age = datetime.now(timezone.utc) - existing_archive.created_at.replace(tzinfo=timezone.utc)
if archive_age.total_seconds() > 4 * 60 * 60: # 4 hours
logger.warning(
f"Found stale 'printing' archive {existing_archive.id} (age: {archive_age}), "
+12 -12
View File
@@ -9,7 +9,7 @@ import hashlib
import json
import logging
import re
from datetime import UTC, datetime, timedelta
from datetime import datetime, timedelta, timezone
import httpx
from sqlalchemy import desc, select
@@ -85,19 +85,19 @@ class GitHubBackupService:
)
configs = result.scalars().all()
now = datetime.now(UTC)
now = datetime.now(timezone.utc)
for config in configs:
# Handle both naive (from DB) and aware datetimes
next_run = config.next_scheduled_run
if next_run and next_run.tzinfo is None:
next_run = next_run.replace(tzinfo=UTC)
next_run = next_run.replace(tzinfo=timezone.utc)
if next_run and next_run <= now:
logger.info(f"Running scheduled backup for config {config.id}")
await self.run_backup(config.id, trigger="scheduled")
def _calculate_next_run(self, schedule_type: str, from_time: datetime | None = None) -> datetime:
"""Calculate the next scheduled run time."""
now = from_time or datetime.now(UTC)
now = from_time or datetime.now(timezone.utc)
interval = SCHEDULE_INTERVALS.get(schedule_type, SCHEDULE_INTERVALS["daily"])
return now + timedelta(seconds=interval)
@@ -237,9 +237,9 @@ class GitHubBackupService:
if not backup_data:
# No data to backup
log.status = "skipped"
log.completed_at = datetime.now(UTC)
log.completed_at = datetime.now(timezone.utc)
log.error_message = "No data to backup"
config.last_backup_at = datetime.now(UTC)
config.last_backup_at = datetime.now(timezone.utc)
config.last_backup_status = "skipped"
config.last_backup_message = "No data to backup"
if config.schedule_enabled:
@@ -259,12 +259,12 @@ class GitHubBackupService:
# Update log and config
log.status = push_result["status"]
log.completed_at = datetime.now(UTC)
log.completed_at = datetime.now(timezone.utc)
log.commit_sha = push_result.get("commit_sha")
log.files_changed = push_result.get("files_changed", 0)
log.error_message = push_result.get("error")
config.last_backup_at = datetime.now(UTC)
config.last_backup_at = datetime.now(timezone.utc)
config.last_backup_status = push_result["status"]
config.last_backup_message = push_result.get("message", "")
config.last_backup_commit_sha = push_result.get("commit_sha")
@@ -285,10 +285,10 @@ class GitHubBackupService:
except Exception as e:
logger.error(f"Backup failed: {e}")
log.status = "failed"
log.completed_at = datetime.now(UTC)
log.completed_at = datetime.now(timezone.utc)
log.error_message = str(e)
config.last_backup_at = datetime.now(UTC)
config.last_backup_at = datetime.now(timezone.utc)
config.last_backup_status = "failed"
config.last_backup_message = str(e)
@@ -572,7 +572,7 @@ class GitHubBackupService:
new_tree_sha = tree_response.json()["sha"]
# Create commit
commit_message = f"Bambuddy backup - {datetime.now(UTC).strftime('%Y-%m-%d %H:%M:%S UTC')}"
commit_message = f"Bambuddy backup - {datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M:%S UTC')}"
commit_response = await client.post(
f"https://api.github.com/repos/{owner}/{repo}/git/commits",
headers=headers,
@@ -689,7 +689,7 @@ class GitHubBackupService:
f"https://api.github.com/repos/{owner}/{repo}/git/commits",
headers=headers,
json={
"message": f"Initial Bambuddy backup - {datetime.now(UTC).strftime('%Y-%m-%d %H:%M:%S UTC')}",
"message": f"Initial Bambuddy backup - {datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M:%S UTC')}",
"tree": tree_sha,
},
)
+2 -2
View File
@@ -2,7 +2,7 @@
import logging
from dataclasses import dataclass
from datetime import UTC, datetime
from datetime import datetime, timezone
import httpx
@@ -355,7 +355,7 @@ class SpoolmanClient:
data["extra"] = extra
# Always update last_used
data["last_used"] = datetime.now(UTC).isoformat()
data["last_used"] = datetime.now(timezone.utc).isoformat()
client = await self._get_client()
response = await client.patch(f"{self.api_url}/spool/{spool_id}", json=data)
@@ -10,7 +10,7 @@ This allows users to add the CA to their slicer's trust store once.
import logging
import socket
from datetime import UTC, datetime, timedelta
from datetime import datetime, timedelta, timezone
from ipaddress import IPv4Address
from pathlib import Path
@@ -89,7 +89,7 @@ class CertificateService:
ca_cert = x509.load_pem_x509_certificate(ca_cert_pem)
# Check if CA is expired or about to expire
now = datetime.now(UTC)
now = datetime.now(timezone.utc)
days_remaining = (ca_cert.not_valid_after_utc - now).days
if days_remaining < CA_EXPIRY_THRESHOLD_DAYS:
logger.warning(f"CA certificate expires in {days_remaining} days, will regenerate")
@@ -160,7 +160,7 @@ class CertificateService:
]
)
now = datetime.now(UTC)
now = datetime.now(timezone.utc)
ca_cert = (
x509.CertificateBuilder()
@@ -227,7 +227,7 @@ class CertificateService:
# Issuer is the CA
issuer = ca_cert.subject
now = datetime.now(UTC)
now = datetime.now(timezone.utc)
local_ip = _get_local_ip()
logger.info(f"Generating printer certificate with CN={self.serial}, local IP: {local_ip}")
@@ -10,7 +10,7 @@ Supports multiple modes:
import asyncio
import logging
from collections.abc import Callable
from datetime import UTC, datetime
from datetime import datetime, timezone
from pathlib import Path
from backend.app.core.config import settings as app_settings
@@ -598,7 +598,7 @@ class VirtualPrinterManager:
file_size=file_path.stat().st_size,
source_ip=source_ip,
status="pending",
uploaded_at=datetime.now(UTC),
uploaded_at=datetime.now(timezone.utc),
)
db.add(pending)
await db.commit()
+1
View File
@@ -38,6 +38,7 @@ ignore = [
"SIM108", # ternary operator (readability preference)
"SIM102", # nested if (readability preference)
"SIM105", # contextlib.suppress (readability preference)
"UP017", # datetime.UTC alias (Python 3.11+ only, we support 3.10)
]
# Allow autofix for all enabled rules