Skip to content

Commit 793878e

Browse files
committed
chore: update datetime usage to use datetime.now(UTC) for consistency across the application
1 parent 6af11c0 commit 793878e

8 files changed

Lines changed: 99 additions & 75 deletions

File tree

backend/app/api/services/ai_exam.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ async def _get_job_result():
108108
return res
109109
else:
110110
raise TypeError("Task result must be a dict")
111-
except Exception as e:
111+
except Exception as e: # noqa: BLE001 - ARQ result failures are retried
112112
last_err = e
113113
await asyncio.sleep(0.05)
114114
if last_err:
@@ -118,7 +118,7 @@ async def _get_job_result():
118118
if job_status == "complete":
119119
response.result = await _get_job_result()
120120
response.completed_at = (
121-
metadata.get("completed_at") or datetime.utcnow().isoformat()
121+
metadata.get("completed_at") or datetime.now(UTC).isoformat()
122122
)
123123
await websocket.send_json(response.dict())
124124
await websocket.close(code=1000)
@@ -153,15 +153,15 @@ async def _get_job_result():
153153
if status_enum is None
154154
else _STATUS_MAP.get(status_enum, "unknown")
155155
)
156-
except Exception:
156+
except Exception: # noqa: BLE001 - status polling is best-effort
157157
current_status = last_sent_status
158158

159159
if current_status and current_status != last_sent_status:
160160
last_sent_status = current_status
161161

162162
if current_status == "complete":
163163
result = await _get_job_result()
164-
completed_at = datetime.utcnow().isoformat()
164+
completed_at = datetime.now(UTC).isoformat()
165165
metadata["completed_at"] = completed_at
166166
metadata["status"] = "complete"
167167
await redis.set(
@@ -228,7 +228,7 @@ async def _get_job_result():
228228

229229
result = await _get_job_result()
230230

231-
completed_at = datetime.utcnow().isoformat()
231+
completed_at = datetime.now(UTC).isoformat()
232232
metadata["completed_at"] = completed_at
233233
metadata["status"] = "complete"
234234
await redis.set(
@@ -248,7 +248,7 @@ async def _get_job_result():
248248
)
249249
await websocket.close(code=1000)
250250
return
251-
except Exception:
251+
except Exception: # noqa: BLE001 - close the WebSocket on an unexpected failure
252252
await websocket.close(code=1011)
253253
return
254254

@@ -311,7 +311,7 @@ async def submit_generate_task(
311311
metadata = {
312312
"user_id": current_user.user_id,
313313
"archive_ids": request.archive_ids,
314-
"created_at": datetime.utcnow().isoformat(),
314+
"created_at": datetime.now(UTC).isoformat(),
315315
"status": "pending",
316316
}
317317
await redis.set(
@@ -328,7 +328,7 @@ async def submit_generate_task(
328328

329329
except HTTPException:
330330
raise
331-
except Exception as e:
331+
except Exception as e: # noqa: BLE001 - translate unexpected backend failures
332332
raise HTTPException(
333333
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
334334
detail=f"Failed to submit task: {e!s}",
@@ -369,7 +369,7 @@ async def delete_task(
369369

370370
except HTTPException:
371371
raise
372-
except Exception as e:
372+
except Exception as e: # noqa: BLE001 - translate unexpected backend failures
373373
raise HTTPException(
374374
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
375375
detail=f"Failed to delete task: {e!s}",
@@ -405,7 +405,7 @@ async def get_api_key_status(
405405
return ApiKeyResponse(has_api_key=has_api_key, api_key_masked=api_key_masked)
406406
except HTTPException:
407407
raise
408-
except Exception as e:
408+
except Exception as e: # noqa: BLE001 - translate unexpected database failures
409409
raise HTTPException(
410410
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
411411
detail=f"Failed to get API key status: {e!s}",
@@ -452,7 +452,7 @@ async def update_api_key(
452452
return ApiKeyResponse(has_api_key=has_api_key, api_key_masked=api_key_masked)
453453
except HTTPException:
454454
raise
455-
except Exception as e:
455+
except Exception as e: # noqa: BLE001 - translate validation and database failures
456456
# Check if it's an API key validation error
457457
if "API key" in str(e) or "authentication" in str(e).lower():
458458
raise HTTPException(

backend/app/api/services/archives.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ async def upload_archive(
116116

117117
except HTTPException:
118118
raise
119-
except Exception as e:
119+
except Exception as e: # noqa: BLE001 - translate storage and database failures
120120
raise HTTPException(
121121
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
122122
detail=f"Failed to upload file: {e!s}",

backend/app/api/services/courses.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ async def _broadcast_discussion(archive_id: int, payload: dict):
188188
for ws in list(sockets):
189189
try:
190190
await ws.send_json(payload)
191-
except Exception:
191+
except Exception: # noqa: BLE001 - a disconnected socket is removed
192192
dead.append(ws)
193193

194194
if dead:
@@ -314,7 +314,7 @@ async def archive_discussion_ws(
314314
return
315315
try:
316316
data = json.loads(raw)
317-
except Exception:
317+
except json.JSONDecodeError:
318318
continue
319319

320320
if not isinstance(data, dict):

backend/app/db/init_db.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import asyncio
12
import os
23
import subprocess
34
import unicodedata
@@ -25,11 +26,13 @@ async def init_db():
2526
# Run Alembic migrations instead of create_all
2627
try:
2728
# Run alembic upgrade head to apply all migrations
28-
result = subprocess.run(
29+
result = await asyncio.to_thread(
30+
subprocess.run,
2931
["uv", "run", "alembic", "upgrade", "head"],
3032
cwd=os.path.dirname(os.path.dirname(os.path.dirname(__file__))),
3133
capture_output=True,
3234
text=True,
35+
check=False,
3336
)
3437
if result.returncode != 0:
3538
print(f"Alembic migration failed: {result.stderr}")
@@ -39,7 +42,7 @@ async def init_db():
3942
await conn.commit()
4043
else:
4144
print("Database migrations applied successfully")
42-
except Exception as e:
45+
except Exception as e: # noqa: BLE001 - migration failure falls back to create_all
4346
print(f"Error running migrations: {e}")
4447
# Fallback to create_all
4548
async with engine.begin() as conn:

backend/app/services/auth.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
from app.core.config import settings
77

88

9-
async def oauth_callback(code: str, state: str = None, stored_state: str = None):
9+
async def oauth_callback(
10+
code: str, state: str | None = None, stored_state: str | None = None
11+
):
1012
"""
1113
Verify CSRF token and handle OAuth callback for NYCU OAuth
1214
"""

backend/app/worker.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import io
22
import logging
3-
from datetime import datetime
3+
from datetime import UTC, datetime
44
from functools import lru_cache
55
from pathlib import Path
6+
from typing import ClassVar
67

78
from arq import create_pool
89
from arq.connections import RedisSettings
@@ -220,7 +221,7 @@ async def publish_event(status: str, *, error: str | None = None):
220221
if not redis or not task_id:
221222
return
222223
try:
223-
fields = {"status": status, "ts": datetime.utcnow().isoformat()}
224+
fields = {"status": status, "ts": datetime.now(UTC).isoformat()}
224225
if error:
225226
fields["error"] = error
226227
stream_key = f"ai_exam:task_events:{task_id}"
@@ -253,7 +254,7 @@ class WorkerSettings:
253254
"""ARQ worker settings"""
254255

255256
redis_settings = RedisSettings.from_dsn(settings.REDIS_URL)
256-
functions = [generate_ai_exam_task]
257+
functions: ClassVar[list] = [generate_ai_exam_task]
257258

258259
max_jobs = 5 # Max concurrent jobs
259260
job_timeout = 600 # Job timeout in seconds

backend/pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,6 @@ dev = [
3434
"pytest-cov>=7.0.0",
3535
"ruff>=0.16.1",
3636
]
37+
38+
[tool.ruff.lint.flake8-bugbear]
39+
extend-immutable-calls = ["fastapi.Depends", "fastapi.Form"]

0 commit comments

Comments
 (0)