uv 0.12.23: pyproject.toml 없이 잠금 파일을 쓰는 조건

짧은 답: uv 0.12.23에서는 잠금 파일만으로 의존성을 점검하는 프리뷰 경로를 사용할 수 있다. 실제 환경 복원에는 별도 소스와 설정이 필요하다.

배포 산출물에 uv.lock만 남아 있을 때 의존성 목록을 다시 확인하려면 무엇이 필요할까. 2026년 10월 3일 공개된 uv 0.12.23은 워크스페이스의 pyproject.toml 없이 잠금 파일을 읽는 경로를 넓혔다. sync, export, tree, workspace metadata의 frozen 실행에 적용되는 frozen-lockfile 프리뷰다. 정식 배포된 uv 버전에 들어 있지만, 이 기능의 상태는 여전히 프리뷰다. 0.12.23 공식 릴리스

이 변화는 잠금 파일을 따로 보관하는 배포 파이프라인이나 의존성 점검 작업에 유용하다. 다만 프로젝트 설정과 소스까지 잠금 파일 하나에 담긴다고 생각하면 설치 단계에서 막히기 쉽다. 여기서는 기존 프로젝트를 지우거나 수정하지 않고, 복사본으로 확인할 수 있는 범위부터 살펴본다.

먼저 결정할 것: 목록 확인인가, 실행 환경 복원인가

잠금 파일에 기록된 버전과 의존 관계를 읽는 작업이라면 tree와 export부터 시작하는 편이 좋다. 애플리케이션을 실제로 실행하려면 소스, 빌드 설정, 사용할 Python과 운영체제까지 준비해야 한다. 두 작업의 완료 조건을 구분하면 “목록을 출력했으니 배포도 가능하다”는 판단을 피할 수 있다.

원본 저장소가 그대로 있는 일반 CI에서는 기존의 일관성 검사도 유지하자. --locked는 프로젝트 메타데이터와 잠금 파일이 맞지 않을 때 오류를 내는 반면, --frozen은 최신 상태인지 확인하지 않고 현재 잠금 파일을 사용한다. 새 의존성을 선언하고 잠금 파일 갱신을 빠뜨린 문제를 찾으려면 이 차이가 중요하다. 잠금 및 동기화 문서

버전과 잠금 파일 형식을 함께 확인하기

uv는 Astral이 관리하는 Rust 기반 Python 패키지·프로젝트 관리 도구다. 이 글의 기준은 공식 저장소의 0.12.23 태그다. GitHub 릴리스와 PyPI 배포 날짜를 교차 확인했으며, 릴리스 자체는 사전 배포로 표시되지 않았다. 라이선스는 MIT 또는 Apache-2.0이다. PyPI 배포의 Python 요구 조건은 3.8 이상이지만, 프로젝트가 사용하는 Python 범위는 해당 프로젝트의 요구 조건을 별도로 따라야 한다. PyPI 배포 정보

매니페스트 없는 export와 sync에는 잠금 파일 revision 5 이상이 필요하다. uv 실행 파일을 업데이트했더라도 오래된 잠금 파일의 형식까지 자동으로 바뀌었다고 가정하지 말자. 다음은 원본 디렉터리에서 버전과 헤더를 읽는 예시다. Python 코드는 표준 라이브러리 tomllib이 있는 Python 3.11 이상을 사용한다.

uv --version
python3 - <<'PY'
from pathlib import Path
import tomllib

lock = tomllib.loads(Path("uv.lock").read_text(encoding="utf-8"))
print("version:", lock.get("version"))
print("revision:", lock.get("revision", 0))
print("requires-python:", lock.get("requires-python"))
PY

revision이 낮다면 원본 프로젝트에서 검토한 uv 버전으로 잠금 파일을 다시 생성하고 변경 내용을 확인하자. 헤더 숫자만 손으로 올리는 방식은 필요한 메타데이터를 추가하지 못한다. export와 sync의 형식 조건은 각각 export 변경 기록과 sync 변경 기록에서 확인할 수 있다.

복사본으로 tree와 export부터 살펴보기

아래 예시는 macOS·Linux 셸용이다. 단일 프로젝트의 잠금 파일을 새 임시 디렉터리에 복사하며, 원본 pyproject.toml은 건드리지 않는다. uv 0.12.23이 이미 준비되어 있고, 잠금 파일과 의존성 출처를 검토했다는 전제다. 멀티 프로젝트 워크스페이스라면 대상 멤버를 명시하는 별도 검토가 필요하다.

check_dir="$(mktemp -d)"
cp uv.lock "$check_dir/uv.lock"

uv --directory "$check_dir" tree \
  --frozen --preview-features frozen-lockfile \
  --no-default-groups --universal \
  --offline --no-python-downloads

uv --directory "$check_dir" export \
  --frozen --preview-features frozen-lockfile \
  --no-default-groups --no-emit-local \
  --format requirements.txt \
  --output-file "$check_dir/requirements.txt" \
  --offline --no-python-downloads

printf '검토 디렉터리: %s\n' "$check_dir"

--no-default-groups로 기본 의존성 그룹을 모두 제외하고, export에서는 로컬 패키지를 내보내지 않도록 했다. 생성되는 파일은 외부 의존성 검토용이다. 필요한 개발 그룹이나 extras가 있다면 실제 운영 조건에 맞게 선택해야 한다. 기본값에 맡기는 것보다 무엇을 포함했는지 기록하기 쉽다.

tree --universal은 여러 Python·플랫폼 조건의 해석 결과를 보여 주므로 같은 패키지의 여러 버전이 보일 수 있다. 현재 머신에 전부 설치된다는 뜻으로 읽으면 안 된다. 일반 tree 실행의 인터프리터 탐색과 잠금 파일 지원은 tree 변경 기록, 옵션의 의미는 CLI 문서를 참고하자.

설치 전에 변경 계획만 보기

다음 단계는 같은 복사본에서 sync의 dry-run을 확인하는 것이다. 기존 프로젝트 환경을 대상으로 실행하지 않도록 위에서 출력한 디렉터리를 그대로 사용한다.

uv --directory "$check_dir" sync \
  --frozen --preview-features frozen-lockfile \
  --no-default-groups --no-install-local \
  --dry-run --offline --no-python-downloads

--no-install-local은 현재 프로젝트, 워크스페이스 멤버, 그 밖의 로컬 경로 패키지를 설치 대상에서 제외한다. --dry-run은 잠금 파일과 프로젝트 환경을 변경하지 않고 계획을 보여 준다. 이 예시는 애플리케이션 전체를 복원하는 명령이 아니다. 실제 설치로 진행할 때는 빠진 로컬 패키지와 소스를 다시 포함해야 한다. sync 옵션 설명

네트워크와 Python 자동 다운로드도 막았으므로 필요한 캐시나 인터프리터가 없으면 실패할 수 있다. 이 경우에는 오류에서 부족한 항목을 먼저 확인하자. 성공한 dry-run 역시 설치, import, 애플리케이션 테스트까지 통과했다는 증거는 아니다. 검증 결과에는 수행한 단계를 정확히 적는 편이 좋다.

잠금 파일에 없는 정보 세 가지

  1. 로컬 소스와 빌드 메타데이터. 프로젝트나 경로 의존성을 실제로 설치하려면 해당 파일들이 필요하다. 잠금 파일에 경로가 기록되어 있어도 파일 내용이 복구되지는 않는다.
  2. 일부 저장소 설정. 매니페스트 없는 export에서 --emit-index-url과 --emit-find-links는 사용할 수 없다. 이 설정이 잠금 파일에 기록되지 않기 때문이다. 사설 저장소를 쓰면 별도의 승인된 설정·인증 제공 경로를 유지하자.
  3. 특수한 워크스페이스의 기본 선택. 프로젝트가 없는 루트의 lock-only sync는 그룹을 명시적으로 선택해야 하며, 그룹별 Python 요구 조건도 이용할 수 없는 제약이 있다. 단일 프로젝트 예제를 워크스페이스 전체에 그대로 확대하지 말자.

이 제약들은 sync 구현 설명과 export 구현 설명에 명시되어 있다. 배포 파일을 줄이려는 목적이라면, 먼저 어떤 설정과 소스가 실제 설치에 필요한지 목록을 만드는 것이 순서다.

도입 판단과 되돌릴 기준

추천하는 첫 적용 범위는 배포에 사용한 잠금 파일의 사후 점검이나 별도 의존성 목록 생성이다. 운영 설치 경로에 넣기 전에는 uv 버전, 잠금 파일 revision, 대상 Python·플랫폼, 선택한 그룹·extras를 함께 남기고 기존 경로와 결과를 비교하자. 캐시가 빈 환경에서도 확인해야 로컬 캐시 덕분에 통과한 조건을 발견할 수 있다.

프리뷰 기능은 변경 가능성을 감수하는 선택이다. 이 예시는 전체 프리뷰를 켜는 --preview 대신 기능 이름만 명시한다. 해당 옵션으로 프리뷰 경고를 없애더라도 안정화 상태가 바뀌는 것은 아니다. 기존 매니페스트 기반 경로를 유지해 두고, 설치 대상이나 설정 재현에 차이가 있으면 그 경로로 돌아가는 편이 낫다. 프리뷰 기능 안내

자료 확인: 2026년 10월 6일 UTC. 공식 릴리스·PyPI·문서·변경 기록을 바탕으로 AI의 도움을 받아 작성했다. 명령은 적용 절차를 설명하는 예시이며, 이 글을 위해 uv 설치·동기화·배포 테스트를 실행하지 않았다.

댓글