
uv 0.12에서 main.py 전제 CI를 탐지하는 Python
요약
uv 0.12 업데이트로 인해 프로젝트 기본 구성이 패키지 기반으로 변경됨에 따라, 기존의 main.py 실행 방식이 CI 환경에서 문제를 일으킬 수 있습니다. 이를 탐지하고 해결하기 위한 Python 스크립트와 올바른 프로젝트 구성 방법을 제안합니다.
핵심 포인트
- uv 0.12부터 기본 프로젝트 구조가 src 레이아웃 및 패키지 기반으로 변경됨
- 기존 main.py 실행 방식은 패키지 진입점(entry point)을 활용하지 못함
- CI/CD 워크플로우 내 구형 실행 명령어를 탐지하는 Python 스크립트 활용 권장
- 패키지화가 필요 없는 경우 uv init --no-package 옵션 사용 가능
uv 0.12로 올릴 때, 의존성 해결보다 먼저 CI를 보는 것이 좋다. uv init의 기본 설정이 패키지 구성으로 돌아갔기 때문이다. 이전의 main.py 전제를 남겨두면, 로컬에서는 알아차리지 못하고 CI만 오래된 진입점(entry point)을 실행하게 된다.
7월 28일에 공개된 uv 0.12.0에서는 uv init example이 src/example과 uv_build를 가진 패키지를 기본으로 생성한다. 또한 uv run example을 위한 project.scripts도 포함된다. 기존 프로젝트가 자동으로 바뀌지는 않지만, 템플릿을 업데이트한 리포지토리나 신구 절차가 섞인 monorepo는 주의가 필요하다.
나는 이런 이행 과정에서 README보다 먼저 .github/workflows를 연다. uv run main.py가 한 줄이라도 남아 있으면 실행 대상이 옛날 상태 그대로이기 때문이다. 이번에도 의사 프로젝트(pseudo project)를 두 개 만들어 검사했고, 오래된 진입점을 포함한 쪽만 실패하게 만들 수 있음을 확인했다.
0.11 계열까지의 기본 설정에서는 main.py를 배치하는 "패키지화하지 않는" 구성이 만들어졌다. 0.12에서는 다음과 같은 구성이 기본이 된다.
| 관점 | 이전 기본값 | uv 0.12 기본값 |
|---|---|---|
| 구현 위치 | main.py | src/<package>/ |
| 빌드 시스템 (build system) | 없음 | uv_build |
| 실행 진입점 | uv run main.py | uv run <project.scripts의 이름> |
| 테스트에서의 import | 프로젝트를 자동으로 install 하지 않음 | 패키지로 import 가능 |
기존의 스크립트형 프로젝트를 유지하고 싶다면 uv init --no-package를 선택하면 된다. 문제가 되는 것은 패키지 구성임에도 실행 명령어만 main.py인 채로 남아 있는 케이스다. uv run main.py는 "패키지의 console script를 실행한다"는 의미가 아니다. 파일을 직접 지정하고 있는 것이다.
CI를 고치기 전에, 먼저 구형 진입점을 참조하고 있는 곳만 찾아낸다.
다음 스크립트는 uv_build를 사용하면서, 동시에 src/<정규화된 프로젝트명>/__init__.py가 있는 리포지토리만을 대상으로 한다. GitHub Actions, Makefile, Dockerfile, scripts/ 안에 있는 python main.py 또는 uv run main.py를 발견하면 종료 코드 1을 반환한다. Python 3.11 이후 버전에서 동작한다.
#!/usr/bin/env python3
from __future__ import annotations
import argparse
...
예를 들어 workflow에 다음과 같은 내용이 있다면, 출력은 다음과 같다.
- run: uv run main.py
uv 0.12 packaged project still runs main.py:
.github/workflows/test.yml:2: - run: uv run main.py
동일한 구성에서 uv run demo-app만 배치한 fixture에서는 아무것도 출력하지 않고 종료되었다. 검사 대상을 uv_build와 src/ 양쪽 모두로 좁혔기 때문에, 기존의 단발성 스크립트까지 일괄적으로 중단시키지는 않는다.
패키지로 키워나갈 생각이라면, pyproject.toml의 [project.scripts]에 진입점을 두고, workflow는 uv run <script-name>에 맞춘다. 코드를 import하여 테스트한다면 이 형태가 경로(path) 처리 방식도 통일된다.
단발성 운영 스크립트라면 굳이 패키지화할 이유는 없다. uv init --no-package로 만들고 main.py를 진입점으로 명시하는 것이 읽는 사람에게도 의도를 전달하기 좋다. 이 부분을 모호하게 둔 채 두 명령어를 모두 두면, CI와 개발자의 터미널에서 서로 다른 진입점이 자라나게 된다.
uv 0.12의 변경은 신규 프로젝트를 일반적인 Python 패키지로 시작하기 쉽게 만드는 것이다. 다만, main.py에서 src/로의 이동은 단순히 디렉토리 이름의 차이로 끝나지 않는다. 실행 진입점, 테스트의 import, CI 명령어까지 함께 다시 결정해야 하는 경계점이 된다.
업그레이드 시에는, 먼저 uv.lock을 업데이트하기 전에 진입점을 하나로 통일한다. 이 검사를 CI (지속적 통합)에 한 번 넣어두면, 새로운 템플릿과 예전의 workflow (워크플로)가 조용히 뒤섞이는 사고를 방지할 수 있다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기