마루옵스서버 · 네트워크 · AI 기술 노트

소개문의

[Python 개발 환경 02] uv 사용법: Python 선택·의존성·잠금 파일·환경 복원

데스크톱 컴퓨터·키보드·태블릿이 놓인 작업 공간

참고 사진 · 데스크톱 컴퓨터·키보드·태블릿이 놓인 작업 공간 · 사진: William Iven firmbee / 원본 / CC0 · 목록용 크기 조정

프로젝트를 넘겨받았을 때 “어떤 패키지를 설치했더라?”부터 묻지 않으려면, 설치 결과뿐 아니라 설치 의도를 남겨야 합니다. uv는 Python 선택, 프로젝트 의존성, 잠금 파일, 실행 환경 동기화를 한 흐름으로 묶어 줍니다. venv에서 하던 일을 버리는 것이 아니라, 환경을 만드는 절차를 더 명시적으로 관리하는 쪽에 가깝습니다.

Python 개발 환경 · 01 선택과 venv · 02 uv · 03 conda · 04 웹 개발 · 05 데이터·AI · 06 OCR·서비스 분리

이 글의 목차

파일 네 개의 역할을 구분한다

파일·디렉터리역할Git 관리
pyproject.toml프로젝트 이름, Python 지원 범위, 직접 의존성, 개발 도구포함
uv.lock의존성 해석 결과와 패키지 출처·아티팩트 정보이 연재의 애플리케이션에서는 포함
.python-version로컬에서 선택할 Python 버전 힌트포함
.venv/현재 머신에서 만들어진 실제 실행 환경제외하고 다시 생성

uv.lock은 Python 패키지를 재현하는 중요한 재료지만, OS 이미지·GPU 드라이버·DB·모델 데이터까지 고정하는 파일은 아닙니다. 또한 .python-version에 3.12만 적으면 패치 버전까지 하나로 고정한 것은 아닙니다. 운영 재현성에 필요한 수준에 따라 Python 패치와 OS 이미지도 기록합니다.

1. Ubuntu·Rocky 공통으로 uv를 설치한다

2026년 10월 18일 이 글의 예제를 확인한 uv는 0.13.1입니다. 아래는 해당 버전 설치 스크립트를 내려받는 방식입니다. 설치 파일 내용을 확인한 뒤 일반 사용자 권한으로 실행합니다. 이후 버전은 공식 설치 안내와 변경 내용을 확인해 선택하세요.

curl -LsSf https://astral.sh/uv/0.13.1/install.sh -o uv-install.sh
less uv-install.sh
sh uv-install.sh
source "$HOME/.local/bin/env"
uv --version

설치 스크립트 접근이 제한된 망에서는 공식 PyPI 패키지를 전용 부트스트랩 venv에 설치하는 방법도 있습니다. 검증 작업에서는 이 경로를 사용했습니다. 아래의 마지막 줄처럼 실행 파일의 전체 경로로 호출할 수 있고, 시스템 Python 영역은 바꾸지 않습니다.

python3.12 -m venv "$HOME/.local/share/uv-bootstrap"
"$HOME/.local/share/uv-bootstrap/bin/python" -m pip install 'uv==0.13.1'
"$HOME/.local/share/uv-bootstrap/bin/uv" --version

본문의 이후 명령은 uv가 PATH에 있는 경우를 기준으로 합니다. 부트스트랩 방식을 사용했다면 uv 대신 위 실행 파일 경로를 사용하거나 해당 실행 파일만 사용자 bin에 연결하세요. 부트스트랩 venv 전체를 프로젝트 Python처럼 쓰는 것은 아닙니다.

2. 프로젝트와 Python을 선택한다

uv python install 3.12
uv init --app --python 3.12 uv-demo
cd uv-demo
uv python pin 3.12

OS에서 준비한 Python 3.12를 그대로 쓸 수도 있고, uv가 관리하는 Python을 설치할 수도 있습니다. uv python install이 설치하는 관리형 실행기는 시스템의 /usr/bin/python3와 따로 관리됩니다. uv의 Python 설치 안내에서 배포 방식과 지원 플랫폼을 확인할 수 있어요.

3. pyproject.toml에 의존성을 나눈다

생성된 pyproject.toml을 아래 예제로 맞춥니다. Python 범위를 3.12 계열로 제한한 것은 이 연재의 공통 실습 조건이며, 모든 프로젝트에 이 범위를 그대로 적용해야 한다는 뜻은 아닙니다. 상위 버전 지원은 핵심 패키지와 테스트를 확인하며 넓힙니다.

[project]
name = "uv-demo"
version = "0.1.0"
requires-python = ">=3.12,<3.13"
dependencies = ["requests>=2.32,<3"]

[dependency-groups]
dev = ["pytest>=8,<10", "ruff>=0.11,<1"]
notebook = ["ipykernel>=6,<8"]

일반적인 변경은 uv add requests, uv add --dev pytest ruff, uv add --group notebook ipykernel처럼 할 수 있습니다. 위 파일을 이미 작성했다면 같은 의존성을 다시 추가할 필요는 없어요. 직접 편집한 명세를 다음 단계에서 잠그고 설치합니다.

dev 그룹은 기본 설치 대상에 포함되지만 notebook 같은 다른 그룹은 선택해 설치합니다. 단, 그룹을 나눴다고 서로 다른 Python 환경이 되는 것은 아닙니다. 잠금 해석 때 그룹·extras의 호환성을 함께 고려하므로 서로 충돌하는 대형 프레임워크를 그룹 이름만 나눠 한 프로젝트에 담지 않습니다. 의존성 그룹 안내와 의존성 해석 규칙을 참고하세요.

4. 잠그고 실행하고 검사한다

먼저 main.py에 실행기와 requests 버전을 출력하는 다음 내용을 넣고, 테스트 파일도 저장합니다.

import sys

import requests

print(sys.executable)
print("requests", requests.__version__)

tests/test_env.py

import sys

import requests


def test_project_interpreter():
    assert sys.prefix != sys.base_prefix


def test_requests_imports():
    assert requests.__version__
uv lock
uv sync --locked
uv run --locked python -c 'import sys, requests; print(sys.executable); print(requests.__version__)'
uv run --locked python main.py
uv run --locked python -m pytest
uv pip check

uv run은 실행 전에 필요한 환경 동기화를 수행할 수 있으므로 매번 activate를 할 필요가 없습니다. 반대로 uv pip install로 임의 설치한 패키지는 프로젝트 의존성 선언을 대신하지 못하고, 다음 sync에서 제거될 수 있습니다. 팀 프로젝트의 의존성 변경은 uv add나 명세 수정으로 남깁니다.

–locked와 –frozen을 같은 뜻으로 쓰지 않는다

명령용도
uv sync –locked명세와 잠금 파일이 맞는지 확인하고, 잠금 갱신이 필요하면 실패. CI에서 불일치 발견에 유용
uv sync –frozen잠금 파일을 갱신하지 않으며 최신 명세와 맞는지 검사하지 않고 기존 잠금 사용
uv sync –locked –no-default-groups기본 dev 그룹 없이 애플리케이션 의존성만 동기화
uv sync –locked –no-default-groups –group notebook기본 dev 대신 notebook 그룹을 명시적으로 포함

“잠금 파일을 바꾸지 않는다”는 공통점만 보고 옵션을 섞어 쓰면 pyproject 변경 누락을 놓칠 수 있습니다. 이 연재의 CI 예제는 --locked를 사용합니다. 세부 동작은 잠금과 동기화 문서를 기준으로 확인했습니다.

5. 환경을 복원하고 패키지를 업데이트한다

새로 받은 저장소에서 pyproject.toml·uv.lock·.python-version을 확인한 뒤 uv sync --locked를 실행합니다. 복원 테스트를 할 때는 원본 코드 디렉터리를 지우지 말고 별도의 새 체크아웃이나 복사본에서 확인하세요.

# 프로젝트 루트에서 선택한 패키지만 업데이트 검토
uv lock --upgrade-package requests
git diff -- pyproject.toml uv.lock
uv sync --locked
uv run --locked python -m pytest

업데이트 전후 테스트를 보고 명세와 잠금 파일을 함께 커밋합니다. uv의 장점은 설치 명령이 짧은 것뿐 아니라, 의존성 변경을 코드 리뷰 대상으로 남기기 쉽다는 데 있어요. 반면 네이티브 패키지·특정 채널 조합이 중심이면 다음 03 conda도 비교해 보세요.

연재 예제 파일 내려받기 · venv·conda 명세와 uv·웹·데이터·OCR 예제 소스, 확인한 uv 잠금 파일을 묶었습니다. 각 프로젝트 디렉터리에서 실행하며 OS 패키지는 본문의 절차로 별도 준비합니다.

댓글

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

닉네임·이메일·댓글 내용·IP 주소·브라우저 정보는 댓글 게시 및 관리에 사용됩니다. 이메일과 접속 정보는 공개 댓글에 표시하지 않습니다. 개인정보 요청은 운영자 이메일로 보내 주세요. 개인정보처리방침