byteforce

CPN 한국어 자습서 · 외부 문서 한국어 미러

UV 문서 · Guides

스크립트 실행

Running scripts · 원문: docs.astral.sh/uv/guides/scripts/

아래는 원문을 한국어로 옮긴 미러입니다. 코드·명령은 원문 그대로이며, 가장 최신 정보는 하단 원문 링크에서 확인하세요.

Python 스크립트는 python <script>.py처럼 독립 실행을 목적으로 하는 파일입니다. uv를 사용해 스크립트를 실행하면 환경을 직접 관리하지 않아도 스크립트 의존성(dependency)을 처리할 수 있습니다.

의존성이 없는 스크립트 실행

스크립트에 의존성이 없으면 uv run으로 실행할 수 있습니다:

코드 · 명령
print("Hello world")
코드 · 명령
$ uv run example.py
Hello world

마찬가지로, 스크립트가 표준 라이브러리 모듈에만 의존한다면 추가 작업이 필요하지 않습니다:

코드 · 명령
import os

print(os.path.expanduser("~"))
코드 · 명령
$ uv run example.py
/Users/astral

스크립트에 인수를 전달할 수 있습니다:

코드 · 명령
import sys

print(" ".join(sys.argv[1:]))
코드 · 명령
$ uv run example.py test
test

$ uv run example.py hello world!
hello world!

또한 스크립트를 표준 입력(stdin)으로 읽을 수도 있습니다:

코드 · 명령
$ echo 'print("hello world!")' | uv run -

셸이 here-document를 지원하는 경우:

코드 · 명령
uv run - <<EOF
print("hello world!")
EOF

uv run프로젝트(즉, pyproject.toml이 있는 디렉터리)에서 사용하면, 스크립트를 실행하기 전에 현재 프로젝트를 설치합니다. 스크립트가 프로젝트에 의존하지 않는다면 --no-project 플래그를 사용해 이를 건너뛸 수 있습니다:

코드 · 명령
$ # 참고: `--no-project` 플래그는 스크립트 이름 _앞에_ 제공해야 합니다.
$ uv run --no-project example.py

의존성이 있는 스크립트 실행

스크립트가 다른 패키지(package)를 필요로 하는 경우, 스크립트가 실행될 환경에 해당 패키지를 설치해야 합니다. uv는 수동으로 의존성을 관리하는 오래 유지되는 가상환경(virtual environment) 대신, 필요할 때 환경을 즉석에서 생성하는 방식을 선호합니다. 이를 위해 스크립트에 필요한 의존성을 명시적으로 선언해야 합니다.

예를 들어, 다음 스크립트는 rich를 필요로 합니다:

코드 · 명령
import time
from rich.progress import track

for i in track(range(20), description="For example:"):
    time.sleep(0.05)

의존성을 지정하지 않고 실행하면 이 스크립트는 실패합니다:

코드 · 명령
$ uv run --no-project example.py
Traceback (most recent call last):
  File "/Users/astral/example.py", line 2, in <module>
    from rich.progress import track
ModuleNotFoundError: No module named 'rich'

--with 옵션으로 의존성을 요청하세요:

코드 · 명령
$ uv run --with rich example.py
For example: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100% 0:00:01

특정 버전이 필요한 경우 버전 제약을 추가할 수 있습니다:

코드 · 명령
$ uv run --with 'rich>12,<13' example.py

--with 옵션을 반복하면 여러 의존성을 요청할 수 있습니다.

uv run프로젝트_에서 사용하는 경우, 이 의존성은 프로젝트 의존성에 _추가하여 포함됩니다. 이 동작을 원하지 않으면 --no-project 플래그를 사용하세요.

Python 스크립트 생성

Python은 최근 인라인 스크립트 메타데이터(metadata)를 위한 표준 형식을 추가했습니다. 이 형식으로 Python 버전을 선택하고 의존성을 정의할 수 있습니다. uv init --script로 인라인 메타데이터와 함께 스크립트를 초기화하세요:

코드 · 명령
$ uv init --script example.py --python 3.12

스크립트 의존성 선언

인라인 메타데이터 형식을 사용하면 스크립트의 의존성을 스크립트 자체에 선언할 수 있습니다.

uv는 인라인 스크립트 메타데이터를 추가하고 업데이트할 수 있습니다. uv add --script로 스크립트의 의존성을 선언하세요:

코드 · 명령
$ uv add --script example.py 'requests<3' 'rich'

이 명령은 TOML을 사용해 의존성을 선언하는 script 섹션을 스크립트 맨 위에 추가합니다:

코드 · 명령
# /// script
# dependencies = [
#   "requests<3",
#   "rich",
# ]
# ///

import requests
from rich.pretty import pprint

resp = requests.get("https://peps.python.org/api/peps.json")
data = resp.json()
pprint([(k, v["title"]) for k, v in data.items()][:10])

uv는 스크립트를 실행하는 데 필요한 의존성이 포함된 환경을 자동으로 만듭니다. 예를 들어:

코드 · 명령
$ uv run example.py
[
│   ('1', 'PEP Purpose and Guidelines'),
│   ('2', 'Procedure for Adding New Modules'),
│   ('3', 'Guidelines for Handling Bug Reports'),
│   ('4', 'Deprecation of Standard Modules'),
│   ('5', 'Guidelines for Language Evolution'),
│   ('6', 'Bug Fix Releases'),
│   ('7', 'Style Guide for C Code'),
│   ('8', 'Style Guide for Python Code'),
│   ('9', 'Sample Plaintext PEP Template'),
│   ('10', 'Voting Guidelines')
]

인라인 스크립트 메타데이터를 사용할 때는 uv run을 _프로젝트_에서 사용하더라도 프로젝트 의존성이 무시됩니다. --no-project 플래그는 필요하지 않습니다.

uv는 Python 버전 요구 사항도 준수합니다:

코드 · 명령
# /// script
# requires-python = ">=3.12"
# dependencies = []
# ///

# Use some syntax added in Python 3.12
type Point = tuple[float, float]
print(Point)

dependencies 필드는 비어 있더라도 반드시 제공해야 합니다.

uv run은 필요한 Python 버전을 검색하고 사용합니다. Python 버전이 설치되어 있지 않으면 다운로드합니다.

Shebang으로 실행 가능한 파일 만들기

uv run을 사용하지 않고도 스크립트를 실행할 수 있도록 shebang을 추가할 수 있습니다 — 이 방법은 PATH에 있거나 현재 폴더에 있는 스크립트를 쉽게 실행할 수 있게 해줍니다.

예를 들어, 다음 내용으로 greet라는 파일을 만드세요:

코드 · 명령
#!/usr/bin/env -S uv run --script

print("Hello, world!")

chmod +x greet 등으로 스크립트를 실행 가능하게 만든 다음 실행하세요:

코드 · 명령
$ ./greet
Hello, world!

이 맥락에서 의존성 선언도 지원됩니다. 예를 들어:

코드 · 명령
#!/usr/bin/env -S uv run --script
#
# /// script
# requires-python = ">=3.12"
# dependencies = ["httpx"]
# ///

import httpx

print(httpx.get("https://example.com"))

대체 패키지 인덱스 사용

의존성 해결에 대체 패키지 인덱스(index)를 사용하려면 --index 옵션으로 인덱스를 지정하세요:

코드 · 명령
$ uv add --index "https://example.com/simple" --script example.py 'requests<3' 'rich'

이 명령은 인라인 메타데이터에 패키지 데이터를 포함시킵니다:

코드 · 명령
# [[tool.uv.index]]
# url = "https://example.com/simple"

패키지 인덱스 접근에 인증이 필요하면 패키지 인덱스 문서를 참조하세요.

의존성 잠금

uv는 uv.lock 파일 형식을 사용해 PEP 723 스크립트의 의존성을 잠글 수 있습니다. 프로젝트와 달리, 스크립트는 uv lock으로 명시적으로 잠가야 합니다:

코드 · 명령
$ uv lock --script example.py

uv lock --script를 실행하면 스크립트 옆에 .lock 파일이 생성됩니다(예: example.py.lock).

잠금 후에는 uv run --script, uv add --script, uv export --script, uv tree --script 등의 작업이 잠긴 의존성을 재사용하며, 필요한 경우 락파일(lockfile)을 업데이트합니다.

잠금 파일이 없는 경우 uv export --script 등의 명령은 계속 작동하지만 잠금 파일을 생성하지는 않습니다.

재현성 개선

의존성 잠금 외에도 uv는 인라인 스크립트 메타데이터의 tool.uv 섹션에 exclude-newer 필드를 지원합니다. 이 필드는 uv가 특정 날짜 이전에 배포된 패키지만 고려하도록 제한하여, 나중에 스크립트를 실행할 때 재현성을 개선합니다.

날짜는 RFC 3339 타임스탬프 형식(예: 2006-12-02T02:07:43Z)으로 지정해야 합니다.

코드 · 명령
# /// script
# dependencies = [
#   "requests",
# ]
# [tool.uv]
# exclude-newer = "2023-10-16T00:00:00Z"
# ///

import requests

print(requests.__version__)

다른 Python 버전 사용

uv를 사용하면 각 스크립트 실행 시 원하는 Python 버전을 요청할 수 있습니다. 예를 들어:

코드 · 명령
import sys

print(".".join(map(str, sys.version_info[:3])))
코드 · 명령
$ # 기본 Python 버전 사용 (머신마다 다를 수 있음)
$ uv run example.py
3.12.6

$ # 특정 Python 버전 사용
$ uv run --python 3.10 example.py
3.10.15

GUI 스크립트 사용

Windows에서 uv.pyw 확장자로 끝나는 스크립트를 pythonw로 실행합니다:

코드 · 명령
from tkinter import Tk, ttk

root = Tk()
root.title("uv")
frm = ttk.Frame(root, padding=10)
frm.grid()
ttk.Label(frm, text="Hello World").grid(column=0, row=0)
root.mainloop()
코드 · 명령
PS> uv run example.pyw

마찬가지로, 의존성도 함께 사용할 수 있습니다:

코드 · 명령
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QGridLayout

app = QApplication(sys.argv)
widget = QWidget()
grid = QGridLayout()

text_label = QLabel()
text_label.setText("Hello World!")
grid.addWidget(text_label)

widget.setLayout(grid)
widget.setGeometry(100, 100, 200, 50)
widget.setWindowTitle("uv")
widget.show()
sys.exit(app.exec_())
코드 · 명령
PS> uv run --with PyQt5 example_pyqt.pyw

다음 단계

uv run에 대해 더 알아보려면 명령 참조를 확인하세요. 또는 계속 읽어 uv로 도구(tool)를 실행하고 설치하는 방법을 알아보세요.

원문(영어): https://docs.astral.sh/uv/guides/scripts/ · 본 문서는 학습용 한국어 번역이며 원본의 권리는 원저작자(Astral)에게 있습니다.

원문(영어): https://docs.astral.sh/uv/guides/scripts/