최근 파이썬 프로젝트들을 보면 pyproject.toml 파일과 poetry 와 같은 키워드들이 점점 많이 보이기 시작한다. pyproject.toml 은 뭐고 poetry 는 또 무엇일까?
| 연도 | 소스코드 테스트 | 패키지 빌드 (패키징, 가장 기본적인 기능) | 패키지 빌드 (엔트리포인트 관리, 메타데이터 관리 등 부가기능) | 패키지 업로드 | 패키지 저장소 | 패키지 다운로드
(소스코드, sdist, 사전 빌드된 바이너리 파일)(ref15) | 패키지 빌드 (빌드 결과물을 만드는 기본 기능) | **패키지 빌드 (**의존성 처리) | **패키지 설치 (**빌드 결과물을 적절한 시스템 위치로 이동) | **패키지 관리 (**엔트리포인트 관리, 메타데이터 관리 등 부가기능) |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| 1998 | | distutils + setup.py | | | 파이썬 커뮤니티 | VCS | distutils + setup.py | | distutils + setup.py | |
| 2003 | | distutils + setup.py | | | PyPI | VCS | distutils + setup.py | | distutils + setup.py | |
| 2004 | setuptools + setup.py (ref5) | setuptools + setup.py | setuptools + setup.py (ref6) | setuptools + setup.py | PyPI | VCS, setuptools (easy_install) (ref7) | setuptools (easy_install) →
(ref10:빌드 프론트)
setuptools + setup.py | setuptools + setup.py | setuptools (easy_install) →
(ref10:빌드 프론트)
setuptools + setup.py | setuptools + setup.py |
| 2008 | unittest, pytest | setuptools + setup.py | setuptools + setup.py | twine | PyPI | VCS, pip | pip →
setuptools + setup.py
빌드 결과물이 wheel 포맷으로 표준화 | pip →
setuptools + setup.py | pip
wheel 파일을 적절한 디렉토리에 밀어넣는 작업 | pip |
| 현재: 2024/03/19 | ??? | ??? | ??? | twine | PyPI | VCS, pip | ??? | ??? | ??? | ??? |
| TO-BE | 빌드 프론트엔드 →
pyproject.toml→
테스트 백엔드(unittest, pytest) | 빌드 프론트엔드 →
pyproject.toml→
빌드 백엔드 | 빌드 프론트엔드 →
pyproject.toml→
빌드 백엔드 | twine | PyPI | VCS, pip | 빌드 프론트엔드 →
pyproject.toml→
빌드 백엔드
빌드 결과물 wheel | 빌드 프론트엔드 + pyproject.toml → 빌드 프론트엔드 + 빌드 백엔드(일부 까다로운 동적 의존성만) | 빌드 프론트엔드
wheel 파일을 적절한 디렉토리에 밀어넣는 작업 | 빌드 프론트엔드 |
| 현재: 2026/01/01 | uv → pyproject.toml → pytest
(e.g. uv run pytest) | uv → pyproject.toml →
빌드 백엔드 | uv → pyproject.toml →
빌드 백엔드 | uv | PyPI | VCS, uv | uv →
pyproject.toml →
빌드 백엔드
빌드 결과물 wheel | uv →
pyproject.toml →
uv + 빌드 백엔드(일부 까다로운 동적 의존성만) | uv(ref18)
wheel 파일을 적절한 디렉토리에 밀어넣는 작업 | uv |
| 약어 | 의미 |
|---|---|
| PyPI | Python Package Index |
| pip | Pip Install Package: 재귀적 의미 😅 |
| VCS | Version Control System (e.g. git과 github) |
역사적으로 볼 때 setuptools 는 setup.py 와 강하게 결합될 수밖에 없었던 운명이다. 1998년 distutils 와 setup.py 가 탄생하던 시절 둘은 한몸이었다(ref4). 2003년 setuptools는 distutils를 구조적으로 고친 것이 아니라 기능을 확장하며 setup.py를 그대로 사용했다.
setup.py 파일과 setuptools 가 강하게 결합되었다는 것은 setup.py 을 파싱하기 위해 setuptools 를 사용했다는 것을 의미한다. 이것이 문제가 되는 이유는, 설치를 위해 setup.py 를 파싱하기 위해서는 적절한 setuptools 버전이 필요한데, 적절한 setuptools 버전은 setup.py 에 명세되었기 때문이다. 뿐만 아니라, setup.py는 파이썬 파일이기 때문에, 라이브러리를 얼마든 임포트할 수 있고, 그럼 또다시 setup.py 를 처리하는 방식이 다시 도구에 의존하게 되면서 버전 명세 등이 불가능했다(ref2).
변화의 핵심 아이디어는 setup.py 파일을 특정 언어나 도구에 종속시키지 말고 pyproject.toml 이라는 표준을 만들어 다양한 백엔드가 단일 파일을 일관된 형태로 읽어가도록 강제하는 것이다. 지금(2024/03/19)은 pyproject.toml 표준이 만들어진 지 얼마 안 된 과도기이다. 그래서 다양한 빌드 백엔드마다 동일한 기능을 pyproject.toml 에 다르게 명세해야 한다는 문제가 있음을 인지하는 것이 좋다(ref3).
| 빌드 프론트엔드(ref11) | 참조하는 파일 | 비고 |
|---|---|---|
| pip install | 패키징용이 아니라 설치용임 | |
| build(ref14) | pyproject.toml |
예제 프론트엔드, C익스텐션 없어 가벼움(ref17) |
| flit | pyproject.toml |
순수 파이썬 구현, C익스텐션 없어 가벼움(ref16) |
| hatch | pyproject.toml |
PEP준수, 다양한 기능, 빠르게 성장 중(ref9) |
| poetry | pyproject.toml |
무거움, PEP 준수 안 함(ref3,ref8) |
| setuptools(ref10) | pyproject.toml, setup.py |
유지관리 중단(ref1) |
| distutils | setup.py |
deprecated (python 3.10~) |
| 빌드 백엔드(ref12,ref13) | 비고 |
|---|---|
| setuptools(ref10) | 유지관리 중단(ref1) |
| flit-core(ref13) | flit의 메인 백엔드 |
| hatchling(ref13) | hatch의 메인 백엔드 |
| poetry-core(ref13) | poetry의 유일한(ref8) 백엔드 |
패키지 빌드 과정 중 의존성 처리 단계에서 프론트엔드가 거의 다 읽고 끝내는 경우가 대부분이다. 하지만 설치하는 환경(OS, Python 버전 등)에 따라 필요한 재료가 달라지는 복잡한 녀석들은 빌드 시점에 의존성이 결정되는 경우가 많다. 그래서 의존성 처리 과정에서 빌드 백엔드는 여전히 개입한다.
2024/03/19 현재 poetry 는 의존성 해결 역량이 뛰어나고, 자체 가상환경을 지원하는 등 기능이 풍부하지만 pyproject.toml PEP 표준을 지키지 않고 있기 때문에 복잡한 프로젝트가 아니라면 일단 flit 으로 시작하고, 프로젝트가 커나감에 따라 hatch를 우선적으로 고려하는 것이 현명해 보인다.
2026/01/01 현재는 uv가 pyproject.toml과 같은 PEP 표준을 잘 따라가고 있을 뿐 아니라 의존성 처리 속도나 프로젝트마다 복제되는 가상환경으로 인한 용량(ref18:하드링크를 거는 방식으로 용량을 아낌)문제 등 고질적인 문제들을 거의 개선하면서도 잘 정의된 추상화 영역을 깔끔히 비교우위로 대체하는 역할까지 수행하고 있기 때문에 사실상 표준으로 오래 자리잡을 것으로 보인다.
python build frontend vs python build backend?
parse me : 언젠가 이 글에 쓰이면 좋을 것 같은 재료을 보관해 두는 영역입니다.
Nonefrom : 과거의 어떤 원자적 생각이 이 생각을 만들었는지 연결하고 설명합니다.
make 는 소스코드를 빌드하는 단계를, make install 은 소스코드를 설치하는 단계에 사용되는 관용적 명령어였다.