√ 패키지 관리 변천사
√ 빠르고 효율적인 관리를 위한 uv 패키지 관리 소개
√ 예제 : uv 패키지 관리를 이용해 fastapi 프로젝트 생성해보기
서론
업무를 하다 보면 시간은 제한되어 있고 처리해야 할 일은 산더미다. 결국 업무를 자동화 하거나 효율 좋게 하기 위한 고민을 하고 방법을 찾다 보면 python 이라는 것은 자연스럽게 접하게 되는 언어 중 하나가 된다.
python 을 이용해 하나 둘 작업을 하다 보면 처음에는 일 처리 하기에 급급해 여기 저기 산재하게 벌려 놓게 되는데, 시간이 좀 지나면 이렇게 어질러진 코드나 기능들을 모아서 정리할 때도 생기고 그러다 보면 자그마한 python 프로젝트가 되기도 한다.
이렇게 만들어진 작은 python 프로젝트를 가지고 활용을 하려다 보면 환경이 바뀌거나 주변의 또 다른 이와 공유하는 과정에서 발생하는 환경 불일치로 인해 문제가 발생하는 경우를 경험하게 된다.
그래서 인가? 어느샌가 python 은 패키징 및 배포 하기 까다로운 언어 중 하나로 인식 되어버린 측면이 있다.
이는 나만 경험한 것이 아닌 듯 python 의 패키지 관리와 관련해서는 pip
, setuptools
, conda
, poetry
등 다양한 패키지 관리 방법들이 등장하였는데, 아래의 이미지가 이러한 패키지 관리의 어려움을 잘 나타낸 것 같다.

그럼 실제로 현재까지 주로 사용되어 왔던 python 패키지 관리 도구에 대해 간단히 살펴보자.
도구/기술 | 등장시기 | 등장 배경 및 목적 | 장점 | 단점 |
---|---|---|---|---|
distutils | 1991년 | Python 패키지를 배포하고 설치하기 위한 초기 배포 도구로 Python 표준 라이브러리에 포함 | - 기본적인 패키징 지원 - Python 표준 라이브러리 일부 |
- 의존성 관리 불가 - 제한된 기능 - 유지 보수 중단 |
PyPI | 2003년 | Python 패키지를 중앙 저장소로 관리하여 패키지 배포 및 검색을 용이하게 하기 위해 등장 | - 중앙 저장소로서의 표준 - pip 등과의 강력한 통합 |
- 패키지 검증 부족 |
setuptools | 2004년 | distutils의 기능 확장을 위해 등장, 의존성 관리 및 배포 자동화를 지원 | - 의존성 관리 지원 - easy_install 제공으로 초기 패키지 설치 간소화 |
- easy_install 의 한계로 pip 등장- 복잡한 설정 |
buildout | 2006년 | 복잡한 Python 애플리케이션을 재현 가능한 환경으로 빌드 및 배포하기 위해 등장 | - 복잡한 배포 환경 관리에 적합 - 자동화된 빌드 지원 |
- 설정이 복잡 - 현대 개발 환경에서는 사용 빈도 감소 |
virtualenv | 2007년 | 프로젝트 간 Python 패키지 충돌 방지를 위한 독립적인 가상환경 생성 도구 | - 경량 가상환경 관리 - pip과 호환성 우수 |
- 가상환경만 관리 가능 - Python 3.3 이후 venv 로 대체 추세 |
pip | 2008년 | easy_install 의 한계를 극복하기 위해 등장, Python의 표준 패키지 설치 도구로 발전 |
- 직관적인 사용법 - PyPI와의 강력한 호환성 - 의존성 트리 설치 지원 |
- 가상환경 관리 기능 없음 - 의존성 충돌 해결 어려움 |
conda | 2012년 | 데이터 과학 및 과학 컴퓨팅 환경을 위한 패키지 및 가상환경 통합 관리 도구 | - Python 외의 패키지 관리 가능 (C, R 등) - 빠른 환경 복제 지원 |
- 무거운 패키지 크기 - PyPI와 호환성 이슈 가능성 |
pyproject.toml | 2016년 | Python 빌드 시스템의 표준화를 위해 등장, 빌드 도구 간 일관성 제공 | - 패키징 표준화 - 다양한 빌드 도구 지원 (poetry, flit 등) |
- 초기 도입 시 혼란 - 일부 도구와 호환성 이슈 가능성 |
flit | 2016년 | Python 패키지 빌드와 배포를 간소화하기 위해 등장 | - 간단한 설정 - 빠른 빌드 및 배포 - pyproject.toml 기반 |
- 복잡한 의존성 관리 부족 - 대규모 프로젝트에는 적합하지 않음 |
pipenv | 2017년 | pip 과 virtualenv 의 기능을 통합하여 간편한 의존성 및 가상환경 관리 지원 |
- Pipfile 과 Pipfile.lock 으로 안정성 확보- 가상환경 자동 생성 |
- 속도 저하 문제 - 대규모 프로젝트에서 불안정성 보고됨 |
poetry | 2018년 | Python 패키징과 의존성 관리를 간소화하고 일관된 개발 워크플로우 제공 | - 의존성 자동 관리 및 잠금 파일 지원 - 가상환경 자동 관리 - 배포까지 지원 |
- 초기 속도 이슈 - 기존 pip와의 호환성 문제 가능 |
uv | 2024년 | pip 대비 빠른 패키지 설치 속도와 효율적인 캐시 관리를 위해 등장 (Rust 기반) | - 매우 빠른 설치 속도 - 효율적인 캐시 및 PEP 668 호환성 |
- 새로운 도구로 커뮤니티 지원 제한적 - 일부 환경에서 호환성 문제 발생 가능성 |
위에 정리해둔 표를 바탕으로 패키지 관리 관련 발전 흐름을 요약하면 아래와 같다.
- 초기 배포 및 관리 (2000~2004)
distutils
로 기본 배포는 가능했으나 기능적 한계 →setuptools
로 확장PyPI
등장으로 중앙 패키지 저장소 등장buildout
은 복잡한 배포 환경을 위해 등장
- 패키지 설치와 가상환경 관리 (2008~2012)
pip
의 등장으로 표준화된 패키지 설치 도구 확보virtualenv
로 독립적인 환경 관리 가능- 데이터 과학 분야(빅데이터, AI 등)에서는
conda
가 확산
- 현대 패키징 표준화 (2016~)
pyproject.toml
로 패키징 표준화 시작 (PEP 518)filt
,pipenv
,poetry
로 다양한 패키징/의존성 관리 방식 등장uv
는 빠른 속도와 캐시 효율성으로 새로운 트렌드 선도
Python이 등장한 것이 1991년이고, 실질적으로 사용률이 높아지기 시작한 것이 빅데이터와 인공지능 등으로 각광 받기 시작한 2008년경부터인 점을 고려할 때, python 의 패키지 관리 도구 변천사는 참으로 역동적으로 변해온 것 만은 확실한 것 같다.
본론
서론이 길게 돌아왔는데, 이번에 다루고자 하는 내용은 앞에서 끝 부분에 잠시 등장한 uv
라는 패키지 관리 도구에 대한 이야기를 해보고자 한다.
Rust 를 기반으로 만들어진 Python 패키지 관리 도구인 uv
는 astral-sh/uv
의 github
Repository에 0.0.5 버전(게시글 작성 일자 기준 0.5.28 버전이 최신 버전)으로 최초 Releases 된 시기가 2024년 02월 16일인 만큼 안된 신생 패키지 관리 도구임에도 불구하고 주목 받는 패키지 관리 도구가 되고 있다.
이에 대한 이유는 아래의 이미지와 링크 본문을 참조 보면 좀 더 명확하게 알 수 있는데, 바로 python 버전 관리 및 의존성 관리가 용이하고 속도가 빠르다는 점이다.


위의 그림만 참고해 보더라도 poetry
에서 0.99초가 걸리는 작업이 uv
에서는 0.06초 만에 해결이 될 수 있는 것을 확인 할 수 있다. 그 외에도 링크 본문을 통해 확인해보면 cpu 를 사용 역시 효율적으로 하고 있음이 확인된다.
uv를 설치해보다
그러나 자신의 python 프로젝트를 관리하는 데 있어 스스로 확인하는 부분도 없이 그저 "누군가가 좋다니까 좋겠지" 라고 검증 없이 신봉하는 것은 옳지 않을 수도 있기에 직접 uv 라는 패키지 관리 도구를 설치해보기로 했다.
테스트로 설치해 볼 환경은 aws(amazon web services)
의 lightsail
서비스 중 512MB 메모리, 20GB SSD, 2개의 vCPU
사양을 갖는 월 5$
짜리 개발 목적으로 생성해 둔 인스턴스에서 진행해 보기로 했고, github 및 doc 사이트 내 설명되어 있는 대로 설치 명령어를 이용해 shell 상에서 직접 설치를 진행하였는데, 설치 완료 메시지(everything's installed!
)를 보기까지 5초가 소요되지 않은 듯 했다.
$ curl -LsSf https://astral.sh/uv/install.sh | sh
downloading uv 0.5.28 x86_64-unknown-linux-gnu
no checksums to verify
installing to /home/ubuntu/.local/bin
uv
uvx
everything's installed!
설치 완료까지 5초가 채 소요되지 않았다.
설치 완료 후 uv 정상 동작 확인
설치가 완료된 이후 정상적인 동작을 확인하기 위해 uv 명령어 실행 및 도움말을 해보니, 프로젝트 생성부터 의존성 추가/제거, 환경 동기화, python 및 pip 관리부터 가상 환경의 생성까지 다양한 기능을 지원하고 있음을 확인해 볼 수 있다.
$ uv --help
An extremely fast Python package manager.
Usage: uv [OPTIONS] <COMMAND>
Commands:
run Run a command or script
init Create a new project
add Add dependencies to the project
remove Remove dependencies from the project
sync Update the project's environment
lock Update the project's lockfile
export Export the project's lockfile to an alternate format
tree Display the project's dependency tree
tool Run and install commands provided by Python packages
python Manage Python versions and installations
pip Manage Python packages with a pip-compatible interface
venv Create a virtual environment
build Build Python packages into source distributions and wheels
publish Upload distributions to an index
cache Manage uv's cache
self Manage the uv executable
version Display uv's version
help Display documentation for a command
Cache options:
-n, --no-cache Avoid reading from or writing to the cache, instead using a temporary directory for the duration of the operation [env: UV_NO_CACHE=]
--cache-dir <CACHE_DIR> Path to the cache directory [env: UV_CACHE_DIR=]
Python options:
--python-preference <PYTHON_PREFERENCE> Whether to prefer uv-managed or system Python installations [env: UV_PYTHON_PREFERENCE=] [possible values: only-managed, managed, system, only-system]
--no-python-downloads Disable automatic downloads of Python. [env: "UV_PYTHON_DOWNLOADS=never"]
Global options:
-q, --quiet Do not print any output
-v, --verbose... Use verbose output
--color <COLOR_CHOICE> Control the use of color in output [possible values: auto, always, never]
--native-tls Whether to load TLS certificates from the platform's native certificate store [env: UV_NATIVE_TLS=]
--offline Disable network access [env: UV_OFFLINE=]
--allow-insecure-host <ALLOW_INSECURE_HOST> Allow insecure connections to a host [env: UV_INSECURE_HOST=]
--no-progress Hide all progress outputs [env: UV_NO_PROGRESS=]
--directory <DIRECTORY> Change to the given directory prior to running the command
--project <PROJECT> Run the command within the given project directory
--config-file <CONFIG_FILE> The path to a `uv.toml` file to use for configuration [env: UV_CONFIG_FILE=]
--no-config Avoid discovering configuration files (`pyproject.toml`, `uv.toml`) [env: UV_NO_CONFIG=]
-h, --help Display the concise help for this command
-V, --version Display the uv version
Use `uv help` for more details.
예제 : uv로 fastapi 구성 구축해보기
이제, uv 설치도 정상적으로 된 것 같고, 실제 업무 환경에서 활용해 볼 수 있도록 fastapi 구성 구축을 다음과 같이 테스트 해보기로 했다. 테스트를 목적으로 진행 하는 거니 응답은 hello world 정도만 반환하는 형태로 진행했다.
$ uv init uv_test
Initialized project `uv-test` at `/home/{user}/uv_test`
$ cd uv_test/
~/uv_test$ uv add fastapi --extra standard
Using CPython 3.12.3 interpreter at: /usr/bin/python3.12
Creating virtual environment at: .venv
Resolved 36 packages in 159ms
Prepared 25 packages in 402ms
Installed 34 packages in 37ms
+ annotated-types==0.7.0
+ anyio==4.8.0
+ certifi==2025.1.31
+ click==8.1.8
+ dnspython==2.7.0
+ email-validator==2.2.0
+ fastapi==0.115.8
+ fastapi-cli==0.0.7
+ h11==0.14.0
+ httpcore==1.0.7
+ httptools==0.6.4
+ httpx==0.28.1
+ idna==3.10
+ jinja2==3.1.5
+ markdown-it-py==3.0.0
+ markupsafe==3.0.2
+ mdurl==0.1.2
+ pydantic==2.10.6
+ pydantic-core==2.27.2
+ pygments==2.19.1
+ python-dotenv==1.0.1
+ python-multipart==0.0.20
+ pyyaml==6.0.2
+ rich==13.9.4
+ rich-toolkit==0.13.2
+ shellingham==1.5.4
+ sniffio==1.3.1
+ starlette==0.45.3
+ typer==0.15.1
+ typing-extensions==4.12.2
+ uvicorn==0.34.0
+ uvloop==0.21.0
+ watchfiles==1.0.4
+ websockets==14.2
~/uv_test$ uv add gunicorn
Resolved 38 packages in 171ms
Prepared 2 packages in 25ms
Installed 2 packages in 3ms
+ gunicorn==23.0.0
+ packaging==24.2
~/uv_test$ cat << EOF > app.py
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello World"}
EOF
~/uv_test$ uv run gunicorn --bind 0:8000 app:app --worker-class uvicorn.workers.UvicornWorker &
[2025-02-05 15:13:14 +0900] [358923] [INFO] Starting gunicorn 23.0.0
[2025-02-05 15:13:14 +0900] [358923] [INFO] Listening at: http://0.0.0.0:8000 (358923)
[2025-02-05 15:13:14 +0900] [358923] [INFO] Using worker: uvicorn.workers.UvicornWorker
[2025-02-05 15:13:14 +0900] [358924] [INFO] Booting worker with pid: 358924
[2025-02-05 15:13:15 +0900] [358924] [INFO] Started server process [358924]
[2025-02-05 15:13:15 +0900] [358924] [INFO] Waiting for application startup.
[2025-02-05 15:13:15 +0900] [358924] [INFO] Application startup complete.
실제 설치 소요 시간 및 실행까지 poetry 를 이용해 구축할 때와는 다르게 매우 빠르게 진행할 수 있었고, 동작에도 문제가 없음을 확인했다.
uv로 설치/구동한 fastapi 응답 확인해보기
이제 남은 확인 절차는 실제로 fastapi 가 정상적으로 hello world 응답을 하는지, 응답 속도도 적절히 잘 나와주는지 확인하는 것이다.
~/uv_test$ curl localhost:8000
{"message":"Hello World"}
~/uv_test$ wrk http://localhost:8000
Running 10s test @ http://localhost:8000
2 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 6.02ms 29.53ms 315.57ms 97.46%
Req/Sec 3.14k 498.06 4.12k 79.49%
61240 requests in 10.00s, 8.76MB read
Requests/sec: 6121.96
Transfer/sec: 0.88MB
확인해 정상적으로 동작하고, 적절히 응답하고 있는 것 같다.
결론
확인 과정과 내용만 가지고 uv
만이 정답이라고 말할 수는 없겠다. 다만 자신이 처해있는 환경에 따라 uv
라는 새로운 패키지 관리 도구를 도입할지 검토해 보는 것은 점점 더 다양해지고 용이한 도구가 나오는 시대에 또 다른 선택지이자 해결책이 될 수 있을 것이라 기대해 마지 않는다.
링크
uv : Document - https://docs.astral.sh/uv/
uv : GitHub - https://github.com/astral-sh/uv
토론하기