# Uv: 의존성이 있는 스크립트 실행하기

> Clean Markdown view of GeekNews topic #22113. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=22113](https://news.hada.io/topic?id=22113)
- GeekNews Markdown: [https://news.hada.io/topic/22113.md](https://news.hada.io/topic/22113.md)
- Type: GN+
- Author: [neo](https://news.hada.io/@neo)
- Published: 2025-07-22T18:34:28+09:00
- Updated: 2025-07-22T18:34:28+09:00
- Original source: [docs.astral.sh](https://docs.astral.sh/uv/guides/scripts/#running-a-script-with-dependencies)
- Points: 14
- Comments: 7

## Summary

**uv**는 Python 스크립트 실행 시 **의존성 관리**와 **가상환경 생성**을 자동화하여, 개발자들이 별도 환경 설정이나 패키지 설치 과정 없이 즉시 작업할 수 있도록 지원합니다. 스크립트별 **인라인 메타데이터**와 다양한 의존성 선언 방식을 제공하며, 필요시 **Python 버전**과 **커스텀 패키지 인덱스** 지정도 유연하게 처리합니다. **Lock 파일**을 통한 환경 고정과 재현성을 강화하여 빠르고 신뢰성 있는 개발 및 배포를 가능하게 합니다.

## Topic Body

- **uv**를 사용하면 Python 스크립트 실행 시 **의존성 관리**를 자동화함
- 별도의 **가상환경 관리** 없이 스크립트별로 환경이 자동으로 생성 및 유지됨
- 필요한 패키지는 **inline metadata** 또는 명령행 옵션 등 다양한 방식으로 선언 가능함
- **Python 버전**과 패키지 관리도 스크립트 단위로 선언 및 자동 조정 가능함
- **Lock 파일**과 의존성 버전 제한 옵션 등으로 재현성과 유지관리성을 높임

---

### 개요

- **uv**는 Python 스크립트 실행 시 해당 스크립트가 필요로 하는 **패키지 의존성**을 자동으로 관리해주는 도구임
- 사용자는 번거로운 **가상환경 생성, 패키지 설치**를 직접 하지 않아도 됨
- 여러 실행 옵션과 **inline metadata** 활용법, 다양한 의존성 선언 방식, 각종 제어 기능을 제공함

### Python 환경과 uv의 역할

- Python은 각각의 설치마다 **고유한 환경**을 가짐
- 일반적으로 **가상환경**을 만들고 관리하는 것이 권장됨
- **uv**는 가상환경을 자동으로 관리하며, **선언적** 방식으로 의존성을 다룸
- 단순한 스크립트는 `uv run example.py`만으로 즉시 실행 가능함
- 표준 라이브러리 사용 시 추가 설정 없이 작동함

### 인자 전달 및 입력 방식

- 스크립트에 **명령행 인자**를 넘길 수 있음
- 표준 입력에서 직접 스크립트 코드를 받아 실행하거나, **here-document** 기능도 지원함

### 프로젝트 환경과 `--no-project` 옵션

- 스크립트가 **프로젝트 폴더**(예: `pyproject.toml`이 있는 곳)에서 실행될 경우, 프로젝트 의존성도 설치됨
- 필요 없다면 `--no-project` 플래그를 스크립트 이름 앞에 넣어 프로젝트 환경을 **무시**할 수 있음

### 스크립트 의존성 선언과 관리

- 외부 패키지가 필요한 경우, 명령행 옵션 `--with`를 이용해 의존성을 지정해서 실행 가능함
- 특정 버전 제약 조건도 지원하며, 여러 의존성도 반복해서 옵션으로 지정 가능함
- 프로젝트 환경에서 추가 의존성을 더할 수 있고, 원하지 않으면 `--no-project`로 제어 가능함

### Inline Script Metadata(PEP 723 방식)

- Python에서는 이제 스크립트 자체에 **의존성이나 Python 버전**을 선언하는 표준 포맷을 지원함
- `uv init --script`로 인라인 메타데이터가 포함된 스크립트를 손쉽게 생성 가능함
- `uv add --script`로 스크립트에 필요한 의존성을 TOML 포맷으로 추가 관리할 수 있음
- 인라인 메타데이터가 있으면, **프로젝트의 의존성은 무시**되고 오직 스크립트 의존성만 적용됨

### Python 버전 선언 및 관리

- 스크립트 내 또는 실행 시 원하는 **Python 버전**을 지정할 수 있음
- 지정된 버전이 없다면 자동으로 다운로드 및 설정됨

### Shebang으로 바로 실행 가능한 스크립트 작성

- shebang(@#!...)을 이용해 `uv run --script` 방식으로 직접 실행 파일 제작 가능함
- 이때도 **의존성 선언** 및 Python 버전 등도 스크립트 상단에서 가능함

### 패키지 인덱스 및 인증 지원

- `--index` 옵션으로 **커스텀 패키지 인덱스** 사용 가능
- index 정보도 메타데이터에 포함됨
- 인증이 필요한 경우 별도 문서 참고 가능

### 의존성 고정(Lock)과 재현성 향상

- `uv lock --script`로 **스크립트 단위**의 Lock 파일 작성 및 관리 가능
- 이후 실행/의존성 추가 시 lock 파일 재사용 및 필요시 갱신됨
- 버전 재현성을 위한 `exclude-newer`(특정 날짜 이후 릴리즈 제외) 옵션 제공
- RFC 3339 타임스탬프로 날짜 지정

### Python 버전 유연성

- 각 실행 시 명령행 옵션으로 **任의의 Python 버전** 사용 지정 가능
- 예시: `uv run --python 3.10 example.py`

### Windows 지원

- `.pyw` 확장자를 가진 스크립트는 윈도우에서 **pythonw**로 실행됨
- GUI 기반의 스크립트도 의존성 함께 실행 가능함

### 참고 문서

- 더 자세한 명령 사용법은 CLI 참조 문서 및 툴 실행/설치 가이드 참고 가능

### 결론

- **uv**는 Python 스크립트의 실행 환경, 의존성, 버전, 패키지 인덱스, 재현성 등을 자동으로 간편하게 관리해 **생산성**과 **신뢰성**을 동시에 높여주는 도구임

## Comments



### Comment 41757

- Author: ihabis02
- Created: 2025-07-24T18:56:08+09:00
- Points: 1

저도 pip에서 uv로 넘어가봤는데 진짜 속도 빠른것 하나만 보고 넘어갈만한 수준이더라고요

### Comment 41730

- Author: idunno
- Created: 2025-07-23T17:36:01+09:00
- Points: 1

자주 올라와서 어제 처음 써봤는데.. 정말 빠르네요. 헐..

### Comment 41727

- Author: ytuniverse
- Created: 2025-07-23T16:34:23+09:00
- Points: 1

uv 관련 포스팅만 여기서 5개 이상 본 것 같네요;;;

### Comment 41721

- Author: pmc7777
- Created: 2025-07-23T13:29:58+09:00
- Points: 1

다른 기능은 제쳐두고, 단순히 속도만으로도 사용 할 이유가 충분합니다.  
다시 pip 쓰라고 하면 절대 못할 정도입니다.  
  
conda의 시스템 패키지 관리는 flake.nix로 대체해서 사용하고 있는데, 공동 작업이나 기존 conda+pip로 유지 관리되던 프로젝트 이외에 개인적으론 앞으로 uv+nix를 사용할 것 같습니다.

### Comment 41694

- Author: xguru
- Created: 2025-07-23T08:03:01+09:00
- Points: 1

[Uv - 러스트로 구현한 초고속 파이썬 패키징 도구](https://news.hada.io/topic?id=13388)  
[UV를 활용한 파이썬 개발 워크플로우 혁신하기](https://news.hada.io/topic?id=21865)  
[uv와 PEP 723으로 Python 스크립트 활용하기](https://news.hada.io/topic?id=21637)  
[uv 1년 사용기: 장단점과 마이그레이션시 고려할 점](https://news.hada.io/topic?id=19313)

### Comment 41691

- Author: ndrgrd
- Created: 2025-07-22T22:30:26+09:00
- Points: 1

최근 대부분의 python 실행을 uv로 대체했는데 정말 빠릅니다.   
완벽히 호환되지 않는 몇몇 고급 기능이 있긴 하지만 대부분의 경우 거의 똑같이 동작합니다.

### Comment 41687

- Author: neo
- Created: 2025-07-22T18:34:29+09:00
- Points: 1

###### [Hacker News 의견](https://news.ycombinator.com/item?id=44641521) 
* "스크립트 의존성 선언" 기능이 정말 유용함을 경험함  
  [공식 가이드 문서](https://docs.astral.sh/uv/guides/scripts/#declaring-script-dependencies)에서 소개하듯, 다음과 같이 Python 코드 최상단에 주석으로 의존성을 명시할 수 있음  
  ```python
  # /// script
  # dependencies = [
  #  "requests<3",
  #  "rich",
  # ]
  # ///
  import requests, rich
  # ... script
  ```
  이 파일을 script.py로 저장한 뒤 "uv run script.py"로 실행하면 명시된 의존성이 마법처럼 임시 가상 환경에 설치되어 곧바로 실행할 수 있음  
  이는 Python의 [PEP 723](https://peps.python.org/pep-0723/)를 구현한 것이며, Claude 4도 이 트릭을 알고 있으므로 “인라인 스크립트 의존성이 포함된 Python 스크립트”를 작성해달라고 프롬프트하면 올바르게 만들어줌  
  예제로 httpx와 click을 사용해 대용량 파일을 다운로드하고 진행률 바를 보여주는 코드 작성을 요청할 수 있음  
  Claude 4 이전엔 이런 기능을 위해 맞춤 프로젝트와 별도 안내가 필요했지만, 이제는 그렇지 않음  
  [자세한 사용 사례](https://simonwillison.net/2024/Dec/19/one-shot-python-tools/)에서도 참고할 수 있음

  * shebang 모드도 정말 유용함을 느낌  
    아래와 같이 스크립트 첫 줄에 shebang을 추가하면 ./script.sh처럼 실행 가능함  
    ```python
    #!/usr/bin/env -S uv run --script
    # /// script
    # dependencies = [
    #  "requests<3",
    #  "rich",
    # ]
    # ///
    import requests, rich
    # ... script
    ```

  * requirements 파일과 같은 형식이면 좋겠다는 바람이 있음  
    만약 그렇게 되면 uv가 없는 사용자를 위해 간단한 주석으로 pip로 동일하게 설치할 수 있는 원라이너도 제공할 수 있기 때문임  
    예시로 `pip install -r <(head myscript.py)`와 같은 접근이 가능할 듯함

  * 실제로 PEP723은 요즘 주목받는 uv뿐 아니라 pipx, hatch에서도 지원 중임  
    그리고 pip-tools 등도 지원 로드맵에 포함되어 있음  
    ([관련 이슈](https://github.com/jazzband/pip-tools/issues/2027) 참고)

  * 처음 봤을 때 requests 옆에 하트 이모지인 줄 알았던 적이 있음

  * 이 방식이 정말 멋지다고 생각함  
    하지만 언젠가는 매직 주석이 아닌 내장 언어 문법으로 채택되었으면 좋겠음  
    주석은 약간 지저분해 보임  
    물론 도구 입장에선 매직 주석이 파싱엔 더 쉽고, Python 코어가 패키징 지식이 많지 않다는 등 구조적 고민이 있다는 것도 알지만, 언젠가는 내장 문법이 생기면 좋겠음

* 이러한 방식에 공감함  
  Python이 requirements.txt 파일이 필수는 아니지만, 관리를 소홀히 하면 기능이 깨지는 불편이 자주 생김이 아쉬움  
  [관련 트윗 참고](https://twitter.com/_damnever/status/1697247813854503250)

* 이 방식에서 겪은 함정을 공유하고 싶음  
  인터넷이 끊겼을 때 라우터를 재시작하는 스크립트에 활용했는데, 의존성 설치 동작이 인터넷 연결에 의존하므로 네트워크가 안 되면 스크립트 자체가 작동 불가해지는 문제가 있음  
  미리 발견하고 의존성 사전 설치로 해결했지만, 나처럼 실수하지 말고 실제 airgapped 환경(네트워크가 완전 차단된 환경)에서는 사용하지 않기를 권장  
  uv 캐시가 있어도 캐시 미스가 날 수 있음

  * `uv run --offline` 옵션 사용 시 캐시된 의존성을 활용해서 새 버전 체크 없이 실행할 수 있음  
    같은 기능이 `uvx`에도 동작함 (`uvx --offline ...`)

  * 의존성이나 venv를 사용할 일이 있다면 최소 한 번은 인터넷 연결에서 실행해야 그 후 오프라인에서도 쓸 수 있는 구조인 것으로 이해함

* 최근 Python 생태계에서 여러 기능들이 점점 잘 맞물려 동작하고 있다는 느낌을 받음  
  Marimo와 uv 스크립트 의존성 조합으로, 다른 팀에서 사용하기 좋은 재현 가능한 리포팅/진단 도구를 만들기 시작함

* uv의 이 기능이 가장 마음에 들어 이 때문에 uv로 갈아타게 됨  
  여러 git-hooks 스크립트들이 각각 별도의 의존성을 가지는데, 이를 메인 venv에 설치하고 싶지 않았음  
  `#!/usr/bin/env -S uv run --script --python 3.13` 한 줄만 추가하면 dev들에게는 brew install uv만 안내하면 됐고, venv를 따로 만들 필요 없이 스크립트 안에서 바로 사용할 수 있게 됨

  * 혹시 `-S` 플래그가 왜 필요한지 아는 사람 있는지 궁금함  
    내 BSD 환경에서는 `/usr/bin/env -S uv run --python 3.11 python`과 `/usr/bin/env uv run --python 3.11 python` 모두 Python shell을 실행해 결과가 똑같다 느꼈음  
    env 매뉴얼을 봐도 명확히 해석되지 않아 유용한 정보라면 듣고 싶음  
    (여기서 -S는 인자를 공백으로 나눠주는 역할임)

  * UV 덕에 원래는 파이썬 대규모 이관 작업을 golang으로 할 계획이었는데, UV 덕분에 이 이관 범위를 줄일 수 있었음  
    특히 작은 스크립트 형태의 작업은 더 이상 이동할 필요가 없어짐

  * 이 기능은 정말 ‘킬러(feature)’라고 확신함

* 의존성 중 Pytorch가 있는 경우엔 이 방식이 조금 제한이 있을 수 있음  
  Uv가 Pytorch 용 [통합 지원](https://docs.astral.sh/uv/guides/integration/pytorch/)을 잘 제공하고 있지만, 스크립트 헤더만으로는 (CPU, CUDA, ROCm 등) 가장 적합한 wheel 인덱스를 명확히 선택하는 방법이 없어 아쉬움

* uv가 자동으로 만들어주는 venv을 VS Code가 쉽게 인식할 수 있었으면 하는 바람이 있음  
  지금은 Python extension이 써드파티 import를 모두 빨간 줄로 표시함  
  임시 해법으로 uv의 Cache 디렉터리에서 수동으로 venv 경로를 찾아 등록하는데, 자주 venv가 재생성되면 또 반복해야 해서 번거로움

  * `uv python find --script "${filePath}"` 명령어로 env 경로를 찾을 수 있음  
    해당 기능을 VS Code에서 자동 감지해 활성화해주는 [확장 프로그램](https://marketplace.visualstudio.com/items?itemName=nsarrazin.pep723-uv-interpreter)을 개발 중임

* UV의 이 기능이 너무 마음에 듦  
  jupyter notebook도 별도 설치 없이 다음과 같이 원라인으로 실행할 수 있음  
  ```bash
  uv run --with jupyter jupyter notebook
  ```
  모든 것이 임시 가상환경에 설치되고, 이후에는 깨끗이 정리됨  
  프로젝트 내에서 실행할 경우 해당 프로젝트의 의존성도 자동 인식함

  * 다만 완전히 ‘깨끗하게’ 정리되는 것은 아니며, uv 캐시 폴더가 계속 커질 수 있음

  * 나 역시 `uv run --with ipython --with boto3 ipython` 식으로 자주 활용 중이며, 정말 시간 절약에 큰 도움이 됨

* 최근 `uv run` 관련해서 발견한 소소한 이슈가 있음  
  스크립트를 프로젝트 폴더 밖에서 실행하면, 실제 스크립트 파일 위치가 아닌 현재 작업 디렉터리에서 pyproject.toml을 찾는 동작이 있음  
  그래서 의존성을 pyproject.toml에 저장한 스크립트는 “uv run path/to/my/script.py” 식으로 외부에서 실행 시 제대로 동작하지 않을 수 있음  
  이 현상은 항상 인라인 의존성을 쓰거나, `--project` 인자를 쓰면 해결할 수 있지만, script 경로를 두 번 입력해야 해서 불편함  
  uv 자체는 매우 훌륭하지만, 이 작은 특성은 꽤 불편하게 느껴짐

* uv 전용 shebang과 인스크립트 의존성 방식을 만족스럽게 사용 중에 있었음  
  여기에 더해 `uv lock --script example.py` 명령어로 스크립트 한 개 전용 lock 파일까지 만들 수 있다는 점이 더욱 인상적임  
  Python 패키징이 20년 넘게 이어졌는데 이렇게 자연스러운 경험이 이제야 등장한 것에 놀라움

  * 단일 스크립트용 lock을 생성하는 사용 사례가 궁금함  
    우리 조직에선 lockfile의 의존성을 `trivy fs uv.lock` 등으로 스캔해, 알려진 CVE가 있는 코드 실행을 예방하는 데에도 활용하고 있음
