파이썬 호환성 해결 — asyncio.get_event_loop + Pydantic class Config
요약로컬 Python 3.14에서 ai-analysis test_main.py 4건이 asyncio.get_event_loop() 비호환(RuntimeError: no current event loop)으로 실패하던 문제를 해결한다. 4건을 asyncio.run()으로 교체하고, Pydantic V2.0 deprecated class Config:를 model_config = SettingsConfigDict로 마이그레이션. 3.12(CI)·3.13(Docker)·3.14(로컬) 공통 동작 입증, Critic 0건, CI 38 pass / 0 fail.
날짜
영향도보통
목표
- 로컬 Python 3.14에서
services/ai-analysis/tests/test_main.py의TestStartupShutdownEvents4건이 실패하는asyncio.get_event_loop()비호환을 해결한다. - CI는 Python 3.12라 통과하지만, Dockerfile 3.13·로컬 3.14 간 호환성 격차를 정리해 3.12~3.14 공통 동작을 보장한다.
배경
- Sprint 191 이월 신규 시드:
test_main.py4건이 로컬 Python 3.14에서RuntimeError: There is no current event loop in thread 'MainThread'로 실패했다(sprint-191 §이월). CI는 Python 3.12라 통과해 빌드는 무관했으나, 로컬 개발 환경(3.14)과 CI(3.12)·Docker(3.13) 간 버전 격차가 잠재 리스크로 남아 있었다. - 원인: Python 3.10+에서
asyncio.get_event_loop()는 실행 중 루프가 없을 때 deprecation 경고를 거쳐, 3.14에서는 현재 루프가 없으면 더 이상 자동 생성하지 않고RuntimeError를 던진다. 테스트가get_event_loop().run_until_complete()패턴으로 coroutine을 직접 실행하던 4곳이 이 변경에 노출됐다. - 부수적으로
src/config.py의 Pydanticclass Config:(V1 스타일)가 V2.0에서 deprecated되어(PydanticDeprecatedSince20) V3.0 제거 예정 경고를 발생시켰다.
결정
D1. 범위 확정 — 코드 호환성 수정에 집중, CI 버전 상향은 제외 (사용자)
- 착수 조사로 3건의 호환성 문제를 재현·확정: ① test_main.py 4건 실패 ② config.py Pydantic deprecation ③ pytest_asyncio 내부 경고.
- 사용자에게 "CI Python 3.12 → 3.13(Dockerfile 정합) 상향" 포함 여부를 질문 → 제외 확정. 근거: 블라스트 반경(전 Python 파이프라인 재검증)이 크고, 버전 정합은 별도 스프린트로 분리하는 것이 안전.
D2. asyncio 패턴 — asyncio.run() 채택
asyncio.get_event_loop().run_until_complete(coro)→asyncio.run(coro).- 각 테스트가 독립 coroutine(
startup_event()1건 /shutdown_event()3건)을 1회 await하는 구조라, 매번 새 루프를 생성·종료하는asyncio.run()이 가장 적합.new_event_loop()수동 관리보다 간결하며 3.12~3.14 공통 동작.
D3. Pydantic V2 마이그레이션 — SettingsConfigDict
class Config: env_file = ".env"→model_config = SettingsConfigDict(env_file=".env"). import에SettingsConfigDict추가. 동작은.env로드로 동일, deprecation 경고만 제거.@field_validator등 기존 로직 무변경.
D4. pytest_asyncio 경고 — 범위 외 (문서화만)
get_event_loop_policy/set_event_loop_policy경고(잔존 19건)는 pytest-asyncio 0.26.0 라이브러리 내부 호출이라 우리 코드에서 수정 불가. Python 3.16 제거 예정으로 즉시성 없음. 라이브러리 상위 버전에서 자연 해소될 잔존 경고로 기록.
구현
구현 커밋 (2커밋, PR #337 squash → 5370c78)
4d21d18fix(ai-analysis) — Python 3.14 asyncio.get_event_loop 비호환 해결 (test_main 4건):asyncio.run()교체 (startup 1·shutdown 3)b1d0554refactor(ai-analysis) — Pydantic class Config → SettingsConfigDict (V2 마이그레이션)
검증
- 로컬 (Python 3.14):
pytest tests/ -q→ 327 passed, 커버리지 99.09%(게이트 97%+),config.py100%. - 우리 코드 DeprecationWarning 0건:
PydanticDeprecatedSince20(config.py) 제거 확인. 잔존 19건은 전부 pytest_asyncio 내부get_event_loop_policy(범위 외, D4). - ruff: lint(src+tests)
All checks passed!· format --check(src) 통과. - Critic:
codex review --base main— 이슈 0건("변경은 Pydantic 설정 구문 갱신과 테스트 이벤트 루프 접근을 asyncio.run으로 교체한 것에 한정. 기존 코드/테스트를 깨뜨릴 동작 없음"). - CI #337: Failed 0 / Passed 38. ai-analysis 전 잡 SUCCESS — Quality(ruff)·Test AI Analysis(Python 3.12)·Build AI Analysis Service(Docker 3.13)·Trivy. → 3.12·3.13·3.14 공통 동작 입증.