Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python 개선 제안 한국어 번역

PEP 808 – 동적 메타데이터에 정적 값 포함하기

Author:
Henry Schreiner <henryschreineriii at gmail.com>, Cristian Le <python at lecris.dev>
Sponsor:
Filipe Laíns <lains at python.org>
PEP-Delegate:
Paul Moore <p.f.moore at gmail.com>
Discussions-To:
Discourse thread
Status:
Accepted
Type:
Standards Track
Topic:
Packaging
Created:
19-Sep-2025
Post-History:
17-Apr-2025, 14-Nov-2025
Resolution:
19-May-2026

Table of Contents

번역·라이선스 안내

이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain or CC0-1.0, whichever is more permissive 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판

초록

이 PEP는 pyproject.toml의 [project] 섹션에 나열된 동적 메타데이터에 대한 제약을 완화합니다. 이제 필드가 테이블이나 배열이라면 [project] 테이블에서 동적 메타데이터 필드의 정적 부분을 정의할 수 있습니다. 마찬가지로, METADATA 2.6에서는 소스 배포판 메타데이터에 정적 메타데이터와 동적 메타데이터를 섞어서 지정할 수 있습니다.

이를 통해 사용자는 메타데이터의 정적 부분을 pyproject.toml의 표준 위치에 정의된 상태로 유지하면서도 백엔드가 메타데이터를 확장하도록 선택적으로 허용할 수 있으며, 검사 도구는 여전히 메타데이터의 정적 부분을 처리할 수 있습니다.

동기

원래 PEP 621에서 제시된 코어 메타데이터 명세에서는 메타데이터를 세 가지 방법으로 지정할 수 있습니다. 첫째, [project] 테이블에 나열할 수 있습니다. 이렇게 하면 메타데이터를 정적으로 추론할 수 있게 되며, 이는 (빌드 백엔드뿐만 아니라) 어떤 도구든 그 값을 신뢰성 있게 계산할 수 있다는 뜻입니다. 둘째, 필드를 project.dynamic 목록에 나열할 수 있으며, 이렇게 하면 빌드 백엔드가 그 값을 계산할 수 있습니다. 마지막으로, 값이 project 테이블과 project.dynamic 목록 모두에 없을 수도 있으며, 이 경우 해당 메타데이터는 비어 있음이 보장됩니다.

이 체계는 Python 패키징에 두 가지 중요한 이점을 제공했습니다. 이제 모든 주요 백엔드가 채택한 표준 명세 덕분에 가르치기가 훨씬 쉬워졌습니다. 이제 튜토리얼 하나만으로 어떤 백엔드를 구성하든 메타데이터 부분을 다룰 수 있습니다. 이제 사용자는 정적 메타데이터를 변경하지 않고도 범용 백엔드에서 특화된 백엔드로 전환할 수 있습니다. 스키마 검증 도구와 같은 도구는 구성 실수를 검증하고 잡아낼 수 있습니다.

두 번째 이점은 소스 파일을 읽어 메타데이터를 찾는 정적 도구에 대한 지원이 개선되었다는 것입니다. 이는 “used by” 그래프와 “uses” 그래프를 만드는 것과 같은 의존성 체인 분석에 유용합니다. 코드 품질 도구에서 지원되는 최소 Python 버전을 감지하는 데 사용됩니다. cibuildwheel이 지원되지 않는 휠을 자동으로 빌드하지 않도록 하는 데에도 사용됩니다. 그러나 SDist를 사용할 수 있을 때 휠 빌드를 피하는 데에는 사용되지 않습니다. 이 문제는 METADATA 2.2에서 해결되었는데, METADATA 2.2는 SDist 메타데이터에 Dynamic 필드를 추가하여 휠을 만들 때 메타데이터가 변경될 수 있는지를 도구가 알 수 있게 합니다. 이름이 비슷하기 때문에 쉽게 혼동할 수 있는 부분입니다.

project 테이블의 인기가 빠르게 높아지고, 모든 주요 백엔드가 이를 지원하며, 복잡한 컴파일 확장을 지원하는 백엔드가 늘어남에 따라, PEP 621에서 적용된 제약의 문제가 더욱 뚜렷해지고 있습니다. PEP 621에서 메타데이터의 선택은 전부 아니면 전무입니다. 메타데이터는 완전히 정적이거나, dynamic 필드에 나열되고 정적 정의에서는 완전히 빠져 있어야 합니다. 가장 흔한 사용 사례에서는 이것으로 충분합니다. 어차피 동적으로 덮어쓸 것이라면 version을 정적으로 설정해도 얻는 이점이 거의 없습니다. 올바르게 표시하기 위해 README를 필터링하거나 수정하는 사용자 정의 README 처리기를 사용한다면, 그 구성을 사용자 정의 [tool.*] 섹션에 지정해야 하는 것은 큰 문제가 아닙니다. 그러나 전부 아니면 전무 방식이 문제가 되는 특정 부류의 경우가 있습니다. 백엔드가 항목을 추가해야 하는 항목 목록은 현재 완전히 동적으로(즉, 백엔드별 구성 위치에) 지정하도록 강제됩니다. 이로 인해 원래의 두 가지 이점(표준 위치와 정적 도구 지원)이 모두 사라집니다.

근거

PEP 621에는 다음과 같은 문장이 있습니다:

이 PEP의 이전 버전에서는 도구가 필드의 데이터를 확장하는 것이 허용되었습니다. 예를 들어, 빌드 백엔드는 버전 번호를 가져와 휠을 빌드할 때 로컬 버전을 덧붙일 수 있었습니다. 도구는 또한 라이선스나 지원되는 Python 버전 같은 것을 위해 trove 분류자를 더 추가할 수도 있었습니다.

하지만 결국에는 더 엄격하게 시작한 뒤, 실제 사용 경험을 바탕으로 데이터를 얼마나 정적인 것으로 간주할 수 있을지를 완화하는 방안을 검토하는 편이 낫다고 판단했습니다.

이 PEP에서는 [project] 테이블과 project.dynamic 리스트에 대한 제약을 제한적이고 명시적으로 완화할 것을 제안합니다.

이제 모든 리스트와 임의의 키를 갖는 모든 테이블은 [project] 테이블에 정적으로 지정하는 동시에 project.dynamic 리스트에도 지정할 수 있습니다. 두 곳 모두에 있는 경우, 빌드 백엔드는 리스트 항목을 확장하고 새 키를 추가할 수 있지만 기존 항목을 수정할 수는 없습니다.

사용 사례

이 규칙을 완화하면 고급 사용 사례에서 큰 이점을 얻을 수 있는 메타데이터 필드들이 하나의 부류를 이룰 만큼 존재합니다. 지금까지 제기된 몇 가지 사용 사례는 다음과 같습니다:

  • 휠을 빌드할 때 의존성 요구 사항을 고정하는 경우. 예를 들어 PyTorch 확장을 빌드할 때, 빌드에 사용한 버전은 생성되는 휠에 SDist에는 없는 제약 조건을 추가합니다.
  • 빌드 시스템에서 추가 스크립트를 생성하는 경우(현재 scikit-build-core에서 제안되어 있습니다).
  • 진입점을 동적으로 추가하는 경우입니다(validate-pyproject-schema-store 프로젝트는 이를 사용해 패키지에 있는 각 스키마마다 진입점을 생성할 수 있었을 것입니다).
  • 설정에 따라 의존성이나 선택적 의존성을 추가하는 경우(예를 들어 all 의존성을 만들거나 dependency-groups에서 의존성을 읽어 오는 경우 등). 제약 조건을 추가하는 것도 유용할 수 있습니다. pybind11은 두 패키지가 같은 저장소에 있고 함께 릴리스되기 때문에 pybind11-global==<version>을 고정하는 global extra를 사용합니다. toga는 여러 패키지의 모음인데, 같은 종류의 고정 문제 때문에 현재 정적 의존성을 전혀 설정할 수 없습니다.
  • 분류자를 추가하는 경우. 일부 백엔드는 다른 곳에서 분류자를 계산하여 주입할 수 있습니다(가장 잘 알려진 예는 Poetry입니다).
  • 링크되는 라이브러리에 따라 휠에 라이선스 파일을 추가하는 경우(이는 PEP 639의 후속 논의에서 활발히 다뤄지고 있습니다).
  • 빌드 시에 SBOM을 추가하는 경우 - PEP 770은 바로 빌드 도구가 이를 추가하기를 원하기 때문에 pyproject.toml 필드를 제거해야 했습니다. [project] 테이블 설정은 쓸모가 없었을 것이며, 이를 사용할 수 있는 경우는 거의 없었을 것입니다.
  • 생성된 모듈을 import-names 또는 import-namespaces에 추가하는 것도 또 다른 예입니다.

이 모든 사용 사례에는 비슷한 특징이 있습니다. 고정된 리스트에 무언가를 동적으로 추가한다는 점입니다(의존성의 경우에는 더 좁은 범위로 고정하는 것일 수도 있습니다).

현재도 이를 구현할 수는 있지만, 확장되지 않는 부분을 위해 완전히 별도의 설정 위치를 제공해야 하며, 정적 분석 도구는 아무것도 감지할 수 없게 됩니다. 현재의 해결책은 모든 메타데이터를 표준 필드 밖으로 옮기는 것이므로, 이 제안은 정적 도구가 활용할 수 있는 메타데이터를 늘려 줄 것입니다.

예시: 고정

예를 들어 가상의 빌드 백엔드(my-build-backend)가 PyTorch 의 지원되는 빌드에 고정할 수 있도록 하고 싶다고 가정해 봅시다. 이 PEP 이전에는 다음과 같이 할 수 있었습니다:

[project]
dynamic = ["dependencies"]

[tool.my-build-backend]
original-dependencies = ["torch", "packaging"]
pin-to-build-versions = ["torch=={exact}"]

이는 실질적으로 다음과 같은 SDist 메타데이터로 확장됩니다:

Dynamic: Requires-Dist
Requires-Dist: packaging
Requires-Dist: torch

그리고 이로부터 다음과 같은 휠을 만들 수 있습니다:

Requires-Dist: packaging
Requires-Dist: torch
Requires-Dist: torch==2.8.0

정적 도구는 더 이상 torch와 packaging이 런타임 의존성이라는 것을 알 수 없으며, 빌드 백엔드는 의존성 테이블을 중복해서 만들어야 하므로 사용자가 배우고 읽기가 더 어려워집니다. PEP 621에서 제안되고 모든 주요 빌드 백엔드가 채택한 표준화된 위치가 사라지는 것입니다.

이 PEP를 적용하면 이제 다음과 같이 지정할 수 있습니다:

[project]
dependencies = ["torch", "packaging"]
dynamic = ["dependencies"]

[tool.my-build-backend]
pin-to-build-versions = ["torch=={exact}"]

이제 정적 도구는 정적 의존성을 감지할 수 있으며, 빌드 백엔드는 더 이상 표준 project.dependencies 필드를 위한 새로운 위치(예를 들어 위의 original-dependencies 필드)를 만들고 문서화할 필요가 없습니다.

향후 업데이트

순수하게 추가만 하는 메타데이터를 허용하도록 이 규칙을 완화하면 실제로 확인된 많은 사용 사례를 해결할 수 있을 것입니다. 추가 변경이 필요하다면 향후 PEP에서 다시 검토할 수 있습니다. 이 PEP는 이러한 향후 업데이트를 권장하지도, 배제하지도 않습니다.

용어

이 문서의 키워드 “MUST”, “MUST NOT”, “REQUIRED”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, “OPTIONAL”은 RFC 2119에 기술된 대로 해석해야 합니다.

명세

임의의 항목을 갖는 리스트나 테이블로 구성된 필드는 이제 [project] 테이블과 project.dynamic 리스트 양쪽에 모두 존재할 수 있습니다. 어떤 필드가 두 곳 모두에 존재하면, 빌드 백엔드는 리스트나 테이블에 항목을 삽입할 수 있지만, 항목을 제거하거나 순서를 바꾸거나 수정할 수는 없습니다. 배열 테이블에서는 위의 규칙에 따라 새 테이블 항목을 추가하거나 기존 배열을 확장할 수 있습니다.

임의의 항목을 갖는 배열이나 테이블인 필드는 다음과 같습니다.

  • authors, maintainers: 새 저자 테이블을 리스트에 추가할 수 있습니다. 기존 저자는 수정할 수 없습니다(미리 정의된 키를 갖는 테이블의 리스트).
  • classifiers: 분류자를 리스트에 추가할 수 있습니다.
  • dependencies: 새 의존성을 추가할 수 있으며, 기존 의존성을 더 엄격하게 제한한 것도 추가할 수 있습니다.
  • entry-points: 새 그룹이나 기존 그룹에 진입점을 추가할 수 있습니다. 기존 진입점은 변경하거나 제거할 수 없습니다.
  • scripts, gui-scripts: 새 스크립트를 추가할 수 있습니다. 기존 스크립트는 변경하거나 제거할 수 없습니다.
  • keywords: 키워드를 리스트에 추가할 수 있습니다.
  • license-files: 파일을 리스트에 추가할 수 있습니다.
  • optional-dependencies: 새 엑스트라를 추가하거나 기존 엑스트라에 새 항목을 추가할 수 있습니다.
  • urls: 새 URL을 추가할 수 있습니다. 기존 URL은 변경하거나 제거할 수 없습니다.
  • import-names, import-namespaces: 새 임포트 이름이나 네임스페이스를 추가할 수 있습니다. 기존 임포트 이름이나 네임스페이스는 수정하거나 제거할 수 없습니다.

항목을 추가하려면 사용자가 해당 필드를 dynamic에 나열하여 명시적으로 선택해야 합니다. 그렇지 않으면 메타데이터는 계속 완전히 정적으로 유지됩니다.

사용자 실수 가능성으로부터 보호하기 위해, 필드가 지정되었는데 백엔드가 그 필드의 확장을 지원하지 않는 경우 백엔드는 오류를 발생시켜야 합니다(SHOULD). dynamic 리스트에 불필요한 항목이 들어가지 않도록 가능한 한 엄격하게 처리할 것을 권장합니다.

정적 분석 도구는 어떤 필드가 지정되어 있으면서 project.dynamic 배열에도 있음을 감지하면, 해당 필드가 불완전하다고 가정하여 패키지를 빌드할 때 새 항목이 존재할 수 있음을 허용해야 합니다(SHOULD).

PEP 643에 명시된 Dynamic 필드는 이 PEP의 영향을 받지 않으며, 백엔드는 원하는 대로 계속 이 필드를 채울 수 있습니다. 그러나 백엔드는 SDist와 휠 메타데이터 모두에 프로젝트 테이블의 정적 메타데이터 부분이 포함되도록 반드시 보장해야 합니다(MUST).

METADATA 2.2부터 2.5까지는 Dynamic으로 나열된 항목에 제약이 없습니다(즉, 해당 필드에 대해 휠이 SDist와 다른 메타데이터를 가질 수 있습니다). 이제 SDist에 지정된 메타데이터 필드는 Dynamic이 존재하더라도 휠에도 존재함이 보장됩니다. METADATA(메타데이터) 버전은 2.6으로 올라갑니다. 다음 예를 살펴봅시다.:

Dynamic: Requires-Dist
Requires-Dist: packaging

METADATA(메타데이터) 2.6 이전에는 필드가 Dynamic에 나타나면 그 필드에 아무런 제약이 없었으므로 휠에는 무엇이든 들어갈 수 있었습니다. 이제 2.6에서는 여기에 있는 모든 값이 휠에도 존재함이 보장되므로 휠에는 Requires-Dist: packaging이 포함됩니다. Requires-Dist가 더 포함될 수는 있지만, 적어도 그 하나는 반드시 포함됩니다.

지침에 다음과 같은 새 항목이 추가됩니다:

  • 여러 번 사용할 수 있는 필드가 소스 배포판에 존재하면서 Dynamic으로도 표시되어 있다면, wheel은 값을 추가할 수 있지만 SDist에 있는 값은 반드시 포함해야 합니다. Keywords, Author-Email, Maintainer-Email은 쉼표로 구분된 목록이므로, 존재하는 경우 마찬가지로 확장할 수 있습니다.

참조 구현

필드별로 동적 메타데이터를 지원할지는 이미 백엔드가 정하도록 되어 있으며, 이 PEP는 백엔드가 동적 메타데이터로 할 수 있는 일에 대한 제약을 완화할 뿐입니다.

여러 빌드 백엔드에서 사용하는 pyproject-metadata 프로젝트는 가능한 확장을 고려하도록 정합성 검사를 수정해야 합니다. 이 작업은 초안 PR에서 진행 중입니다.

백엔드가 동적 메타데이터 플러그인을 공유하는 데 쓸 수 있는 플러그인 시스템을 제공하는 dynamic-metadata 프로젝트는 이러한 가능성을 허용하도록 설계되었으며, 위와 비슷한 PR을 통해 메타데이터를 추가할 수 있게 될 것입니다.

하위 호환성

이 PEP 이전에는 이것이 엄격히 허용되지 않았으므로, 기존 pyproject.toml 파일에는 아무런 영향을 주지 않습니다.

사용자가 pyproject.toml에서 이 기능을 사용하면 백엔드가 이를 지원해야 합니다. 백엔드가 지원하지 않으면 이전 표준에 따라 올바르게 오류가 발생합니다. 프런트엔드는 오류를 발생시키도록 요구된 적이 없지만, 일부 프런트엔드는 부분적으로 정적인 메타데이터의 이점을 누리려면 업데이트가 필요할 수 있습니다. 다른 pyproject.toml PEP와 마찬가지로, 일부 프런트엔드와 스키마 검증기 같은 기타 도구는 업데이트가 필요할 수 있습니다.

정적 분석 도구는 이 변경을 처리하려면 업데이트가 필요할 수 있습니다. 도구는 다음과 같이 dynamic 테이블을 먼저 확인해야 합니다:

match pyproject["project"]:
    # New in PEP 808
    case {my.key: value, "dynamic": dyn} if my.key in dyn:
        print(f"Partial {my.key}: {value}")
    case {"dynamic": dyn} if my.key in dyn:
        print(f"Fully dynamic {my.key}")
    case {my.key: value}:
        print(f"Fully static {my.key}: {value}")
    case _:
        print(f"No metadata for {my.key}")

이 PEP 이전에는 project 테이블에 항목이 있으면 그 항목은 동적일 수 없다고 가정하고, 도구가 dynamic 블록과 정적 블록의 순서를 뒤바꿀 수 있었습니다. 그렇게 하면 이제 도구는 실제로는 필드의 메타데이터 중 일부만 가지고 있으면서도 전부를 가지고 있다고 잘못 가정하게 됩니다.

보안 영향

이것은 기존의 동적 메타데이터 지원에 정적 구성 요소를 추가할 뿐이므로, 기존에 없던 새로운 보안 문제는 생기지 않습니다.

교육 방법

현재 동적 메타데이터를 사용하고 있지만 일부 목록이나 테이블 항목을 정적으로 알 수 있다면, 이제 [project] 테이블에 정적 항목을 추가하여 이를 명시적으로 나타내면서, 빌드 백엔드가 동적 부분을 추가할 수 있도록 project.dynamic 목록에도 해당 항목을 그대로 유지할 수 있습니다.

메타데이터를 [project]와 project.dynamic 양쪽에 나열해서는 안 된다고 설명하는 현재 가이드는, project.dynamic으로 표시된 목록과 테이블도 정적 항목을 가질 수 있다고 설명하도록 업데이트할 수 있습니다. 동적 메타데이터는 이미 고급 개념이므로, 입문용 패키징을 대상으로 하는 기존 튜토리얼 자료 대부분에는 영향을 주지 않을 것입니다.

pyproject.toml 명세는 필드가 지정되어 있으면서 dynamic 필드에도 나열된 경우의 동작을 포함하도록 업데이트됩니다.

또한 dynamic에 무언가를 지정하면, 전체 메타데이터가 필요한 도구는 해당 항목이 부분적으로 정적으로 지정되어 있더라도 백엔드를 호출해야 한다는 점에 유의해야 합니다. 따라서 다른 동적 메타데이터와 마찬가지로, 꼭 필요한 경우가 아니면 사용하지 않아야 합니다.

기각된 아이디어

dynamic을 추가하지 않고 일부 필드를 특수 처리하기

이 방안은 특히 빌드 의존성 고정 사용 사례에서 제기되었지만, 나열된 다른 사용 사례에도 적용할 수 있습니다. 그러나 이 방안으로는 확인된 모든 사용 사례를 다룰 수 없으며, 정적 도구에는 명시적인 옵트인 방식이 더 낫습니다.

문자열 필드 포함하기

일부 문자열 필드도 확장할 수 있습니다. 특히 license 필드는 확장할 수 있으면 이점이 있으며, SPDX 표현식의 의미 체계상 확장은 AND를 통해 정의할 수 있습니다. 그렇게 하려면 개별 필드마다 고유한 의미 체계가 필요하므로 이 PEP에는 추가하지 않았습니다.

그 밖의 문자열 필드, 즉 version과 requires-python은 (name은 동적으로 지정할 수 없습니다) 확장할 이유가 더 적습니다. 폐기된 license.text/license.file이나 readme.text/readme.file과 같은 고정 키 테이블 역시 부분적으로 동적이 되어서 얻는 뚜렷한 이점이 없습니다.

백엔드에 대한 제한을 완전히 제거하기

또 다른 방법은 필드가 정적으로 정의되어 있으면서 dynamic 배열에도 있는 경우 백엔드가 원하는 대로 무엇이든 할 수 있도록 그냥 허용하는 것입니다. 이렇게 하면 정적 도구가 해당 필드에 대해 아무것도 추론할 수 없게 되며, 사용자가 입력한 내용을 백엔드가 무시하거나 변경할 수 있게 되므로 사용자에게 혼란을 줄 수도 있습니다. 이는 정적 도구와 동적 메타데이터에 관한 현재 상황보다 나쁘지는 않지만, 현재 제안은 정적 도구가 동적 필드에 대해 일부 사항을 추론할 수 있는 능력을 향상합니다. 예를 들어, 대부분의 애플리케이션에서는 의존성에 대해 아무것도 모르는 것보다 의존성 중 일부라도 아는 편이 더 낫습니다.

단순화 허용하기

이 PEP의 초기 초안에는 백엔드가 일부 유형의 필드를 단순화할 수 있도록 허용하는 절이 있었습니다. 가장 대표적으로, 의존성 지정자에서는 예를 들어 torch를 torch>=1.2로 바꾸는 것과 같은 “조이기”가 허용되었을 것입니다. 이 조항은 현재 명세 내에서 변형된 결과가 모든 리졸버에서 동일하게 해석되도록 보장하는 것이 불가능하다는 점 때문에, 그리고 백엔드와의 계약을 단순화하기 위해 제거되었습니다. 그 밖의 단순화는 순전히 겉모양에 관한 것일 뿐이므로 제외되었습니다. 이제 현재 PEP에서는 순서가 원래의 정적 메타데이터와 일치해야 하며, 동적 부분에서는 삽입만 허용됩니다.

동적 메타데이터를 지정하는 일반적인 메커니즘 추가하기

이 PEP는 동적 메타데이터를 지정하는 방법을 다루지 않습니다. 이는 계속해서 전적으로 백엔드에 맡겨집니다. 이전의 초안 제안에서는 이를 다루었지만, 대신 라이브러리(궁금하신 분들을 위해 밝히면 dynamic-metadata)로 개발하는 편이 더 낫다고 판단되었습니다. 이 문제는 향후 다시 검토될 수 있습니다.

참고 문헌