Procházet zdrojové kódy

Remove unused imports, variables, and fix minor CodeQL findings

- Remove 28 unused imports across 22 test files
- Prefix 4 unused local variables with _ in app code
  (archives, bambu_mqtt, main) and remove 1 dead store
- Consolidate import/import-from in test_plate_detection.py
- Fix unreachable statement in test_archive_service.py
- Simplify redundant comparison in timelapse_processor.py

Resolves ~50 CodeQL py/unused-import, py/unused-local-variable,
py/import-and-import-from, py/unreachable-statement, and
py/redundant-comparison findings.
maziggy před 3 měsíci
rodič
revize
b99536cc33

+ 1 - 1
backend/app/api/routes/archives.py

@@ -1270,7 +1270,7 @@ async def scan_timelapse(
     if not matching_file and (archive.started_at or archive.completed_at or archive.created_at):
     if not matching_file and (archive.started_at or archive.completed_at or archive.created_at):
         from datetime import datetime, timedelta
         from datetime import datetime, timedelta
 
 
-        archive_start = archive.started_at
+        _archive_start = archive.started_at
         archive_end = archive.completed_at or archive.created_at
         archive_end = archive.completed_at or archive.created_at
         best_match = None
         best_match = None
         best_diff = timedelta(hours=24)
         best_diff = timedelta(hours=24)

+ 1 - 2
backend/app/main.py

@@ -963,7 +963,7 @@ async def on_print_start(printer_id: int, data: dict):
                 existing_archive.failure_reason = "Stale - print likely cancelled or failed without status update"
                 existing_archive.failure_reason = "Stale - print likely cancelled or failed without status update"
                 await db.commit()
                 await db.commit()
                 # Fall through to create new archive (don't return)
                 # Fall through to create new archive (don't return)
-                existing_archive = None  # Clear so we don't use stale archive
+                _existing_archive = None  # Clear so we don't use stale archive
             else:
             else:
                 logger.info(
                 logger.info(
                     f"Skipping duplicate - already have printing archive {existing_archive.id} for {check_name}"
                     f"Skipping duplicate - already have printing archive {existing_archive.id} for {check_name}"
@@ -1325,7 +1325,6 @@ async def on_print_start(printer_id: int, data: dict):
                 if not notification_sent:
                 if not notification_sent:
                     archive_data = {"print_time_seconds": archive.print_time_seconds}
                     archive_data = {"print_time_seconds": archive.print_time_seconds}
                     await _send_print_start_notification(printer_id, data, archive_data, logger)
                     await _send_print_start_notification(printer_id, data, archive_data, logger)
-                    notification_sent = True
 
 
                 # Extract printable objects for skip object functionality
                 # Extract printable objects for skip object functionality
                 try:
                 try:

+ 2 - 2
backend/app/services/bambu_mqtt.py

@@ -1064,7 +1064,7 @@ class BambuMQTTClient:
 
 
     def _update_state(self, data: dict):
     def _update_state(self, data: dict):
         """Update printer state from message data."""
         """Update printer state from message data."""
-        previous_state = self.state.state
+        _previous_state = self.state.state
 
 
         # Update state fields
         # Update state fields
         if "gcode_state" in data:
         if "gcode_state" in data:
@@ -2370,7 +2370,7 @@ class BambuMQTTClient:
     def _handle_kprofile_response(self, data: dict):
     def _handle_kprofile_response(self, data: dict):
         """Handle K-profile response from printer."""
         """Handle K-profile response from printer."""
         response_nozzle = data.get("nozzle_diameter")
         response_nozzle = data.get("nozzle_diameter")
-        response_seq_id = data.get("sequence_id", "?")
+        _response_seq_id = data.get("sequence_id", "?")
         filaments = data.get("filaments", [])
         filaments = data.get("filaments", [])
         expected_nozzle = getattr(self, "_expected_kprofile_nozzle", None)
         expected_nozzle = getattr(self, "_expected_kprofile_nozzle", None)
         has_pending_request = self._pending_kprofile_response is not None
         has_pending_request = self._pending_kprofile_response is not None

+ 2 - 1
backend/app/services/timelapse_processor.py

@@ -258,7 +258,8 @@ class TimelapseProcessor:
             remaining_speed *= 2.0
             remaining_speed *= 2.0
 
 
         # Add final atempo for remaining adjustment
         # Add final atempo for remaining adjustment
-        if 0.5 <= remaining_speed <= 2.0 and remaining_speed != 1.0:
+        # After the while loops above, remaining_speed is guaranteed to be in [0.5, 2.0]
+        if remaining_speed != 1.0:
             filters.append(f"atempo={remaining_speed:.4f}")
             filters.append(f"atempo={remaining_speed:.4f}")
 
 
         return ",".join(filters)
         return ",".join(filters)

+ 0 - 2
backend/tests/conftest.py

@@ -6,10 +6,8 @@ import json
 import logging
 import logging
 import os
 import os
 import shutil
 import shutil
-import sys
 import tempfile
 import tempfile
 from collections.abc import AsyncGenerator
 from collections.abc import AsyncGenerator
-from datetime import datetime
 from pathlib import Path
 from pathlib import Path
 from unittest.mock import AsyncMock, MagicMock, patch
 from unittest.mock import AsyncMock, MagicMock, patch
 
 

+ 0 - 1
backend/tests/integration/test_camera_api.py

@@ -3,7 +3,6 @@
 Tests the full request/response cycle for /api/v1/printers/{id}/camera/ endpoints.
 Tests the full request/response cycle for /api/v1/printers/{id}/camera/ endpoints.
 """
 """
 
 
-import asyncio
 from unittest.mock import AsyncMock, MagicMock, patch
 from unittest.mock import AsyncMock, MagicMock, patch
 
 
 import pytest
 import pytest

+ 0 - 2
backend/tests/integration/test_discovery_api.py

@@ -3,8 +3,6 @@
 Tests the full request/response cycle for /api/v1/discovery/ endpoints.
 Tests the full request/response cycle for /api/v1/discovery/ endpoints.
 """
 """
 
 
-from unittest.mock import AsyncMock, patch
-
 import pytest
 import pytest
 from httpx import AsyncClient
 from httpx import AsyncClient
 
 

+ 1 - 1
backend/tests/integration/test_endpoint_auth.py

@@ -4,7 +4,7 @@ Tests that verify endpoints properly enforce authentication when auth is enabled
 and allow access when auth is disabled (CVE-2026-25505 fix verification).
 and allow access when auth is disabled (CVE-2026-25505 fix verification).
 """
 """
 
 
-from unittest.mock import AsyncMock, patch
+from unittest.mock import patch
 
 
 import pytest
 import pytest
 from httpx import AsyncClient
 from httpx import AsyncClient

+ 0 - 2
backend/tests/integration/test_print_lifecycle.py

@@ -13,11 +13,9 @@ Full end-to-end tests require the actual database setup.
 """
 """
 
 
 import asyncio
 import asyncio
-from datetime import datetime
 from unittest.mock import AsyncMock, MagicMock, patch
 from unittest.mock import AsyncMock, MagicMock, patch
 
 
 import pytest
 import pytest
-from sqlalchemy import select
 
 
 
 
 class TestPrintStartLogic:
 class TestPrintStartLogic:

+ 1 - 1
backend/tests/integration/test_printers_api.py

@@ -3,7 +3,7 @@
 Tests the full request/response cycle for /api/v1/printers/ endpoints.
 Tests the full request/response cycle for /api/v1/printers/ endpoints.
 """
 """
 
 
-from unittest.mock import AsyncMock, MagicMock, patch
+from unittest.mock import MagicMock, patch
 
 
 import pytest
 import pytest
 from httpx import AsyncClient
 from httpx import AsyncClient

+ 1 - 1
backend/tests/integration/test_updates_api.py

@@ -1,6 +1,6 @@
 """Integration tests for Updates API endpoints."""
 """Integration tests for Updates API endpoints."""
 
 
-from unittest.mock import AsyncMock, MagicMock, patch
+from unittest.mock import AsyncMock, patch
 
 
 import pytest
 import pytest
 from httpx import AsyncClient
 from httpx import AsyncClient

+ 9 - 28
backend/tests/unit/services/test_archive_service.py

@@ -1,9 +1,6 @@
 """Unit tests for the archive service."""
 """Unit tests for the archive service."""
 
 
 from datetime import datetime
 from datetime import datetime
-from unittest.mock import AsyncMock, MagicMock, patch
-
-import pytest
 
 
 
 
 class TestArchiveServiceHelpers:
 class TestArchiveServiceHelpers:
@@ -364,41 +361,25 @@ class TestThreeMFPlateIndexExtraction:
         # First priority should be plate_5.png
         # First priority should be plate_5.png
         assert thumbnail_paths[0] == "Metadata/plate_5.png"
         assert thumbnail_paths[0] == "Metadata/plate_5.png"
 
 
-    def test_print_name_enhanced_for_plate_greater_than_1(self):
-        """Test that print_name is enhanced with plate info for plate > 1."""
-        plate_index = 5
-        print_name = "Benchy"
-
-        # Logic from archive.py
+    @staticmethod
+    def _enhance_print_name(print_name: str, plate_index: int) -> str:
+        """Apply plate name enhancement logic from archive.py."""
         if plate_index and plate_index > 1:
         if plate_index and plate_index > 1:
             if print_name and f"Plate {plate_index}" not in print_name:
             if print_name and f"Plate {plate_index}" not in print_name:
                 print_name = f"{print_name} - Plate {plate_index}"
                 print_name = f"{print_name} - Plate {plate_index}"
+        return print_name
 
 
-        assert print_name == "Benchy - Plate 5"
+    def test_print_name_enhanced_for_plate_greater_than_1(self):
+        """Test that print_name is enhanced with plate info for plate > 1."""
+        assert self._enhance_print_name("Benchy", 5) == "Benchy - Plate 5"
 
 
     def test_print_name_not_enhanced_for_plate_1(self):
     def test_print_name_not_enhanced_for_plate_1(self):
         """Test that print_name is NOT enhanced for plate 1."""
         """Test that print_name is NOT enhanced for plate 1."""
-        plate_index = 1
-        print_name = "Benchy"
-
-        # Logic from archive.py
-        if plate_index and plate_index > 1:
-            if print_name and f"Plate {plate_index}" not in print_name:
-                print_name = f"{print_name} - Plate {plate_index}"
-
-        assert print_name == "Benchy"  # Unchanged for plate 1
+        assert self._enhance_print_name("Benchy", 1) == "Benchy"
 
 
     def test_print_name_not_duplicated(self):
     def test_print_name_not_duplicated(self):
         """Test that plate info is not added if already present in print_name."""
         """Test that plate info is not added if already present in print_name."""
-        plate_index = 5
-        print_name = "Benchy - Plate 5"
-
-        # Logic from archive.py
-        if plate_index and plate_index > 1:
-            if print_name and f"Plate {plate_index}" not in print_name:
-                print_name = f"{print_name} - Plate {plate_index}"
-
-        assert print_name == "Benchy - Plate 5"  # Not duplicated
+        assert self._enhance_print_name("Benchy - Plate 5", 5) == "Benchy - Plate 5"
 
 
     def test_high_plate_number_extraction(self):
     def test_high_plate_number_extraction(self):
         """Test extracting high plate numbers (e.g., plate 28)."""
         """Test extracting high plate numbers (e.g., plate 28)."""

+ 0 - 2
backend/tests/unit/services/test_bambu_mqtt.py

@@ -4,8 +4,6 @@ Tests for the BambuMQTTClient service.
 These tests focus on timelapse tracking during prints.
 These tests focus on timelapse tracking during prints.
 """
 """
 
 
-from unittest.mock import MagicMock, patch
-
 import pytest
 import pytest
 
 
 
 

+ 1 - 1
backend/tests/unit/services/test_external_camera.py

@@ -4,7 +4,7 @@ Tests for the external camera service.
 These tests cover pure functions and frame parsing logic.
 These tests cover pure functions and frame parsing logic.
 """
 """
 
 
-from unittest.mock import MagicMock, patch
+from unittest.mock import patch
 
 
 import pytest
 import pytest
 
 

+ 0 - 2
backend/tests/unit/services/test_hms_errors.py

@@ -1,7 +1,5 @@
 """Tests for HMS error code translations."""
 """Tests for HMS error code translations."""
 
 
-import pytest
-
 from backend.app.services.hms_errors import HMS_ERROR_DESCRIPTIONS, get_error_description
 from backend.app.services.hms_errors import HMS_ERROR_DESCRIPTIONS, get_error_description
 
 
 
 

+ 0 - 1
backend/tests/unit/services/test_notification_service.py

@@ -4,7 +4,6 @@ Tests event-based notifications and toggle behavior.
 """
 """
 
 
 import json
 import json
-from datetime import datetime
 from unittest.mock import AsyncMock, MagicMock, patch
 from unittest.mock import AsyncMock, MagicMock, patch
 
 
 import pytest
 import pytest

+ 18 - 5
backend/tests/unit/services/test_plate_detection.py

@@ -1,7 +1,5 @@
 """Unit tests for plate detection service."""
 """Unit tests for plate detection service."""
 
 
-import tempfile
-from pathlib import Path
 from unittest.mock import MagicMock, patch
 from unittest.mock import MagicMock, patch
 
 
 import pytest
 import pytest
@@ -17,7 +15,12 @@ class TestPlateDetectionResult:
     def test_result_to_dict(self):
     def test_result_to_dict(self):
         """Verify PlateDetectionResult.to_dict() returns correct structure."""
         """Verify PlateDetectionResult.to_dict() returns correct structure."""
         with patch.dict("sys.modules", {"cv2": cv2_mock, "numpy": np_mock}):
         with patch.dict("sys.modules", {"cv2": cv2_mock, "numpy": np_mock}):
-            from backend.app.services.plate_detection import PlateDetectionResult
+            import importlib
+
+            import backend.app.services.plate_detection as pd_module
+
+            importlib.reload(pd_module)
+            PlateDetectionResult = pd_module.PlateDetectionResult
 
 
             result = PlateDetectionResult(
             result = PlateDetectionResult(
                 is_empty=True,
                 is_empty=True,
@@ -40,7 +43,12 @@ class TestPlateDetectionResult:
     def test_result_with_debug_image(self):
     def test_result_with_debug_image(self):
         """Verify has_debug_image is True when debug_image is provided."""
         """Verify has_debug_image is True when debug_image is provided."""
         with patch.dict("sys.modules", {"cv2": cv2_mock, "numpy": np_mock}):
         with patch.dict("sys.modules", {"cv2": cv2_mock, "numpy": np_mock}):
-            from backend.app.services.plate_detection import PlateDetectionResult
+            import importlib
+
+            import backend.app.services.plate_detection as pd_module
+
+            importlib.reload(pd_module)
+            PlateDetectionResult = pd_module.PlateDetectionResult
 
 
             result = PlateDetectionResult(
             result = PlateDetectionResult(
                 is_empty=False,
                 is_empty=False,
@@ -57,7 +65,12 @@ class TestPlateDetectionResult:
     def test_result_needs_calibration(self):
     def test_result_needs_calibration(self):
         """Verify needs_calibration flag is preserved."""
         """Verify needs_calibration flag is preserved."""
         with patch.dict("sys.modules", {"cv2": cv2_mock, "numpy": np_mock}):
         with patch.dict("sys.modules", {"cv2": cv2_mock, "numpy": np_mock}):
-            from backend.app.services.plate_detection import PlateDetectionResult
+            import importlib
+
+            import backend.app.services.plate_detection as pd_module
+
+            importlib.reload(pd_module)
+            PlateDetectionResult = pd_module.PlateDetectionResult
 
 
             result = PlateDetectionResult(
             result = PlateDetectionResult(
                 is_empty=True,
                 is_empty=True,

+ 1 - 3
backend/tests/unit/services/test_printer_manager.py

@@ -3,9 +3,7 @@
 Tests printer connection management, status tracking, and print control.
 Tests printer connection management, status tracking, and print control.
 """
 """
 
 
-import asyncio
-from datetime import datetime
-from unittest.mock import AsyncMock, MagicMock, PropertyMock, patch
+from unittest.mock import AsyncMock, MagicMock, patch
 
 
 import pytest
 import pytest
 
 

+ 0 - 1
backend/tests/unit/services/test_smart_plug_manager.py

@@ -4,7 +4,6 @@ These tests specifically target the auto-off behavior and toggle functionality
 that were identified as common regression points.
 that were identified as common regression points.
 """
 """
 
 
-import asyncio
 from datetime import datetime
 from datetime import datetime
 from unittest.mock import AsyncMock, MagicMock, patch
 from unittest.mock import AsyncMock, MagicMock, patch
 
 

+ 0 - 2
backend/tests/unit/services/test_spoolman_tracking.py

@@ -1,7 +1,5 @@
 """Unit tests for Spoolman tracking service helpers."""
 """Unit tests for Spoolman tracking service helpers."""
 
 
-import pytest
-
 from backend.app.services.spoolman_tracking import (
 from backend.app.services.spoolman_tracking import (
     _resolve_global_tray_id,
     _resolve_global_tray_id,
     _resolve_spool_tag,
     _resolve_spool_tag,

+ 0 - 1
backend/tests/unit/services/test_stl_thumbnail.py

@@ -2,7 +2,6 @@
 
 
 import tempfile
 import tempfile
 from pathlib import Path
 from pathlib import Path
-from unittest.mock import MagicMock, patch
 
 
 import pytest
 import pytest
 
 

+ 0 - 1
backend/tests/unit/test_code_quality.py

@@ -6,7 +6,6 @@ that could cause runtime errors but aren't caught by normal tests.
 """
 """
 
 
 import ast
 import ast
-import os
 from pathlib import Path
 from pathlib import Path
 
 
 import pytest
 import pytest

+ 0 - 4
backend/tests/unit/test_log_error_detection.py

@@ -5,10 +5,6 @@ These tests use the capture_logs fixture to detect runtime errors
 that might not cause test failures but indicate problems.
 that might not cause test failures but indicate problems.
 """
 """
 
 
-from unittest.mock import AsyncMock, MagicMock, patch
-
-import pytest
-
 
 
 class TestMQTTMessageProcessingNoErrors:
 class TestMQTTMessageProcessingNoErrors:
     """Verify MQTT message processing doesn't log errors."""
     """Verify MQTT message processing doesn't log errors."""

+ 0 - 1
backend/tests/unit/test_plate_object_extraction.py

@@ -1,6 +1,5 @@
 """Unit tests for plate object extraction from 3MF model_settings.config."""
 """Unit tests for plate object extraction from 3MF model_settings.config."""
 
 
-import pytest
 from defusedxml import ElementTree as ET
 from defusedxml import ElementTree as ET
 
 
 
 

+ 0 - 2
backend/tests/unit/test_threemf_tools.py

@@ -6,8 +6,6 @@ and cumulative layer usage lookup.
 
 
 import math
 import math
 
 
-import pytest
-
 from backend.app.utils.threemf_tools import (
 from backend.app.utils.threemf_tools import (
     get_cumulative_usage_at_layer,
     get_cumulative_usage_at_layer,
     mm_to_grams,
     mm_to_grams,

+ 1 - 1
tests/e2e_toggle_persistence_test.py

@@ -8,7 +8,7 @@ are properly persisted to the database and survive page reloads.
 import os
 import os
 import time
 import time
 
 
-from playwright.sync_api import expect, sync_playwright
+from playwright.sync_api import sync_playwright
 
 
 BASE_URL = os.environ.get("BAMBUDDY_URL", "http://localhost:8000")
 BASE_URL = os.environ.get("BAMBUDDY_URL", "http://localhost:8000")