Merge pull request #228 from christianlouis/copilot/check-all-lints-in-main
fix: resolve all backend lint errors (black, ruff, mypy)
This commit is contained in:
@@ -14,6 +14,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Lint**: Removed unused imports (`pytest` in `test_dns_fallback.py`, `asyncio` in `test_mail_processor_pop3.py`); reformatted three test files with Black; resolved mypy type errors in `mail_processor.py` (IPv4 address tuple indexing, `_create_socket` override) and suppressed spurious `alembic.command` attr-defined error in `main.py`.
|
||||
|
||||
- **POP3/IMAP connectivity**: Added retry logic (up to 3 attempts, 5 s delay) for
|
||||
transient errors (`-ERR EOF`, timeout, connection-reset) in both POP3 and IMAP
|
||||
fetch paths. Most `-ERR EOF` and "timed out" failures now self-heal without
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ from fastapi.middleware.cors import CORSMiddleware
|
||||
from prometheus_client import generate_latest, CONTENT_TYPE_LATEST
|
||||
import logging
|
||||
from alembic.config import Config as AlembicConfig
|
||||
from alembic import command as alembic_command
|
||||
from alembic import command as alembic_command # type: ignore[attr-defined]
|
||||
|
||||
from app.core.config import settings
|
||||
from app.core.middleware import SecurityHeadersMiddleware, CSRFProtectionMiddleware
|
||||
|
||||
@@ -196,7 +196,7 @@ def _resolve_ipv4_sync(host: str, port: int) -> Optional[str]:
|
||||
try:
|
||||
infos = socket.getaddrinfo(host, port, socket.AF_INET, socket.SOCK_STREAM)
|
||||
if infos:
|
||||
ipv4 = infos[0][4][0]
|
||||
ipv4: str = infos[0][4][0] # type: ignore[assignment]
|
||||
if settings.DNS_CACHE_FALLBACK_ENABLED:
|
||||
_set_cached_ipv4(host, port, ipv4)
|
||||
return ipv4
|
||||
@@ -250,10 +250,10 @@ class _POP3WithIPv4Pref(poplib.POP3):
|
||||
self._ipv4_addr = _ipv4_addr
|
||||
super().__init__(host, port, timeout)
|
||||
|
||||
def _create_socket(self, timeout: Any) -> socket.socket: # type: ignore[override]
|
||||
def _create_socket(self, timeout: Any) -> socket.socket: # type: ignore[override,misc]
|
||||
if self._ipv4_addr:
|
||||
return socket.create_connection((self._ipv4_addr, self.port), timeout)
|
||||
return super()._create_socket(timeout)
|
||||
return super()._create_socket(timeout) # type: ignore[misc]
|
||||
|
||||
|
||||
class _POP3SSLWithIPv4Pref(poplib.POP3_SSL):
|
||||
@@ -279,10 +279,10 @@ class _POP3SSLWithIPv4Pref(poplib.POP3_SSL):
|
||||
self._ipv4_addr = _ipv4_addr
|
||||
super().__init__(host, port, timeout=timeout, context=context)
|
||||
|
||||
def _create_socket(self, timeout: Any) -> socket.socket: # type: ignore[override]
|
||||
def _create_socket(self, timeout: Any) -> socket.socket: # type: ignore[override,misc]
|
||||
if self._ipv4_addr:
|
||||
return socket.create_connection((self._ipv4_addr, self.port), timeout)
|
||||
return super()._create_socket(timeout)
|
||||
return super()._create_socket(timeout) # type: ignore[misc]
|
||||
|
||||
|
||||
def _make_pop3_conn(
|
||||
|
||||
@@ -13,7 +13,6 @@ import socket
|
||||
import struct
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from app.services.mail_processor import (
|
||||
_build_dns_query,
|
||||
@@ -24,7 +23,6 @@ from app.services.mail_processor import (
|
||||
_dns_cache_lock,
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -869,7 +869,6 @@ class TestFetchPop3Retry:
|
||||
@pytest.mark.asyncio
|
||||
async def test_retries_on_eof_error(self, mock_poplib, _mock_resolve):
|
||||
"""EOF error on first attempt triggers a retry; second attempt succeeds."""
|
||||
import asyncio
|
||||
import poplib as real_poplib
|
||||
|
||||
# First call raises EOF; second succeeds
|
||||
@@ -910,9 +909,7 @@ class TestFetchPop3Retry:
|
||||
account = _make_account(protocol="pop3_ssl")
|
||||
proc = MailProcessor(account, "secret")
|
||||
|
||||
with patch(
|
||||
"app.services.mail_processor.asyncio.sleep", new_callable=AsyncMock
|
||||
):
|
||||
with patch("app.services.mail_processor.asyncio.sleep", new_callable=AsyncMock):
|
||||
with pytest.raises(MailFetchError):
|
||||
await proc._fetch_pop3_emails(10, set())
|
||||
|
||||
|
||||
@@ -1945,7 +1945,9 @@ class TestNotificationBackoff:
|
||||
account = _make_account(delivery_method=DeliveryMethod.SMTP, **overrides)
|
||||
account.debug_logging = False
|
||||
account.debug_logging_run_count = 0
|
||||
account.error_notification_sent = overrides.get("error_notification_sent", False)
|
||||
account.error_notification_sent = overrides.get(
|
||||
"error_notification_sent", False
|
||||
)
|
||||
account.status = MagicMock(value="active")
|
||||
return account
|
||||
|
||||
@@ -1995,7 +1997,10 @@ class TestNotificationBackoff:
|
||||
mock_send_notification = AsyncMock(return_value=1)
|
||||
|
||||
with (
|
||||
patch(f"{MODULE}.async_session_maker", side_effect=[maker(), session_maker_side_effect()]),
|
||||
patch(
|
||||
f"{MODULE}.async_session_maker",
|
||||
side_effect=[maker(), session_maker_side_effect()],
|
||||
),
|
||||
patch(f"{MODULE}.engine", AsyncMock()),
|
||||
patch(f"{MODULE}.decrypt_credential", return_value="pw"),
|
||||
patch(f"{MODULE}.MailProcessor", return_value=mock_processor),
|
||||
|
||||
Reference in New Issue
Block a user