Browse Source

Fix Python 3.10 compatibility (StrEnum requires 3.11)

  enum.StrEnum was added in Python 3.11, but the documented minimum is
  3.10. Add a compatibility shim in backend/app/core/compat.py that falls
  back to (str, Enum) on older versions. Updated all 5 import sites and
  lowered pyproject.toml target-version to py310.
maziggy 2 months ago
parent
commit
0faf03ecb3

+ 1 - 0
CHANGELOG.md

@@ -11,6 +11,7 @@ All notable changes to Bambuddy will be documented in this file.
 - **Print Queue Scheduler Diagnostics** ([#616](https://github.com/maziggy/bambuddy/issues/616)) — Added diagnostic logging to the print queue scheduler to help diagnose why queued prints aren't starting. After each queue check, the scheduler now logs a skip summary (how many items were skipped due to manual_start, scheduled_time, etc.) and for each busy printer, logs the exact state preventing it from being considered idle (connected status, printer state, plate_cleared flag). Previously the scheduler only logged "found N pending items" with no visibility into why items were skipped.
 
 ### Fixed
+- **Python 3.10 Compatibility** — Bambuddy failed to start on Python 3.10 with `ImportError: cannot import name 'StrEnum' from 'enum'` because `enum.StrEnum` was added in Python 3.11. Added a compatibility shim that falls back to `(str, Enum)` on Python < 3.11, matching the documented requirement of Python 3.10+.
 - **Bug Report Bubble Overlapping Toasts** — Moved toast notifications and upload progress up so they stack above the bug report bubble instead of overlapping on top of each other.
 - **Virtual Printer: Bind-TLS Proxy Handshake Failure on OpenSSL 3.x** — The TLS proxy connecting to the printer's bind port (3002) failed with `SSLV3_ALERT_HANDSHAKE_FAILURE` on systems with OpenSSL 3.x (e.g. Python 3.12+) because the default cipher set excludes plain RSA key exchange, which is the only mode Bambu printers support. Added `AES256-GCM-SHA384` and `AES128-GCM-SHA256` to the client SSL context's cipher list.
 - **Windows: Server Shuts Down After 60 Seconds** ([#605](https://github.com/maziggy/bambuddy/issues/605)) — On Windows, terminating orphaned ffmpeg camera processes broadcast `CTRL_C_EVENT` to the entire process group, causing uvicorn to interpret it as a user-initiated shutdown. ffmpeg is now spawned in its own process group (`CREATE_NEW_PROCESS_GROUP`) so cleanup no longer affects the server. Reported by @Reactantvr.

+ 11 - 0
backend/app/core/compat.py

@@ -0,0 +1,11 @@
+"""Compatibility shims for older Python versions."""
+
+import sys
+
+if sys.version_info >= (3, 11):
+    from enum import StrEnum
+else:
+    from enum import Enum
+
+    class StrEnum(str, Enum):
+        """Drop-in replacement for enum.StrEnum on Python < 3.11."""

+ 1 - 1
backend/app/core/permissions.py

@@ -4,7 +4,7 @@ This module defines all permissions using a string enum with `resource:action` n
 Permissions are additive across groups - a user has all permissions from all their groups.
 """
 
-from enum import StrEnum
+from backend.app.core.compat import StrEnum
 
 
 class Permission(StrEnum):

+ 2 - 1
backend/app/schemas/github_backup.py

@@ -2,10 +2,11 @@
 
 import re
 from datetime import datetime
-from enum import StrEnum
 
 from pydantic import BaseModel, Field, field_validator
 
+from backend.app.core.compat import StrEnum
+
 
 class ScheduleType(StrEnum):
     """Backup schedule types."""

+ 2 - 1
backend/app/schemas/notification.py

@@ -1,11 +1,12 @@
 """Pydantic schemas for notification providers."""
 
 from datetime import datetime
-from enum import StrEnum
 from typing import Any
 
 from pydantic import BaseModel, Field, field_validator
 
+from backend.app.core.compat import StrEnum
+
 
 class ProviderType(StrEnum):
     """Supported notification provider types."""

+ 2 - 1
backend/app/schemas/notification_template.py

@@ -1,10 +1,11 @@
 """Pydantic schemas for notification templates."""
 
 from datetime import datetime
-from enum import StrEnum
 
 from pydantic import BaseModel, Field
 
+from backend.app.core.compat import StrEnum
+
 
 class EventType(StrEnum):
     """Supported notification event types."""

+ 1 - 1
backend/app/services/firmware_update.py

@@ -11,11 +11,11 @@ Orchestrates firmware updates for Bambu Lab printers:
 import asyncio
 import logging
 from dataclasses import dataclass
-from enum import StrEnum
 
 from sqlalchemy import select
 from sqlalchemy.ext.asyncio import AsyncSession
 
+from backend.app.core.compat import StrEnum
 from backend.app.core.websocket import ws_manager
 from backend.app.models.printer import Printer
 from backend.app.services.bambu_ftp import (

+ 1 - 1
install/install.sh

@@ -242,7 +242,7 @@ detect_python() {
     minor=$(echo "$version" | cut -d'.' -f2)
 
     if [[ "$major" -lt 3 ]] || { [[ "$major" -eq 3 ]] && [[ "$minor" -lt 10 ]]; }; then
-        log_warn "Python $version found, but 3.10+ is required"
+        log_warn "Python $version found, but 3.10 or newer is required"
         return 1
     fi
 

+ 4 - 2
pyproject.toml

@@ -2,10 +2,10 @@
 name = "bambuddy"
 version = "0.1.5"
 description = "Archive and manage Bambu Lab 3MF files"
-requires-python = ">=3.11"
+requires-python = ">=3.10"
 
 [tool.ruff]
-target-version = "py311"
+target-version = "py310"
 line-length = 120
 exclude = [
     ".git",
@@ -54,6 +54,8 @@ unfixable = []
 "backend/app/main.py" = ["E402"]
 # MQTT client has some unused variables for debugging
 "backend/app/services/bambu_mqtt.py" = ["F841"]
+# compat module intentionally uses version checks for Python 3.10 support
+"backend/app/core/compat.py" = ["UP036"]
 
 [tool.ruff.lint.isort]
 known-first-party = ["backend"]