🚀
고급 (Advanced)
venv · pyproject.toml · console_scripts · TestPyPI
9주차 — 패키징과 배포
가상환경, pyproject.toml 의 구조, console_scripts 로 CLI 도구 제공, 그리고 TestPyPI 업로드까지 — 자체 패키지를 만들어 배포하는 전체 흐름.
venvpyproject.tomlbuildtwine
소요 시간
⏱ 2시간
난이도
📊 고급
선수 조건
🎯 고급 8주차
결과물
자체 패키지 빌드와 배포
이 강의에서 배우는 것
- 1pyproject.toml 의 구조를 이해한다
- 2자체 패키지를 빌드해서 설치한다
- 3console_scripts 로 CLI 도구를 제공한다
- 4TestPyPI 에 업로드한다
1. 가상환경
프로젝트마다 라이브러리 버전을 분리합니다.
bash
python -m venv .venv
# 활성화
source .venv/bin/activate # macOS/Linux
.venv\Scripts\activate # Windows
# 종료
deactivate2. pyproject.toml
현대 파이썬 패키지의 표준 설정 파일.
toml
[project]
name = "mytool"
version = "0.1.0"
description = "내 멋진 CLI 도구"
authors = [{name = "홍길동", email = "hong@example.com"}]
requires-python = ">=3.10"
dependencies = [
"requests>=2.28",
"rich>=13.0",
]
[project.scripts]
mytool = "mytool.cli:main"
[build-system]
requires = ["setuptools>=61"]
build-backend = "setuptools.build_meta"3. 패키지 구조
text
mytool_project/
├── pyproject.toml
├── README.md
├── LICENSE
├── src/
│ └── mytool/
│ ├── __init__.py
│ └── cli.py
└── tests/
└── test_cli.pypython
# src/mytool/cli.py
def main():
print("Hello from mytool!")설치:
bash
pip install -e . # 개발 모드 (수정이 즉시 반영)
mytool # CLI 실행4. 빌드
bash
pip install build
python -m build # dist/ 에 .whl, .tar.gz 생성5. TestPyPI 업로드
bash
pip install twine
twine upload --repository testpypi dist/*다른 환경에서 설치:
bash
pip install --index-url https://test.pypi.org/simple/ mytool6. requirements.txt vs pyproject.toml
| requirements.txt | pyproject.toml | |
|---|---|---|
| 용도 | 환경 고정 (deploy) | 라이브러리 메타데이터 |
| 버전 | 정확한 핀 | 범위 |
| 빌드 | 안 됨 | 됨 |
bash
pip freeze > requirements.txt # 현재 환경 내보내기
pip install -r requirements.txt # 재현자주 하는 실수
- 가상환경 활성화 안 함 — 시스템 파이썬에 설치됨
- __init__.py 빠뜨림 — 패키지로 인식 안 됨
- src/ 레이아웃 안 씀 — import 충돌 가능
- 버전 안 올리고 재배포 — PyPI는 같은 버전 거부
FAQ
Q1. setup.py 는? — 신규는 pyproject.toml. 레거시 호환만 setup.py.
Q2. poetry vs pip+venv? — poetry는 통합 도구. 신규는 poetry나 uv 권장.
Q3. PyPI vs TestPyPI? — PyPI는 진짜 공개. TestPyPI는 연습용.
💻 예제 (examples)
실제로 실행해 결과를 확인할 수 있는 예제 코드입니다.
pyproject.toml— 패키지 설정 (전체)
CODE
[project]
name = "mytool"
version = "0.1.0"
description = "내 멋진 CLI 도구"
authors = [{name = "홍길동", email = "hong@example.com"}]
requires-python = ">=3.10"
dependencies = ["requests>=2.28"]
[project.scripts]
mytool = "mytool.cli:main"
[build-system]
requires = ["setuptools>=61"]
build-backend = "setuptools.build_meta"▶ 실행 결과
(설정 파일 — 직접 출력은 없음)src/mytool/__init__.py— 패키지 진입
CODE
__version__ = "0.1.0"▶ 실행 결과
(import 시 활성화)src/mytool/cli.py— CLI 진입점
CODE
import argparse
def main():
parser = argparse.ArgumentParser(prog="mytool")
parser.add_argument("name", help="이름")
parser.add_argument("--upper", action="store_true")
args = parser.parse_args()
msg = f"Hello, {args.name}!"
print(msg.upper() if args.upper else msg)
if __name__ == "__main__":
main()▶ 실행 결과
$ mytool 홍길동
Hello, 홍길동!
$ mytool 홍길동 --upper
HELLO, 홍길동!build_demo.sh— 빌드와 로컬 설치
CODE
# 가상환경
python -m venv .venv
source .venv/bin/activate
# 개발 설치
pip install -e .
# 실행
mytool 세상
# 빌드
pip install build
python -m build▶ 실행 결과
Hello, 세상!
Successfully built mytool-0.1.0.tar.gz mytool-0.1.0-py3-none-any.whl📝 과제 (exercises)
직접 풀어보고, 막힐 때 정답을 펼쳐 비교해보세요.
과제 1
최소 패키지
목표: Hello World 를 출력하는 CLI 패키지를 만든다.
요구사항
- src/hello/__init__.py + cli.py
- pyproject.toml + console_scripts
- pip install -e . 후 hello 명령 실행 가능
💡 힌트
[project.scripts] hello = 'hello.cli:main'
입출력 예시
Hello, 패키지!채점
- · 패키지 구조
- · CLI 등록
▶정답 코드 펼치기 / 접기
SOLUTION
# pyproject.toml
[project]
name = "hello"
version = "0.1.0"
[project.scripts]
hello = "hello.cli:main"
[build-system]
requires = ["setuptools>=61"]
build-backend = "setuptools.build_meta"
# src/hello/__init__.py
__version__ = "0.1.0"
# src/hello/cli.py
def main():
print("Hello, 패키지!")
# 설치 + 실행
# pip install -e .
# hello▶ 실행 결과
Hello, 패키지!과제 2
argparse 가산기
목표: 두 수를 더하는 CLI 패키지를 만든다.
요구사항
- addr 1 2 → 3 출력
- argparse 사용
💡 힌트
type=int 지정
입출력 예시
3채점
- · argparse 사용
- · 정상 출력
▶정답 코드 펼치기 / 접기
SOLUTION
# src/addr/cli.py
import argparse
def main():
p = argparse.ArgumentParser(prog="addr")
p.add_argument("a", type=int)
p.add_argument("b", type=int)
args = p.parse_args()
print(args.a + args.b)
# pyproject.toml: [project.scripts] addr = "addr.cli:main"
# 실행: addr 1 2▶ 실행 결과
3과제 3
버전 출력 옵션
목표: --version 옵션으로 패키지 버전을 출력한다.
요구사항
- argparse --version action
- __init__.py 의 __version__ 사용
💡 힌트
action='version', version=f'%(prog)s {__version__}'
입출력 예시
mytool 0.1.0채점
- · --version 동작
- · 버전 일치
▶정답 코드 펼치기 / 접기
SOLUTION
# src/mytool/__init__.py
__version__ = "0.1.0"
# src/mytool/cli.py
import argparse
from mytool import __version__
def main():
p = argparse.ArgumentParser(prog="mytool")
p.add_argument("--version", action="version", version=f"%(prog)s {__version__}")
p.parse_args()
# mytool --version▶ 실행 결과
mytool 0.1.0