uv, 궁극의 가상 환경

computer-tool
coding
python
virtual-env
Python 가상 환경은 이걸로 끝이다!
Author

JS HUHH

Published

September 2, 2024

TL; DR

  • Python 가상 환경, 더 이상 헤매지 마세요.

방황은 끝났다.

Python의 가상 환경에는 선택지가 많다. 선택지가 많다는 게 꼭 나쁜 것은 아니다. 다양한 선택지가 있으면, 이용 환경의 차이 및 변화 따라서 유연하게 대응할 수 있게 된다. 다만 (나 같은) 초급 이용자 입장에서는 이 점이 혼란스러울 때가 있다. 그냥 닥치고 선택할 수 있는 ‘간편한’ 무지성적 해결책이 있으면 싶다. 최근 등장한 Rye, Pixi 모두 이런 시도의 한 갈래다. 둘 모두 CLI에서 거의 원스톱에 가깝게 쓸 수 있는 좋은 가상 환경 및 패키지 관리 도구이다. 다만 이들이 모두 conda에 의존하고 있다는 점에서 살짝 거슬리는 대목이 있다.

그리고 Python 버전 3.12부터 pyproject.toml을 활용한 보다 체계적이고 편리한 패키지 설정 및 관리가 도입되었다. 편리한 가상 환경이 이와 같은 흐름 위에 구축된다면 이후의 호환성을 크게 염려하지 않아도 될 것이다. 물론 설정 과정이 복잡하거나 이것저것 따로 깔아야 하는 것도 피했으면 싶다. 예를 들어 Poetry의 경우 다재다능한 패키지 관리를 제공하나 가상 환경을 번들로 제공하지 않는다. (물론 따로 까는게 어렵진 않지만, 역시 초보는 귀찮을 따름이고…)

이 모든 조건과 요구를 만족시키는 가상 환경과 패키지 관리 도구가 있을까? 있다!

uv

사용 조건

macOS와 WSL-Ubuntu이 가정하는 사용 조건이다. 윈도 역시 필요하다면 어렵지 않게 쓸 수 있으리라 짐작한다. (하지만 WSL을 쓸 수 있는 마당에 윈도에서 윈도 네이티브를 고집할 이유가 있을까…)

Here Comes the uv!

Conda가 편리하지만 사설은 사설이다. 예를 들어 한글 이용자라면 matplotlib에서 한글 폰트를 미리 설정해줘야 한다. 아주 번거롭지는 않지만 바쁠 때는 이마저 귀찮을 수 있다. koreanize-matplotlib 패키지는 나눔고딕폰트를 matplotlib의 기본 폰트로 설정해주는 간단한 패키지다. 이 녀석은 conda에는 없고 PyPI에만 있다. uv를 쓰면 이 패키지도 바로 설치할 수 있다.

물론 Pixi나 Rye에서도 PyPI를 통해 패키지를 설치할 수 있다. 아주 번거롭지는 않지만 한번에 떠오르지 않을 때가 있다. 그래서 PyPI를 뼈대로 하는 uv 쪽이 살짝 더 편하다.

uv 개발진의 야심처럼 uv는 pip, pip-tools, pipx, poetry, pyenv, virtualenv를 대체하기 위한 툴이다. 새롭게 뭔가를 만들었다기보다는 기존에 존재하는 툴은 잘 연결해주는 성격이 강하다. 패키지를 pip를 통해 설치하는 것처럼 가상 환경 역시 venv를 그대로 쓰면 된다. 프로젝트 디렉토리 아래 .venv 폴더를 생성하고 그 아래 가상 환경의 요소들이 설치된다. VS Code에서도 이 가상 환경이 쉽게 인식되고 그대로 활용하면 된다.

그리고 Rust로 제작되서 무엇보다도 빠르다. 개발진의 벤치마크가 결코 허언이 아니다.

사용 사례

프로젝트 초기화 및 복원

보다 상세한 내용은 공식 문서를 참고하자. 여기서는 내가 활용하는 간단한 사례를 소개하도록 한다. 이 역시 미래의 나 놈을 위한 것이다. 설치는 고민하지 말고 brew를 이용하자. brew 없이 까는 방법은 링크에 소개되어 있다.

> brew install uv 

이제 프로젝트 폴더를 생성하고 아래와 같이 기초 작업을 해준다.

>  uv init . # 프로젝트 초기화
> uv venv --python 3.12.0 # venv 조건 활성화 및 파이썬 설치  
> uv add jupyter polars # pyproject.toml에 해당 패키지 넣기 

----

> un sync # pyproject.toml 내용 동기화 
  • 프로젝트를 초기화하고, venv를 통해 가상환경을 설치한다. 이떄 파이썬 버전을 지정할 수 있다.
  • 필요한 패키지를 설치한다. add 명령을 활용하면 pyproject.toml에 추가된다.
  • 해당 프로젝트 디렉토리를 github 등을 통해 수입했다면, uv sync를 통해 pyproject.toml의 내용을 해당 로컬 머신에 설치할 수 있다. 즉, 없거나 업데이트된 요소를 갱신하는 명령이다.

가상환경 활성화는 venv와 동일하다.

# 프로젝트 폴더에서 실행 
> source .venv/bin/activate

OS 특정 패키지 설치

OS에 따라서 서로 다른 파이썬 패키지가 필요한 경우가 있다. 대표적으로 torch가 그렇다. 리눅스에서는 nvidia CUDA를, macOS에서는 metal(MPS)를 쓰는 상황을 가정해보자. 토치의 홈페이지에서는 각각 상황에 디해서 pip로 어떻게 설치해야 하는지를 알려준다. 이 내용을 pyproject.toml에 반영하면 된다. 아래의 예를 보자.

pyproject.toml
[project]

name = "test-uv-torch"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.11"

dependencies = [
    "jupyter>=1.1.1",
    "matplotlib>=3.9.2",
    "torch>=2.4.0",
    "torchvision>=0.9.0",
    "torchaudio>=2.4.0"
    ]

[project.optional-dependencies]
cuda = [
    "torch>=2.4.0; sys_platform == 'linux'",
    "torchvision>=0.9.0; sys_platform == 'linux'",
    "torchaudio>=2.4.0; sys_platform == 'linux'"
    ]
  
[tool.uv.sources]
cuda = { url = "https://download.pytorch.org/whl/cu124" }

toml을 좀 들여다 보자.

    "torch>=2.4.0",
    "torchvision>=0.9.0",
    "torchaudio>=2.4.0"

macOS의 경우 sys_platform으로 ’darwin’을 지정하면 된다. macOS의 경우 CPU를 쓰는 상황과 동일하기 떄문에 별달리 OS를 지정하지 않았다.

[project.optional-dependencies]
cuda = [
    "torch>=2.4.0; sys_platform == 'linux'",
    "torchvision>=0.9.0; sys_platform == 'linux'",
    "torchaudio>=2.4.0; sys_platform == 'linux'"
    ]
  
[tool.uv.sources]
cuda = { url = "https://download.pytorch.org/whl/cu124" }

cuda를 쓰는 상황을 가정해서 cuda라는 이름의 별도 옵션을 만들었다. [tool.uv.sources]는 pip로 설치할 때 --index-url의 옵션을 넣어주면 된다. 위 toml의 경우 cuda 12.4를 활용했다. 이렇게 지정해 둔 cuda 옵션으로 Pytorch를 설치하고 싶다면 아래와 같이 실행하면 된다.

> uv sync --extra cuda
  • --extra는 toml 파일에 있는 별도의 의존성 옵션을 이용하겠다는 뜻이다.

requirements.txt 생성

간혹 pyproject.toml이 아닌 requirements.txt가 필요한 경우가 있다. 이 역시 uv를 통해 쉽게 생성할 수 있다.

> uv pip compile pyproject.toml -o requirements.txt