반응형

Python 프로젝트를 개발하다 보면 프로젝트 설정과 관련된 여러 파일들을 다뤄야 합니다. setup.py, requirements.txt, Pipfile, setup.cfg 등 다양한 파일들이 존재하죠. 하지만 이제 pyproject.toml이라는 새로운 표준이 등장했습니다. 이 글에서는 pyproject.toml에 대해 자세히 알아보고, 어떻게 구성하고 사용하는지 살펴보겠습니다.

pyproject.toml 소개

pyproject.toml은 Python 프로젝트의 빌드 시스템과 관련된 설정을 포함하는 파일입니다. 패키징 도구뿐만 아니라 linters, type checkers 등 다양한 도구들에서 사용됩니다. pyproject.toml에는 세 가지 TOML 테이블이 있을 수 있습니다.

  • [build-system]: 빌드 백엔드와 빌드에 필요한 의존성을 선언합니다. 강력히 권장되는 테이블입니다.
  • [project]: 대부분의 빌드 백엔드에서 프로젝트의 기본 메타데이터(의존성, 이름 등)를 명시하는 데 사용됩니다.
  • [tool]: 도구 특화 설정을 위한 서브테이블(예: [tool.hatch], [tool.black], [tool.mypy] 등)이 포함됩니다.

[build-system]과 [project] 테이블은 사용하는 빌드 백엔드에 따라 차이가 있습니다. [build-system]은 항상 존재해야 하지만, [project]는 일부 빌드 백엔드에서 다른 형식을 사용할 수 있습니다. 예를 들어, Poetry는 [tool.poetry] 테이블을 사용합니다. setuptools 빌드 백엔드는 [project] 테이블과 setup.cfg, setup.py의 이전 형식을 모두 지원합니다. 새 프로젝트라면 [project] 테이블을 사용하는 것이 권장되지만, C 확장 빌드 등 프로그래밍 설정이 필요한 경우 setup.py를 유지할 수 있습니다.

빌드 백엔드 선언

[build-system] 테이블에는 사용할 빌드 백엔드를 지정하는 build-backend 키와 빌드에 필요한 의존성을 나열하는 requires 키가 포함됩니다. 보통은 선택한 빌드 백엔드의 문서에 제시된 내용을 그대로 사용하면 됩니다.

[build-system]
requires = ["setuptools>=42", "wheel", "numpy==1.21.0"]
build-backend = "setuptools.build_meta"

프로젝트 메타데이터 설정

[project] 테이블에는 프로젝트의 다양한 메타데이터를 설정할 수 있습니다. 주요 필드는 다음과 같습니다:

  • name: PyPI에 표시될 프로젝트 이름 (필수)
  • version: 프로젝트 버전 (필수, dynamic 지정 가능)
  • description: PyPI에 표시될 프로젝트 한 줄 설명
  • readme: 프로젝트 상세 설명 (README 파일 지정)
  • authors, maintainers: 프로젝트 작성자 및 관리자 정보
  • license: 라이선스 명시 (파일 또는 텍스트)
  • keywords: PyPI 검색에 활용될 키워드
  • classifiers: PyPI 분류자 (라이선스, 개발 단계, Python 버전 등)
  • urls: 프로젝트 관련 URL (홈페이지, 문서, 저장소 등)

version 필드는 빌드 백엔드가 동적으로 채울 수 있도록 dynamic 리스트에 지정할 수 있습니다. readme 필드는 파일 경로와 포맷(content-type)을 명시적으로 지정할 수도 있습니다. 표준 라이선스를 사용한다면 license 필드 대신 분류자에 라이선스를 명시하는 것이 권장됩니다. Python 지원 버전은 분류자에도 명시할 수 있지만, 실제 설치 제한을 위해선 requires-python 필드를 사용해야 합니다.
PyPI에 업로드되지 않도록 하려면 Private :: Do Not Upload 분류자를 사용합니다.

의존성 및 요구사항 명시

dependencies와 optional-dependencies를 통해 프로젝트의 의존성 패키지를 명시할 수 있습니다. 버전 제약에는 여러 문법을 사용할 수 있습니다. requires-python으로는 지원하는 Python 버전을 지정합니다.

[project]
dependencies = [
  "httpx",
  "gidgethub[httpx]>4.0.0",
  "django>2.1; os_name != 'nt'",
  "django>2.0; os_name == 'nt'",
]
requires-python = ">= 3.8"

[project.optional-dependencies]
gui = ["PyQt5"]
cli = [
  "rich",
  "click",
]

선택적 의존성은 "extra"로 표현되며, pip install 프로젝트명[extra이름] 형식으로 설치할 수 있습니다.

실행 파일 생성

[project.scripts]와 [project.gui-scripts]를 사용하여 패키지 설치 시 함께 설치될 실행 파일을 지정할 수 있습니다.

[project.scripts]
spam-cli = "spam:main_cli"

[project.gui-scripts]
spam-gui = "spam:main_gui"

[project.scripts]로 지정한 스크립트는 Windows에서 터미널이 필요하고, [project.gui-scripts]는 터미널 없이 백그라운드 실행됩니다. 이 차이는 Windows에서만 유효합니다.

고급 플러그인 설정

[project.entry-points]의 서브테이블을 통해 pytest, Pygments 등 플러그인 시스템을 갖춘 패키지의 플러그인을 설정할 수 있습니다.

[project.entry-points."spam.magical"]
tomatoes = "spam:main_tomatoes"

전체 예시

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "spam-eggs"
version = "2020.0.0"
dependencies = [
  "httpx",
  "gidgethub[httpx]>4.0.0",
  "django>2.1; os_name != 'nt'",
  "django>2.0; os_name == 'nt'",
]
requires-python = ">=3.8"
authors = [
  {name = "Pradyun Gedam", email = "pradyun@example.com"},
  {name = "Tzu-Ping Chung", email = "tzu-ping@example.com"},
  {name = "Another person"},
  {email = "different.person@example.com"},
]
maintainers = [
  {name = "Brett Cannon", email = "brett@example.com"}
]
description = "Lovely Spam! Wonderful Spam!"
readme = "README.rst"
license = {file = "LICENSE.txt"}
keywords = ["egg", "bacon", "sausage", "tomatoes", "Lobster Thermidor"]
classifiers = [
  "Development Status :: 4 - Beta",
  "Programming Language :: Python"
]

[project.optional-dependencies]
gui = ["PyQt5"]
cli = [
  "rich",
  "click",
]

[project.urls]
Homepage = "https://example.com"
Documentation = "https://readthedocs.org"
Repository = "https://github.com/me/spam.git"
"Bug Tracker" = "https://github.com/me/spam/issues"
Changelog = "https://github.com/me/spam/blob/master/CHANGELOG.md"

[project.scripts]
spam-cli = "spam:main_cli"

[project.gui-scripts]
spam-gui = "spam:main_gui"

[project.entry-points."spam.magical"]
tomatoes = "spam:main_tomatoes"

pyproject.toml은 Python 프로젝트 설정을 위한 새로운 표준으로 자리 잡고 있습니다. 빌드 시스템 설정부터 프로젝트 메타데이터, 의존성, 실행 파일, 플러그인 등 다양한 설정을 한 곳에서 관리할 수 있게 해 줍니다. Python 생태계에서 pyproject.toml의 활용이 더욱 확대되기를 기대합니다.

반응형