본문 바로가기
목차
Python

PyPI에 wheel을 업로드하기

by ds31x 2025. 12. 21.
728x90
반응형

0. 전체 workflow 개요

PyPI에 wheel을 업로드하는 과정은 다음 단계로 구성됨.

  1. PyPI account 생성
  2. project metadata 준비
  3. wheel build 수행
  4. upload tool 준비
  5. PyPI로 upload 수행

각 단계는 독립적으로 수행됨.

 

1-3 은 다음을 참고해도 됨:

2025.12.21 - [Python] - 개발 디렉토리를 pip package로 설치하기 - pip install -e .

 

개발 디렉토리를 pip package로 설치하기 - pip install -e .

0. pyproject.toml 과 pip install -e . 사용 튜토리얼이 글은 개발 중인 Python code directory를 pip package로 install하는 방법을 정리함.pyproject.toml을 이용한 package metadata 정의 와pip install -e .를 활용한 editable insta

ds31x.tistory.com


1. 사전 작업

isolated environment에서 build 수행 필요함: conda environment 생성.

conda create -n pypi-build python=3.10
conda activate pypi-build

다음과 같은 project directory구조

my_project/
├─ pyproject.toml
└─ src/
   └─ my_pkg/
      ├─ __init__.py
      └─ core.py

pyproject.toml작성.

[build-system]
requires = ["setuptools>=64", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "my-pkg"
version = "0.1.2"
description = "PyPI upload tutorial"
requires-python = ">=3.10"

dependencies = []
  • project name은 PyPI에 존재하지 않아야 함: 여기서 사용한 my-pkg 는 백프로 안되니 고유한 이름을 바꾸어 넣어야 함.
  • version은 upload 시마다 증가해야 함

주의할 부분

 

  • pip install <distribution-name> import <package-name>은 다를 수 있음
  • distribution name은 pyproject.toml의 [project].name으로 결정됨
  • import namesrc/ 아래의 package directory 이름으로 결정됨

 


test package source 준비.

  • 다시한번 언급하지만,
    src 밑의 디렉토리가 import 에 사용하는 패키지 이름이 됨에 주의할 것.
# src/my_pkg/core.py
def hello():
    return "hello from wheel"
# src/my_pkg/__init__.py
from .core import hello

2. PyPI account 생성

PyPI upload를 위해 account 필요함.

초기 테스트 목적일 경우 TestPyPI 사용 권장됨.


3. project metadata 준비

다음 파일이 project root에 존재해야 함.

  • pyproject.toml
  • package source directory

pyproject.toml에는 최소한 다음 정보가 포함되어야 함.

  • project name
  • version
  • build-system
  • dependencies (선택)

4. wheel build 수행

wheel build는 build module을 이용함.

4-1 build tool 설치

wheel build를 위해 다음 tool install 필요함.

pip install --upgrade pip
pip install build

4-2 wheel 및 sdist 생성

python -m build

 

명령 실행 결과, 다음과 같은 dist/ directory 생성됨.

dist/
├─ <[project].name>-0.1.2-py3-none-any.whl
└─ <[project].name>-0.1.2.tar.gz
  • 주의할 것은 <[project].name>pyproject.toml 에서의 [project] 섹션의 name 의 값으로 대체해야함.
  • hypen 은 underbar로 대체됨.

PyPI는 wheel과 sdist 모두 업로드 가능함.

 

업로드하기전에 wheel 파일이 정상인지 확인해야 함.

다음으로 설치하고:

pip install dist/<[project].name>-0.1.2-py3-none-any.whl

 

설치 성공시 다음의 코드실행이 가능함:

from my_pkg import hello
print(hello())

정상 출력 확인할 것.

 

PyPI (or TestPyPI)에서의 install 확인을 위해 제거해 둘 것.

pip uninstall <[project].name>

5. upload tool (twine) 준비

PyPI upload에는 twine 사용이 권장됨.

pip install twine

6. PyPI upload 수행

6-1 TestPyPI로 upload (권장)

project root에서 다음 명령을 실행함.

twine upload --repository testpypi dist/*
  • credential 입력 필요함: username 과 password
    • 과거 기준이고 현재는 username은 __token__으로 고정.
    • password는 발급받은 API Token 문자열임.
    • 보통 Enter your API token: 이 뜨면 Token을 입력하면 됨.
  • 정상 upload 여부 확인 가능함

6-2 실제 PyPI로 upload

twine upload dist/*

upload 완료 후 PyPI project page 생성됨.

만약 버전이 올라간 것을 업로드하려면 위 명령어에서 와일드카드 문자 대신 해당 버전의 파일을 지정해야함.


7. 입력 요청 시 API token 사용 권장

username 은 __token__으로 고정됨.
password 대신 API token 사용 으로 변경됨

  • PyPI account settings에서 token 생성
  • __token__을 username으로 사용
# 현재
Enter your API token:

# 과거
username: __token__
password: pypi-xxxxxxxxxxxxxxxx

보안 측면에서 필수적임.

 

upload 성공시 URL 출력됨.
다음과 같은 출력임:

Uploading distributions to https://test.pypi.org/legacy/
Uploading <[project].name>-0.1.2-py3-none-any.whl
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━  (업로드 진행 바)
Uploading <[project].name>-0.1.2.tar.gz
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
View at:
https://test.pypi.org/project/my-pkg/0.1.0/

출력되는 Project URL은 다음과 같음:

  • TestPyPI: https://test.pypi.org/project/<[project].name>/<version>/
  • PyPI: https://pypi.org/project/<[project].name>/<version>/

이 URL이 출력되는 경우는 “서버에 업로드가 받아들여졌고, 인덱싱이 끝난 상태” 임을 의미.


8. 업로드 후 확인

TespPyPI는 기본 index가 아니므로 다음과 같은 option이 필요함:

pip install \
  --index-url https://test.pypi.org/simple/ \
  <[project].name>

 

PyPI에 업로드 한 경우는 다음 명령으로 install 가능 여부 확인함.

pip install my-pkg

 

wheel이 존재할 경우 pip는 wheel을 우선적으로 선택함.

 

참고로, TestPyPI는 dependency가 부족한 경우가 많으므로, PyPI로 제대로 올려졌는지만 확인하려면 다음처럼 --no-deps 를 주는게 나을 수도 있음:

pip install \
  --index-url https://test.pypi.org/simple/ \
  --no-deps \
  <[project].name>
  • --no-deps: dependency 설치를 시도하지 않음
  • 목적: “내 패키지가 install 가능한지”만 검증함

Index URL이란 pip가 패키지를 조회·다운로드하기 위해 사용하는 패키지 인덱스 인스턴스의 주소임.

Index 인스턴스란 pip가 패키지를 검색하고 다운로드하기 위해 접속하는 하나의 패키지 저장소 서버(endpoint)임.

Index URL은 다음과 같음:

사내/프라이빗 인덱스 인덱스 인스턴스의 url은 다음과 같음:https://packages.mycompany.com/simple/

pip는 PEP 503 (Simple Repository API) 규격을 사용

9. install이 성공했는지 확인하는 방법

설치 후 다음을 수행함.

python -c "import my_pkg; print(my_pkg.__file__)"

여기서 출력 경로가 conda env 내부의 site-packages를 가리키면 정상임.


추가로 함수 테스트도 가능함.

python -c "from my_pkg import hello; print(hello())"

10. 자주 발생하는 오류

  • version conflict
    • 동일 version 재업로드 불가함
    • version increment 필요함
  • metadata 오류
    • pyproject.toml 누락
    • project name 중복
  • wheel tag 오류
    • platform tag mismatch
    • Python version mismatch

11. editable install과 PyPI upload의 관계

  • editable install 인 pip install -e .는 upload 대상 아님
  • wheel / sdist 만 PyPI에 upload 가능함
  • development 단계와 distribution 단계는 명확히 구분 필요함

2025.12.21 - [Python] - 개발 디렉토리를 pip package로 설치하기 - pip install -e .

 

개발 디렉토리를 pip package로 설치하기 - pip install -e .

0. pyproject.toml 과 pip install -e . 사용 튜토리얼이 글은 개발 중인 Python code directory를 pip package로 install하는 방법을 정리함.pyproject.toml을 이용한 package metadata 정의 와pip install -e .를 활용한 editable insta

ds31x.tistory.com


정리

  • PyPI upload는 wheel build 이후 수행
  • python -m build + twine upload가 표준 workflow임
  • TestPyPI를 통한 사전 검증 권장됨
  • API token 사용이 안전함
  • version 관리 필수적임

같이 보면 좋은 자료들

https://dsaint31.tistory.com/534#Python%20Package%20Index%20(PyPI)-1-2

 

[Python] pip 란 (Package Management System)

정의pip는 Pip Installs Python를 줄인 말로, Python에서 기본적으로 사용되는 Python package management system임.pip와 같이, 줄임말이 원래 문장에 다시 들어가 있는 경우를 recursive acronym (or recursice initialism)이

dsaint31.tistory.com


 

728x90