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

Python 개선 제안 한국어 번역

PEP 825 – Wheel 변형: 패키지 형식

Author:
Jonathan Dekhtiar <jonathan at dekhtiar.com>, Michał Górny <mgorny at quansight.com>, Konstantin Schütze <konstin at mailbox.org>, Ralf Gommers <ralf.gommers at gmail.com>, Andrey Talman <atalman at meta.com>, Charlie Marsh <charlie at astral.sh>, Michael Sarahan <msarahan at gmail.com>, Eli Uriegas <eliuriegas at meta.com>, Barry Warsaw <barry at python.org>, Donald Stufft <donald at stufft.io>, Andy R. Terrel <andy.terrel at gmail.com>
PEP-Delegate:
Paul Moore <p.f.moore at gmail.com>
Discussions-To:
Discourse thread
Status:
Draft
Type:
Standards Track
Topic:
Packaging
Created:
17-Feb-2026
Post-History:
17-Feb-2026

Table of Contents

번역·라이선스 안내

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

초록

이 PEP는 추가 호환성 데이터를 포함하면서 동일한 패키지의 여러 변형을 빌드할 수 있도록 하는, Binary distribution format의 확장인 변형 wheel의 데이터 형식을 제공합니다. 이 데이터는 wheel 내부에 저장되며, 파일 이름에 사람이 읽을 수 있는 변형 레이블로 표현됩니다.

wheel이 색인에서 호스팅되는 경우, 최적화를 위해 별도의 JSON 파일에도 추가로 공개됩니다. 이후 변형 wheel의 나머지 측면을 정의하는 추가 PEP가 이어질 예정입니다. 이 명세의 최종 목표는 GPU 지원과 같은 추가 호환성 차원을 고려해야 하는 패키지에서 {tool} install {package}이 가장 적합한 변형을 선택할 수 있도록 하는 것입니다.

동기

이 PEP는 Platform compatibility tags가 충분하지 않은 상황에서 도구가 사용할 올바른 패키지를 선택할 수 있도록, 바이너리 패키지에 추가 호환성 데이터를 기록하는 프로토콜을 제안합니다. 특히 과학 및 머신 러닝(ML) 라이브러리의 경우처럼 이러한 기능이 필요한 사례는 많으며, 이 경우 높은 성능을 내려면 사용자의 환경에서 이용 가능한 정확한 하드웨어에 맞게 신중하게 조정된 확장 코드가 필요합니다. 잘 알려진 예는 다음과 같습니다.

  • 사용자의 GPU 하드웨어와 드라이버에 의존하는 PyTorch 및 기타 ML 도구입니다.
  • 서로 다른 선형 대수 라이브러리에 링크할 수 있는 SciPy와 같은 과학 라이브러리입니다.
  • 서로 다른 OpenMP 런타임에 링크할 수 있는 XGBoost와 같은 라이브러리입니다.
  • AVX2 또는 AVX-512와 같은 특정 CPU 명령어 집합을 이용할 수 있을 때 사용할 수 있는 성능 향상 빌드를 제공하는 라이브러리입니다.

이 문제 영역은 PEP 817에서 더 자세히 다루어졌습니다.

명세

정의

이 문서에서 “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, “OPTIONAL”이라는 핵심 단어는 RFC 2119에 설명된 의미로 해석해야 합니다.

구현 요구 사항

이 명세는 변형 wheel, 변형 메타데이터 파일 또는 pylock.toml 파일과 같이 이 명세에서 정의되거나 변경된 다양한 파일 형식을 생성하는 도구의 관점에서 작성되었습니다. 형식 정의의 맥락에서 “MUST”라는 단어는 데이터가 이 명세에 따라 유효한 것으로 간주되려면 해당 요구 사항을 충족해야 함을 구체적으로 나타냅니다.

이 명세에 따라 데이터 형식을 생성하는 도구는 항상 이 명세의 요구 사항을 충족하는 파일을 생성해야 합니다.

이 명세의 데이터 형식을 사용하는 도구는 데이터가 이러한 요구 사항을 충족하는지 확인할 필요가 없습니다. 도구는 해당 데이터가 명세 형식을 충족하지 않는다고 확인한 데이터에 의존해서는 안 됩니다. 적절한 대응은 도구의 역할에 따라 달라지며, wheel 파일의 유효하지 않은 Core Metadata에 대한 대응과 동일한 방식을 따릅니다. 패키지 색인이 업로드를 수락하는 경우처럼 생태계에 데이터가 유입되는 시점에 유효하지 않은 데이터를 거부할 수 있는 위치에 있는 도구는 그렇게 해야 합니다. 의존성을 해결하는 설치 프로그램처럼 나중에 유효하지 않은 데이터를 접한 도구는 완전히 실패하기보다 우아하게 성능을 저하하는 방식을 우선해야 하며, 예를 들어 변형 wheel을 무시하고 남은 wheel 중에서 선택해야 합니다.

변형 wheel

변형 wheel은 Binary distribution format에 정의된 wheel 형식의 확장입니다. 변형 wheel은 파일 이름에 Variant label을 지정해야 하며, 이로써 일반 wheel과 구별됩니다. 변형 wheel은 Variant metadata 파일을 포함해야 하며, 이 파일은 변형 레이블을 0개 이상의 Variant properties에 매핑합니다.

변형 속성

변형 속성은 Platform compatibility tags에 더하여 특정 플랫폼과 바이너리 패키지의 호환성을 표현합니다. 변형 속성은 키-값 형식을 따르며, 여기서 키를 변형 기능이라고 합니다. 키는 독립적으로 관리되는 변형 네임스페이스로 다시 그룹화됩니다. 따라서 변형 기능은 네임스페이스와 기능 이름으로 구성되는 반면, 변형 속성은 네임스페이스, 기능 이름 및 기능 값으로 구성됩니다.

변형 속성은 다음 형식의 구조화된 3-튜플로 직렬화됩니다.:

{namespace} :: {feature_name} :: {feature_value}

휠을 빌드할 때 사용된 속성은 휠 내부의 Variant metadata 파일에 저장됩니다. 변형 휠은 하나의 변형 기능에 대응하는 여러 값을 지정할 수 있습니다. 휠이 시스템과 호환되는 것으로 간주되려면, 해당 속성에 나열된 모든 기능에 대해 하나 이상의 값이 시스템과 호환되어야 합니다. 속성이 0개인 변형 휠은 항상 호환되는 것으로 간주됩니다.

네임스페이스와 기능 이름 구성 요소는 비어 있지 않아야 하며 0-9, a-z_ ASCII 문자로만 구성되어야 합니다(^[a-z0-9_]+$). 기능 값은 비어 있지 않아야 하며 0-9, a-z, _. ASCII 문자로만 구성되어야 합니다(^[a-z0-9_.]+$).

사용 가능한 속성과 해당 호환성을 규정하는 규칙은 이후 PEP에서 정의됩니다.

예:

# the system must be compatible with all of the following
x86_64 :: level :: v3
x86_64 :: avx512_bf16 :: on
nvidia :: cuda_version_lower_bound :: 12.8
# it must also be compatible with at least one of the following
nvidia :: sm_arch :: 120_real
nvidia :: sm_arch :: 110_real

변형 레이블

원래 PEP 427에서 정의한 휠 파일명 템플릿은 다음과 같이 변경됩니다:

{distribution}-{version}(-{build tag})?-{python tag}-{abi tag}-{platform tag}(-{variant label})?.whl
                                                                             +++++++++++++++++++

Python 태그 구성 요소는 숫자로 시작해서는 안 됩니다.

변형 휠은 변형 레이블 구성 요소를 반드시 포함해야 합니다. 반대로 변형 레이블이 없는 휠은 비변형 휠입니다. 변형 레이블은 비어 있지 않아야 하며 0-9, a-z, _. ASCII 문자로만 구성되어야 합니다(^[0-9a-z_.]+$).

모든 변형 레이블은 특정 변형 속성 집합에 고유하게 대응해야 하며, 단일 패키지 버전 내에서 동일한 레이블을 사용하는 모든 휠에 대해 그 집합은 동일해야 합니다.

null 레이블은 예약되어 있으며 항상 속성이 0개인 변형에 대응합니다. 이를 널 변형이라고 합니다. 이 변형은 항상 호환되는 대체 변형으로 작동합니다.

예:

  • 비변형 휠: numpy-2.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl
  • 변형 레이블이 x86_64_v3인 휠: numpy-2.3.2-cp313-cp313t-musllinux_1_2_x86_64-x86_64_v3.whl
  • 널 변형: numpy-2.3.2-cp313-cp313t-musllinux_1_2_x86_64-null.whl

변형 메타데이터

변형 휠에 특화된 추가 메타데이터는 JSON 형식을 사용하여 휠 내부의 *.dist-info/variant.json 파일에 저장됩니다. 이 PEP는 다음 구조를 정의합니다:

+- $schema
+- default-priorities
|  +- namespace        : list[str]
+- variants
  +- {variant_label}
     +- {namespace}
        +- {feature}   : list[str]  = []

이 구조는 형식의 버전 0.1.1에 해당합니다. 버전 번호는 Schema URL의 일부로 저장됩니다. 버전 번호는 시맨틱 버전 관리를 따릅니다.

0으로 시작하는 번호는 초안용으로 예약되어 있으며 프로덕션에서 사용해서는 안 됩니다. 도구는 이러한 버전에 대해 어떠한 호환성 가정도 해서는 안 됩니다. 제안이 완료되면 최신 초안이 버전 1.0.0으로 승격됩니다.

사양에 하위 호환성을 깨는 변경이 이루어지는 경우 주 버전 번호를 증가시키고 나머지 버전 구성 요소는 0으로 설정해야 합니다. 도구는 지원하지 않는 주 버전 번호가 포함된 메타데이터를 거부해야 합니다. 이러한 변경을 도입하는 사양 업데이트에서는 추가적인 하위 호환성 및 전환 관련 고려 사항을 제시할 수 있습니다.

사양에 하위 호환 가능한 변경이 이루어지는 경우 부 버전 번호를 증가시키고 패치 번호는 0으로 설정해야 합니다. 변형 메타데이터만 사용하는 설치 관리자 및 기타 도구는 주 버전이 지원되는 경우 최신 지원 버전보다 더 새로운 부 버전 번호가 포함된 메타데이터를 수락하는 것이 좋습니다. 변형 메타데이터를 출력하는 도구는 명시적으로 지원하지 않는 버전을 출력해서는 안 됩니다.

최상위 키와 해당 범위 및 일관성 요구 사항은 다음 섹션에서 설명합니다.

스키마

$schema키는 사용되는 JSON 스키마를 지정하는 표준 방법입니다. 해당 값은 이 사양에 대응하는 JSON 스키마의 URL이어야 하며, packaging.python.org에서 호스팅되어야 합니다. 스키마 URL에는 버전 번호가 포함되어야 하며, 따라서 모든 스키마는 일치하는 형식 버전을 설명해야 합니다. 스키마는 JSON 파일을 처리하기 전에 또는 출력한 후에 해당 파일의 유효성을 확인하는 데 사용할 수 있습니다.

이 PEP의 부록에는 현재 형식 버전에 대한 제안된 JSON 스키마가 포함되어 있습니다. 메타데이터 형식을 변경하는 후속 PEP에는 업데이트된 스키마 버전이 포함됩니다. 스키마는 부록: 변형 메타데이터용 JSON 스키마에서 사용할 수 있습니다.

기본 우선순위

default-priorities딕셔너리는 변형 순서 지정에 사용되는 네임스페이스의 순서를 정의합니다. 정확한 알고리즘은 Variant ordering 섹션에 설명되어 있습니다.

다음 키가 필수입니다.

  • namespace: list[str]: 특정 패키지 버전의 변형 휠에서 사용되는 모든 변형 네임스페이스를 우선순위가 높은 순서로 정렬한 목록입니다. 이 목록은 변형 속성에 사용되는 모든 네임스페이스를 포함해야 하며 비어 있어서는 안 됩니다. 변형 휠을 제공하는 패키지 버전은 하나 이상의 변형 네임스페이스를 사용해야 합니다.

기본 우선순위는 프로젝트 범위에서 정의됩니다. 서로 다른 휠의 값은 동일하거나 한쪽이 다른 쪽의 확장인 것이 좋습니다. 추가 네임스페이스는 뒤에 추가할 수 있습니다. 더 긴 목록이 더 짧은 목록의 요소로 동일한 순서로 시작하면 메타데이터가 일관된 것으로 간주됩니다. 이 경우 메타데이터를 결합하면 더 긴 목록을 사용해야 합니다.

변형

variants 딕셔너리는 변형 레이블에서 변형 속성으로의 매핑을 제공합니다. 개별 변형 휠에서는 해당 휠에 범위가 지정되며, 해당 휠의 파일 이름에 포함된 변형 레이블을 키로 하는 항목을 정확히 하나 포함해야 합니다.

3개 수준으로 구성됩니다. 첫 번째 수준의 키는 변형 레이블이고, 두 번째 수준의 키는 네임스페이스이며, 세 번째 수준의 키는 기능 이름입니다. 세 번째 수준의 값은 기능 값의 집합이며, 리스트로 변환한 후 사전순으로 정렬됩니다.

메타데이터의 일관성을 유지하려면 동일한 키가 항상 동일한 값에 대응해야 합니다. 메타데이터를 결합할 때 결과 variants 딕셔너리는 모든 입력 딕셔너리의 합집합이어야 합니다.

{
  // The schema URL will be replaced with the final URL on packaging.python.org
  "$schema": "https://variants-schema.wheelnext.dev/peps/825/v0.1.1.json",

  "default-priorities": {
    // REQUIRED: specifies that x86_64 CPU properties are more important than
    // aarch64 CPU properties (both are mutually exclusive, so the exact order
    // does not matter), and both are more important than specific BLAS/LAPACK
    // library:
    "namespace": ["x86_64", "aarch64", "blas_lapack"],
  },

  "variants": {
    // REQUIRED: in variant.json, always a single entry, with the key
    // matching the variant label ("x86_64_v3_openblas") and the value
    // specifying its properties (the system must be compatible with both):
    // - blas_lapack :: library :: openblas
    // - x86_64 :: level :: v3
    "x86_64_v3_openblas": {
      "blas_lapack": {
        "library": ["openblas"]
      },
      "x86_64": {
        "level": ["v3"]
      }
    }
  }
}

색인 수준 메타데이터

하나 이상의 변형 휠을 포함하는 패키지 버전이 패키지 색인에 호스팅되는 경우, 해당하는 {name}-{version}-variants.json 파일도 함께 호스팅되어야 합니다. 이 파일의 목적은 의존성 해결 중 여러 변형 휠을 가져올 필요를 없애 변형 메타데이터 조회를 최적화하는 것입니다. {name}{version} 자리 표시자는 Binary Distribution Format 사양의 File name convention에 명시된 휠 파일과 동일한 규칙에 따라 정규화된 패키지 이름과 버전에 해당합니다.

파일이 호스팅되는 정확한 URL은 중요하지 않지만, 변형 휠이 포함된 모든 응답에서 해당 URL이 제공되어야 합니다. 이 URL은 Simple repository API의 파일 규칙을 따라야 하지만, 색인이 제공하는 선택적 메타데이터 속성(예: core-metadata, dist-info-metadata, requires-python 또는 yanked)은 해당 파일에 의미가 없습니다. 색인은 이러한 속성을 생략해야 하며, 도구는 이를 무시해야 합니다.

이 파일은 Variant metadata와 동일한 구조를 사용하지만, variants 객체의 범위는 색인으로 지정되며 해당 패키지 버전에 대해 패키지 색인에서 사용할 수 있는 모든 변형을 나열해야 합니다. 이 파일은 개별 휠의 Variant metadata와 일관되어야 하며, 이는 Metadata consistency에 명시된 바와 같습니다.

클라이언트가 색인 수준 메타데이터 파일에 나열되지 않은 레이블의 변형 휠을 발견하면, 해당 휠을 무시하거나 휠에서 변형 메타데이터를 직접 가져오도록 선택할 수 있습니다.

이 파일은 불변으로 간주해서는 안 되며, 언제든지 하위 호환 방식으로 업데이트할 수 있습니다(예: 새 변형을 추가하는 경우).

변형 색인은 업로드된 변형 휠에서 파일을 자동으로 생성하거나, 사용자가 직접 파일을 생성하여 색인에 업로드하도록 허용할 수 있습니다.

동일한 {name}-{version}-variants.json 파일을 다른 (도구별) 휠 모음에서 변형 휠과 함께 게시할 수도 있습니다. 그 예로 흔히 사용되는 --find-links 옵션이 참조하는 디렉터리를 들 수 있습니다.

이전 예에 나열된 변형 중 하나를 포함하여 두 개의 휠 변형이 있는 패키지에 해당하는 foo-1.2.3-variants.json 파일은 다음과 같이 표시됩니다:

{
  // The schema URL will be replaced with the final URL on packaging.python.org
  "$schema": "https://variants-schema.wheelnext.dev/peps/825/v0.1.1.json",
  "default-priorities": {
    // identical to above
  },
  "variants": {
    // REQUIRED: entries for all wheel variants for the package version

    // if a null variant is present
    "null": {},

    // "x86_64_v3_openblas" label corresponds to:
    // - blas_lapack :: library :: openblas
    // - x86_64 :: level :: v3
    "x86_64_v3_openblas": {
      "blas_lapack": {
        "library": ["openblas"]
      },
      "x86_64": {
        "level": ["v3"]
      }
    },

    // "x86_64_v4_mkl" label corresponds to:
    // - blas_lapack :: library :: mkl
    // - x86_64 :: level :: v4
    "x86_64_v4_mkl": {
      "blas_lapack": {
        "library": ["mkl"]
      },
      "x86_64": {
        "level": ["v4"]
      }
    }
  }
}

메타데이터 일관성

패키지 버전의 개별 변형 휠이 포함하는 Variant metadata와 게시되는 경우 해당 Index-level metadata 파일은 모두 동일한 릴리스를 설명하며 서로 일치해야 합니다. 이를 한곳에 모아 각각의 키를 정의하는 섹션에 전체 내용을 명시하면, 요구 사항은 다음과 같습니다.

  • default-priorities.namespace: 목록은 반드시 동일하거나, 더 긴 목록이 더 짧은 목록의 요소로 같은 순서로 시작해야 합니다. 이를 결합하면 반드시 더 긴 목록이 되어야 합니다.
  • variants: 동일한 변형 레이블은 항상 동일한 속성 집합에 매핑되어야 합니다. 이를 결합하면 반드시 딕셔너리의 합집합이 되어야 합니다.

두 규칙은 대칭적이므로, 이 규칙을 충족하는 메타데이터를 결합하면 입력을 처리하는 순서와 관계없이 동일한 결과를 얻습니다.

이러한 요구 사항을 충족하는 것은 패키지 버전 게시자의 책임입니다. 데이터는 프로젝트마다 단일 소스에서 생성되고 빌드 시점에 휠에 복사되므로, 한 릴리스의 휠이 서로 다른 입력으로 빌드되지 않는 한 이러한 요구 사항은 구성상 충족됩니다.

변형 메타데이터를 소비하는 도구는 이러한 요구 사항이 충족되었다고 가정할 수 있으며, 이를 검증할 필요는 없습니다. 도구가 이러한 요구 사항이 충족되지 않았음을 확인한 경우에는 Implementation requirements에 설명된 대응이 적용됩니다.

사용자가 동일한 패키지의 휠을 둘 이상의 게시된 소스에서 가져오는 경우, 어떤 게시자도 다른 소스와의 일관성을 보장할 수 없습니다. 결합되는 소스의 일관성을 보장하는 것은 사용자의 책임입니다. 도구는 소스 간의 불일치를 감지하거나 해결할 필요가 없습니다. 대신 도구가 합리적으로 수행할 수 있는 작업은 Installing wheels from multiple sources (non-normative)에 설명되어 있습니다.

변형 정렬

이 사양은 변형 메타데이터의 존재 여부를 기반으로 서로 다른 휠 간의 정렬 순서를 정의합니다.

정렬을 위해 후보 변형 휠 모두에 대한 결합된 변형 메타데이터를 반드시 가져와야 합니다. 이는 Index-level metadata 파일에서 가져오거나, Variant metadata 섹션에 지정된 대로 개별 휠에서 결합하여 가져올 수 있습니다. 두 소스는 일관성이 있어야 하므로 동일한 결과를 산출하며, 데이터를 가져오는 비용이 훨씬 저렴하므로 도구는 인덱스 수준 메타데이터 파일을 사용할 수 있는 경우 이를 우선적으로 사용해야 합니다.

자격을 충족하는 모든 변형 휠의 변형 속성은 기능으로 그룹화되고, 기능은 네임스페이스로 그룹화됩니다. 도구는 각 네임스페이스에 대해 호환 가능한 기능 목록을, 각 기능에 대해 호환 가능한 값 목록을 반드시 가져와야 합니다. 이러한 목록을 가져오는 방법은 이후 PEP에서 정의됩니다. 이러한 목록의 항목은 변형 휠의 정렬 순서에 영향을 미치는 특정 순서로 제공됩니다.

특정 패키지 이름, 버전 및 빌드 번호 조합에 해당하는 호환 가능한 휠은 변형 레이블별로 반드시 그룹화해야 하며, 변형이 아닌 휠로 구성된 별도의 그룹도 반드시 만들어야 합니다. 그런 다음 변형 휠 그룹은 다음 알고리즘에 따라 반드시 정렬해야 합니다.

  1. 결합된 변형 메타데이터에서 default-priorities.namespace 키의 값을 복사하여 네임스페이스의 정렬된 목록을 구성합니다. 예제에서는 이것이 namespace_order입니다.
  2. 각 네임스페이스에 대해 앞서 가져온 호환 가능한 기능 이름의 정렬된 목록을 사용합니다. 예제에서는 이것이 feature_order입니다.
  3. 각 기능에 대해 앞서 가져온 호환 가능한 값의 정렬된 목록을 사용합니다. 예제에서는 이것이 value_order입니다.
  4. 각 그룹에 대해 해당 그룹의 변형 속성에 존재하는 모든 변형 기능에 대응하는 가장 선호되는 값을 결정합니다. 이는 값 중 정렬된 속성 값 목록에서 위치가 가장 낮은 값을 찾는 방식으로 수행합니다. 이 단계가 끝나면 각 변형에 대해 기능과 해당 기능의 최적 값으로 구성된 목록을 사용할 수 있습니다. 예제에서는 VariantWheel.best_value_properties() 메서드로 이를 수행합니다.
  5. 이전 단계에서 구성한 목록의 각 항목에 대해 해당 항목의 네임스페이스, 기능 이름 및 최적 기능 값의 각 정렬 목록 내 인덱스로 구성된 3-튜플을 정렬 키로 구성합니다. 예제에서는 property_key() 함수로 이를 수행합니다.
  6. 각 그룹에 대해 4단계에서 구성한 목록을 5단계에서 구성한 정렬 키를 사용하여 오름차순으로 정렬합니다. 예제에서는 VariantWheel.sorted_properties() 메서드로 이를 수행합니다.
  7. 그룹의 순서를 정하려면 6단계에서 얻은 정렬된 목록을 비교합니다. 첫 번째 위치의 정렬 키가 서로 다르면 키가 더 낮은 그룹을 더 먼저 정렬합니다. 키가 같으면 동률 판정 기준이 발견되거나 그룹 중 하나의 목록이 소진될 때까지 두 번째 위치의 키를 비교하고, 이후에도 같은 방식으로 진행합니다. 후자의 경우에는 키가 더 많은 그룹을 더 먼저 정렬합니다. 대안으로, 두 그룹의 키 수가 같으면 변형 레이블을 기준으로 오름차순의 사전식 순서로 정렬합니다. 이는 예제 알고리즘의 마지막 단계에서 수행되며, 비교 함수는 VariantWheel.__lt__()로 구현됩니다.

이 알고리즘은 null 변형 휠 그룹에 변형 속성이 없으므로 이를 마지막에 정렬합니다. 비변형 휠 그룹은 다른 모든 그룹 뒤에 배치해야 합니다.

각 그룹 내에서 휠은 이후 플랫폼 호환성 태그에 따라 정렬해야 합니다. 이 과정이 끝나면 변형 휠은 가장 선호되는 것부터 가장 덜 선호되는 것까지 정렬됩니다.

도구는 기본 순서를 재정의하는 옵션을 제공할 수 있으며, 예를 들어 특정 네임스페이스, 기능 또는 속성에 대한 선호도를 지정할 수 있습니다. 도구는 특정 변형을 제외하거나 특정 변형을 선택하는 옵션도 제공할 수 있습니다. 이러한 옵션은 호환되는 것으로 확인된 휠에 적용되므로 해당 집합을 재정렬하거나 축소할 수 있지만, 대상 시스템이 지원하지 않는 속성을 가진 휠을 선택하게 해서는 안 됩니다. 설치 대상 시스템이 아닌 다른 시스템을 위한 변형 휠을 설치하는 것은 지원되는 것으로 간주할 속성을 재정의하는 문제이며, 이는 이 PEP에서 Out of scope인 사항입니다.

또는 다음 의사 코드로 변형 휠의 정렬 알고리즘을 설명할 수 있습니다. 간단히 하기 위해 이 코드는 비변형 휠이나 이후의 플랫폼 호환성 태그에 따른 정렬을 고려하지 않습니다.

from typing import Self


def get_compatible_feature_names(namespace: str) -> list[str]:
    """Get an ordered list of compatible features"""
    ...


def get_compatible_feature_values(namespace: str, feature_name: str) -> list[str]:
    """Get an ordered list of compatible values"""
    ...


# default-priorities dict from combined variant metadata
default_priorities = {
    "namespace": [...],  # : list[str]
}

# 1. Obtain the ordered list of namespaces from the variant metadata.
namespace_order = default_priorities["namespace"]
# 2. Obtain the ordered lists of features.
feature_order = {
    namespace: get_compatible_feature_names(namespace)
    for namespace in namespace_order
}
# 3. Obtain the ordered lists of feature values.
value_order = {
    namespace: {
        feature_name: get_compatible_feature_values(namespace, feature_name)
        for feature_name in feature_order[namespace]
    } for namespace in namespace_order
}


def best_value_property(namespace: str, feature_name: str, feature_values: str) -> str:
    """Helper function to determine the best value for given feature"""
    for best_value in value_order[namespace][feature_name]:
        if best_value in feature_values:
            return best_value
    assert False, "No feature value supported, wheel should have been filtered out"


def property_key(prop: tuple[str, str, str]) -> tuple[int, int, int]:
    """Construct a sort key for variant property (akin to step 5)"""
    namespace, feature_name, feature_value = prop
    return (
        namespace_order.index(namespace),
        feature_order[namespace].index(feature_name),
        value_order[namespace][feature_name].index(feature_value),
    )


class VariantWheel:
    """Example class exposing properties of a variant wheel"""

    label: str
    # {namespace: {feature_name: [feature_values]}}, as in variant.json
    properties: dict[str, dict[str, list[str]]]

    def best_value_properties(self: Self) -> list[tuple[str, str, str]]:
        """Determine the most preferred values for every feature, step 4"""
        return [
            (
                namespace,
                feature_name,
                best_value_property(namespace, feature_name, feature_values),
            )
            for namespace, features in self.properties.items()
            for feature_name, feature_values in features.items()
        ]

    def sorted_properties(self: Self) -> list[tuple[str, str, str]]:
        """Sort the list of features with their best values (step 6)"""
        return sorted(self.best_value_properties(), key=property_key)

    def __lt__(self: Self, other: Self) -> bool:
        """Variant comparison function for sorting (part of step 7)"""
        self_properties = self.sorted_properties()
        other_properties = other.sorted_properties()
        # Proceed from the first to the last common sort best-value property.
        # If any of them are different, the variant with better property wins.
        for self_prop, other_prop in zip(self_properties, other_properties):
            if self_prop != other_prop:
                return property_key(self_prop) < property_key(other_prop)
        # If the best-value properties of one variant are a subset of another,
        # the one with more properties wins.
        if len(self_properties) != len(other_properties):
            return len(self_properties) > len(other_properties)
        # If two variants have exactly the same properties, fall back to
        # sorting on variant label (they must be unique).
        return self.label < other.label


# A list of variant wheels to sort.
variant_wheels: list[VariantWheel] = [...]


# 7. Order variant wheels by comparing their sorted properties
# (see VariantWheel.__lt__())
variant_wheels.sort()

환경 마커

종속성 명세에 네 가지 새로운 environment markers가 도입됩니다. 관련 Dependency specifiers 명세에 정의된 마커와 달리, 해당 값은 모든 휠에서 동일하지 않습니다. 처리 중인 휠이 빌드된 대상인 변형 속성으로 범위가 한정됩니다. Evaluating variant markers에 설명된 대로 이를 얻어야 합니다. 다음과 같습니다:

  1. variant_label: 처리 중인 휠의 정확한 변형 레이블을 나타내는 문자열입니다. 비변형 휠의 경우 빈 문자열입니다.
  2. variant_properties: 대상 시스템과 호환되는, 변형 레이블에 해당하는 속성의 모든 namespace :: feature :: value 튜플 집합입니다. 비변형 휠의 경우 빈 집합입니다.
  3. variant_features: variant_properties에 있는 속성에 해당하는 모든 namespace :: feature 쌍의 집합입니다.
  4. variant_namespaces: variant_properties에 있는 모든 속성의 모든 네임스페이스 집합입니다.

variant_labelString 필드이고, variant_properties, variant_featuresvariant_namespacesSet of String 필드입니다. 각 필드에 사용할 수 있는 연산자와 그 의미는 Dependency specifiers에 정의된 해당 필드 형식의 것과 같습니다.

구현은 기능과 속성을 일치시킬 때 :: 구분자 주위의 공백 차이를 무시해야 합니다.

변형 마커 평가

변형 마커는 반드시 의존성 지정자에서만 사용해야 하며, 휠을 선택하는 데 관여해서는 안 됩니다. 이러한 마커는 이미 선택된 휠의 개별 의존성 지정자를 제한합니다. 이러한 마커는 Variant ordering에 설명된 변형 휠 선택이 완료된 후에만 평가해야 합니다.

해당 값은 다음과 같이 결정해야 합니다.

  1. variant_label은 파일 이름에 나타난 선택된 휠의 변형 레이블입니다.
  2. Variant metadatavariants딕셔너리가 해당 레이블에 매핑하는 속성을 가져와, 나열된 각 기능 값에 대해 namespace :: feature :: value트리플로 확장합니다. 일관성 요구 사항에 따라 두 메타데이터가 일치하므로, 휠 자체에 포함된 Variant metadata 또는 Index-level metadata를 사용할 수 있습니다.
  3. 확장된 트리플 집합을 변형 휠 선택 중에 이미 결정된 대로 대상 시스템이 지원하는 변형 속성으로 필터링합니다. 그 결과가 variant_properties입니다. 휠은 대상 시스템이 이를 지원하는 경우에만 선택될 수 있으며, 이를 위해서는 휠이 선언하는 모든 기능에 대해 하나 이상의 지원되는 값이 필요하므로, 이 단계에서 기능이 완전히 제거되는 일은 없습니다.
  4. variant_featuresvariant_namespacesvariant_properties에서 파생됩니다.

변형이 없는 휠의 경우 variant_label은 빈 문자열이고, 집합 값을 갖는 세 가지 마커는 빈 집합입니다. 이러한 휠의 변형 마커를 평가하는 데는 변형 메타데이터가 필요하지 않습니다.

예시

다음 의존성 지정자는 네 가지 마커와 각 마커에 허용되는 연산자를 보여 줍니다.

# satisfied by the variant "foobar"
dep1; variant_label == "foobar"
# satisfied by any wheel other than the null variant
# (including the non-variant wheel)
dep2; variant_label != "null"
# satisfied by the non-variant wheel
dep3; variant_label == ""
# satisfied by any "foo :: * :: *" property
dep4; "foo" in variant_namespaces
# satisfied by any "foo :: bar :: *" property
dep5; "foo :: bar" in variant_features
# satisfied only by "foo :: bar :: baz" property
dep6; "foo :: bar :: baz" in variant_properties
# equivalent
dep7; "foo::bar::baz" in variant_properties

3단계의 필터링은 변형 기능에 여러 값이 나열되어 있고, 그중 대상 시스템이 하나만 지원하면 되는 경우에만 관찰할 수 있습니다(Variant properties참조). 속성에 다음 두 항목이 모두 포함된 휠을 고려하십시오.

nvidia :: sm_arch :: 120_real
nvidia :: sm_arch :: 110_real

두 아키텍처를 모두 제공하는 시스템에서는 variant_properties에 두 속성이 모두 포함됩니다. 전자만 제공하는 시스템에서는 nvidia :: sm_arch :: 120_real만 포함되므로, nvidia :: sm_arch :: 110_real을 검사하는 의존성 지정자는 충족되지 않습니다.

pylock.toml과의 통합

변형 휠은 플랫폼 호환성 태그가 서로 다른 휠과 동일한 방식으로 pylock.toml 파일에 나열할 수 있습니다. 즉, 모든 변형 휠과 비변형 휠을 나열하거나 그 일부만 나열할 수 있습니다.

파일에 새로운 [packages.variants-json]하위 테이블이 추가됩니다. 이 테이블은 Index-level metadata파일과 동일한 형식에 따라 결합된 변형 메타데이터를 인라인으로 포함해야 하며, JSON 구조를 해당 TOML 형식으로 변환해야 합니다. 버전 관리를 용이하게 하려면 $schema키를 보존해야 합니다. 도구는 패키지에 나열된 휠에 레이블이 나타나지 않는 variants딕셔너리의 항목과, 그 결과 default-priorities.namespace에서 사용되지 않게 된 네임스페이스를 제거할 수 있습니다. 실제로 나타나는 모든 레이블의 항목은 전체를 보존해야 합니다. Evaluating variant markers에서는 선택된 레이블에 해당하는 전체 속성 집합이 필요하기 때문입니다.

변형 휠이 나열된 경우, 도구는 최적의 휠 파일을 선택하도록 변형을 해석해야 합니다.

잠긴 패키지의 의존성 지정자에 포함된 변형 Environment markersEvaluating variant markers에 설명된 대로 해당 패키지 항목에 선택된 휠의 컨텍스트에서 평가됩니다. 잠금 파일에는 추가 컨텍스트가 필요하지 않습니다. 해당 휠이 선택된 후에만 마커가 평가되며, 각 패키지 항목이 자체 휠을 해석하기 때문입니다. 변형 마커는 의존성 지정자에서만 사용할 수 있으므로 packages.marker나 최상위 environments 키에는 나타날 수 없습니다. 이 둘은 어느 것도 선택된 휠을 범위로 하지 않기 때문입니다.

제안된 사양 업데이트

다음은 pylock.toml Specification에 제안된 텍스트입니다:

[packages.variants-json]
  • 유형: 표
  • 필수 여부: 아니요
  • 함수:
    • 패키지에 대한 인라인 변형 선택 메타데이터입니다.
    • 이 표의 구조는 JSON 스키마를 반드시 준수해야 합니다.
    • 변형 인식 해석을 지원하는 도구는 이 표를 참조된 스키마에 대해 반드시 검증해야 합니다.
    • 변형 인식 해석을 지원하지 않는 도구는 이 표를 무시해도 되지만, 잠금 파일을 다시 작성할 때는 보존해야 합니다.

예제

lock-version = "1.0"
created-by = "uv"
requires-python = ">=3.14"

[[packages]]
name = "numpy"
version = "2.3.4"
index = "https://pypi.anaconda.org/mgorny/simple"
wheels = [
    { url = "https://pypi.anaconda.org/mgorny/simple/numpy/2.3.4/numpy-2.3.4-cp314-cp314-linux_x86_64-openblas.whl", hashes = {} },
    { url = "https://pypi.anaconda.org/mgorny/simple/numpy/2.3.4/numpy-2.3.4-cp314-cp314-linux_x86_64-x86_64_v4_mkl.whl", hashes = {} },
    { url = "https://pypi.anaconda.org/mgorny/simple/numpy/2.3.4/numpy-2.3.4-cp314-cp314-macosx_13_0_x86_64-accelerate.whl", hashes = {} },
    { url = "https://pypi.anaconda.org/mgorny/simple/numpy/2.3.4/numpy-2.3.4-cp314-cp314-macosx_13_0_x86_64-openblas.whl", hashes = {} },
]

[packages.variants-json]
"$schema" = "https://variants-schema.wheelnext.dev/peps/825/v0.1.1.json"

[packages.variants-json.default-priorities]
namespace = [ "x86_64", "aarch64", "blas_lapack" ]

[packages.variants-json.variants]
null = { }
x86_64_v3_openblas = { "blas_lapack" = { "library" = ["openblas"]}, "x86_64" = { "level" = ["v3"]}  }
x86_64_v4_mkl = { "blas_lapack" = { "library" = ["mkl"]}, "x86_64" = { "level" = ["v4"]}  }

도구를 위한 권장 구현 로직(비규범적)

색인에서 패키지 설치

색인에서 패키지 버전을 설치하라는 요청을 받으면 다음과 같이 동작하는 것이 제안됩니다.

  1. 해당 패키지를 원격 색인에서 조회합니다.
  2. 먼저 버전 제약 조건을 충족하는 패키지 버전을 선택합니다(이때 변형 메타데이터를 고려할 필요는 없습니다).
  3. 플랫폼 호환성 태그를 기준으로 사용 가능한 휠을 필터링합니다.
  4. 남은 휠 중 변형 휠이 있는지 확인합니다. 없다면 비변형 휠과 동일하게 진행합니다.
  5. 휠에 Variant label이 있으면 결합된 변형 메타데이터를 가져옵니다. 일반적으로 이는 Index-level metadata 파일인 {name}-{version}-variants.json을 다운로드하는 것을 의미합니다. 소스에서 해당 파일을 제공하지 않는 경우에는 후보 휠에서 결합된 메타데이터를 읽을 수도 있습니다. 서로 다른 각 변형 레이블마다 하나의 휠만 검사하면 되며, 전체 휠이 아니라 그 안의 Variant metadata 파일만 검사하면 됩니다. 그래도 비용이 너무 많이 드는 경우 도구는 변형 휠을 호환되지 않는 것으로 처리하고 대신 비변형 휠로 진행할 수 있습니다.
  6. 결합된 변형 메타데이터를 사용하여 변형 레이블을 변형 속성 집합으로 매핑합니다. 휠 파일 이름에 있는 레이블 중 결합된 메타데이터에 누락된 것이 있으면 해당 휠을 호환되지 않는 것으로 간주하거나, 5단계에 설명된 대로 휠에서 직접 메타데이터를 읽습니다.
  7. 호환 가능한 변형 속성의 정렬된 목록을 가져옵니다. 이에 대한 메커니즘은 후속 PEP에서 지정됩니다.
  8. Variant ordering에 따라 호환 가능한 속성 목록을 기준으로 변형을 필터링하고 정렬한 다음, 가장 선호되는 변형을 선택합니다. 일치하는 변형 휠이 없으면 해당 규칙에 따라 비변형 휠을 사용합니다.
  9. 특정 버전에 대한 여러 휠이 동일한 변형 레이블을 공유하면 플랫폼 호환성 태그와 빌드 번호를 기준으로 정렬하고 가장 적합한 휠을 선택합니다.
  10. 선택한 휠의 종속성을 읽고, Evaluating variant markers에 설명된 대로 선택한 휠의 레이블과 대상 시스템이 지원하는 해당 변형 속성의 레이블을 사용하여 종속성에 포함된 Environment markers를 평가합니다.

4단계부터 8단계까지는 변형 휠을 위해 특별히 도입되었다는 점에 유의하십시오. 나머지 단계는 현재 설치 프로그램의 동작에 해당합니다. 10단계는 새로운 환경 마커의 존재에 따라 수정됩니다.

동일한 알고리즘은 색인 이외의 소스, 예를 들어 휠의 로컬 디렉터리에도 적용됩니다.

특정 로컬 휠 설치

로컬 휠 파일을 설치하라는 요청을 받으면 제안되는 동작은 다음과 같습니다:

  1. 파일 이름에 변형 레이블이 없으면 변형이 아닌 휠과 동일하게 처리합니다.
  2. 플랫폼 호환성 태그를 통해 휠의 호환성을 확인합니다.
  3. 휠 파일 내부의 *.dist-info/variant.json에서 Variant metadata를 읽습니다.
  4. 호환 가능한 변형 속성의 정렬된 목록을 가져옵니다. 이 메커니즘은 후속 PEP에서 지정합니다.
  5. 호환 가능한 속성을 통해 휠의 호환성을 확인합니다.
  6. 휠의 의존성을 읽고, Evaluating variant markers에 설명된 대로 휠의 레이블과 대상 시스템이 지원하는 변형 속성의 레이블을 사용하여 의존성에 포함된 Environment markers를 평가합니다.

색인에 변형 휠 게시

변형 휠은 일반 휠과 동일한 방식으로 색인에 업로드합니다. 각 패키지 버전에 대한 색인 수준의 {name}-{version}-variants.json 파일을 게시하는 방법은 두 가지가 있습니다. 사용자가 파일을 준비하여 업로드하거나 색인이 자동으로 생성할 수 있습니다.

색인이 파일 생성을 담당하는 경우, 릴리스가 완전히 업로드될 때까지 파일 게시를 지연하는 메커니즘을 사용해야 합니다(예: PEP 694).

{name}-{version}-variants.json 파일을 생성하려면 특정 패키지 버전에 해당하는 모든 변형 휠의 *.dist-info/variant.json 파일을 가져와 Default prioritiesVariants 섹션에서 개별 키에 대해 지정된 대로 결합합니다. 결과는 휠을 처리하는 순서에 의존하지 않습니다.

설치 예시(규범적이지 않음)

PyTorch가 여러 변형 휠을 게시한다고 가정하겠습니다:

torch-2.13.0-{py}-{abi}-{platform}-cuda12.6.whl
                                   ^^^^^^^^
torch-2.13.0-{py}-{abi}-{platform}-cuda13.0.whl
                                   ^^^^^^^^
torch-2.13.0-{py}-{abi}-{platform}-cuda13.2.whl
                                   ^^^^^^^^
torch-2.13.0-{py}-{abi}-{platform}-rocm7.2.whl
                                   ^^^^^^^
torch-2.13.0-{py}-{abi}-{platform}-null.whl      # CPU-only
                                   ^^^^

강조 표시된 파일 이름 부분이 변형 레이블입니다.

이러한 각 휠에는 다음을 포함하는 변형 메타데이터 파일이 있습니다:

{
  "$schema": "https://variants-schema.wheelnext.dev/peps/825/v0.1.1.json",
  "default-priorities": {
    "namespace": ["nvidia", "amd"]
  },
  "variants": {
    // ...
  }
}

각 휠에서 variants 딕셔너리는 변형 레이블인 단일 키를 포함하며, 그 값에는 해당 레이블에 대응하는 모든 속성이 나열됩니다. 예를 들어 cuda* 변형 휠에는 NVIDIA GPU와의 호환성을 나타내는 속성이 포함되는 반면, rocm* 변형 휠에는 AMD GPU와의 호환성을 나타내는 속성이 포함됩니다. null 변형에는 속성이 없습니다.

이러한 변형 휠과 함께 개별 휠의 변형 메타데이터를 병합한 torch-2.13.0-variants.json 파일이 게시됩니다. variants 딕셔너리에 모든 변형 레이블과 해당 속성이 포함된다는 점을 제외하면 예시와 동일한 내용을 가집니다.

패키지 관리자가 torch를 설치하라는 요청을 받으면 다음 순서로 진행합니다:

  1. 사용 가능한 휠을 확인하기 위해 색인을 조회합니다. 2.13.0이 최신 버전임을 확인하고 해당 버전을 선택합니다.
  2. 사용 가능한 2.13.0 휠을 플랫폼 호환성 태그로 필터링합니다. 현재 시스템과 호환되는 휠만 남습니다.
  3. 색인 응답에서 torch-2.13.0-variants.json 파일을 찾고 다운로드합니다. 변형 레이블에서 변형 속성 집합으로의 매핑과 네임스페이스 선호 순서를 확인하기 위해 해당 파일의 내용을 읽습니다.
  4. 호환 가능한 기능 및 기능 값의 목록은 variants 딕셔너리에서 사용되는 모든 네임스페이스에 대해 가져옵니다. 이러한 목록에 없는 속성에 해당하는 변형 레이블이 지정된 휠은 호환되지 않으므로 필터링됩니다.

    예를 들면 다음과 같습니다:

    • cuda* 레이블은 값이 최소 CUDA 드라이버 버전을 지정하는 nvidia :: cuda_version_lower_bound 속성 및 값이 지원되는 GPU를 나열하는 nvidia :: sm_arch 속성에 매핑됩니다. 설치 프로그램은 호환 가능한 런타임과 호환 가능한 GPU 중 하나를 사용할 수 있는지 확인하기 위해 드라이버가 있으면 이를 조회합니다. 드라이버, 호환 가능한 런타임 버전 또는 호환 가능한 GPU를 찾지 못하면 휠이 목록에서 제거됩니다.
    • 마찬가지로 rocm* 레이블은 지원되는 ROCm 버전을 지정하는 amd :: rocm_version 속성과 지원되는 GPU를 나열하는 amd :: gfx_arch 속성에 매핑됩니다. 설치 프로그램은 앞서와 유사한 방식으로 적절한 드라이버를 조회합니다. 드라이버, 호환 가능한 런타임 버전 또는 호환 가능한 GPU를 찾지 못하면 휠이 목록에서 제거됩니다.
    • null 레이블은 항상 빈 속성 집합에 해당하므로 항상 호환됩니다.

    호환 가능한 NVIDIA GPU와 CUDA 런타임이 있는 시스템에서는 cuda* 휠 중 하나 이상과 null 휠이 목록에 남습니다.

  5. 서로 다른 여러 레이블의 변형 휠이 목록에 남아 있으면 결과가 Variant ordering의 알고리즘에 따라 정렬됩니다. 가장 선호되는 레이블이 선택됩니다.

    예를 들어 이 경우에는 4단계에서 가져온 목록을 사용하여 cuda* 휠을 해당 속성에 따라 정렬합니다. 최신 CUDA 버전이 선호되므로 CUDA 13용 휠이 CUDA 12용 휠보다 먼저 정렬됩니다. null 휠은 항상 마지막에 정렬되므로 GPU 휠이 호환되는 것이 하나도 없을 때만 선택됩니다.

  6. 이 시점에 동일한 레이블의 휠이 여러 개 목록에 남아 있으면 최종 선택은 플랫폼 호환성 태그를 기준으로 수행됩니다. 이는 드문 경우이며 여기에는 적용되지 않습니다.

    예를 들어 동일한 휠 변형이 abi3 태그와 cp315 태그가 모두 지정된 상태로 제공된 경우에 발생할 수 있습니다. Python 3.15용으로 설치할 때 설치 프로그램은 태그를 기준으로 이 둘 중 하나를 선택합니다.

  7. 선택된 휠의 메타데이터가 처리됩니다. 해당 휠에 대응하는 변형 속성 중 4단계에서 시스템이 지원하는 것으로 확인된 속성으로 범위를 좁힌 속성을 사용하여 Environment markers를 처리합니다. 그 결과 CUDA 관련 추가 종속성이 선택됩니다.

    해당 휠이 자신이 지원하는 아키텍처 중 하나만 지원하는 라이브러리에도 종속된다고 가정하십시오.

    fast-gemm; "nvidia :: sm_arch :: 120_real" in variant_properties
    

    이전 GPU가 있는 시스템에서는 120_real이 4단계에서 확인된 지원 속성에 포함되지 않으므로 범위를 좁히는 과정에서 해당 속성이 제거되고 이 종속성은 선택되지 않습니다.

  8. 휠이 다운로드되어 설치됩니다.

여러 소스에서 휠 설치하기(규범적이지 않음)

이 글을 작성하는 시점에는 여러 소스에서 패키지를 설치하는 지원을 다루는 승인된 표준이 없으며, 기존 도구들은 정확한 동작이 서로 다릅니다. 이 문제는 정보 제공용 PEP 766에서 더 자세히 설명합니다. 변형 휠은 이러한 차이를 확장합니다. 변형 메타데이터를 결합할 수 있게 하는 일관성 요구 사항은 단일 소스 트리 내에서 적용되며, 독립적인 게시자가 서로에 대해 이러한 요구 사항을 충족해야 할 의무는 없습니다. 동일한 변형 레이블이 서로 다른 속성에 매핑될 수 있고, 독립적으로 선택한 네임스페이스 순서는 서로의 확장일 필요가 없습니다. 두 소스의 메타데이터를 결합할 수 있는지 확인하는 것은 가능하지만, 일반적인 경우 이를 수행하는 비용은 감당하기 어렵고, 결합할 수 없는 경우에는 올바른 답이 없습니다. 이러한 이유로 이 사양은 동작을 표준화하려고 하지 않고, 대신 이를 구현 정의로 간주하며, 비규범적인 몇 가지 제안된 해결책을 제공합니다. 여기에는 비변형 휠을 사용하는 방법도 포함됩니다.

도구가 이 동작을 지원하지 않는 것은 전적으로 유효합니다. 여러 소스를 사용하는 기능을 아예 제공하지 않거나, 소스 중 둘 이상에 변형 휠이 포함되어 있으면 진행을 거부할 수 있습니다.

서로 다른 소스의 변형 휠을 처리할 때는 해당 변형 메타데이터를 서로 독립적으로 고려하는 것이 좋습니다. 일치하는 변형 레이블이나 네임스페이스가 있다고 해서 소스 간에 동일한 의미를 갖는 것은 아닙니다.

우선순위 순서로 소스를 검색하는 도구(예를 들어 PEP 766의 “색인 우선순위”)는 Variant ordering 알고리즘을 사용하여 한 번에 한 소스의 변형을 정렬하고, 현재 소스에 실행 가능한 후보가 없는 경우에만 다음 소스로 진행할 수 있습니다. 소스 간 메타데이터 병합은 필요하지 않습니다.

모든 소스의 후보를 모은 후 그중에서 선택하는 도구(예를 들어 PEP 766의 “버전 우선순위”)는 서로 다른 소스의 휠을 직접 비교해야 합니다. 패키지 버전에 대해 호환 가능한 변형 휠을 제공하는 소스가 정확히 하나라면, 일반적으로 변형 휠이 비변형 휠보다 선호되므로 해당 변형을 비변형 휠보다 우선하여 선택할 수 있습니다. 여러 소스가 호환 가능한 변형을 제공하는 경우, 개별 메타데이터 키에 해당하는 절에서 지정한 대로 메타데이터가 일관될 때에만 해당 메타데이터를 모호하지 않게 결합할 수 있습니다.

메타데이터를 모호하지 않게 결합할 수 없는 경우에는 유일하게 올바른 전역 순서가 없습니다. 도구별로 유효한 선택에는 다음이 포함됩니다.

  • 오류와 함께 설치를 거부하는 것
  • 경고를 출력하고 변형 휠을 무시하여 비변형 휠 중에서 선택하는 것으로 대체하는 것
  • 여러 호환 가능한 변형 휠 중에서 선택할 때 결정론적 기준을 사용하는 것. 예를 들어 옵션 인자에서 더 앞에 나온 색인의 휠을 우선하는 방법이 있습니다.
  • 사용자에게 추가 입력을 요청하는 것

이러한 선택을 통해 전역적으로 최적인 선택을 보장하지 않고도 유효한 설치를 수행할 수 있습니다. 결합된 순서를 조용히 만들어 내거나 충돌하는 레이블 매핑을 해결하는 것은 기술적으로 가능하지만 권장되지 않습니다. 이는 어떤 소스도 선언하지 않은 의미를 만들어 내기 때문입니다.

근거

이 PEP는 원래 PEP 817로 제안된 더 큰 변형 휠 설계의 일부입니다. 그러나 복잡성 때문에 이를 서로 기반을 이루는 더 작은 부분으로 나누기로 결정했습니다. 이 PEP는 시리즈의 첫 번째로, 필요한 메타데이터와 함께 파일 형식, 색인 지원 및 기본 도구 알고리즘을 포함한 기반을 제공합니다. 실제 변형 속성을 제공하거나 휠을 빌드하는 것과 같은 측면은 후속 PEP로 미룹니다.

변형 휠은 구조화된 Variant properties 를 사용하여 다차원 휠 호환성 행렬을 표현합니다. 속성은 독립적으로 정의하고 관리할 수 있는 네임스페이스로 구성됩니다. 키-값 구조는 속성을 더 유연하게 만듭니다. 새로운 호환성 축을 추가할 때 새 키를 추가하면 됩니다. 이는 AND 방식의 종속성과 OR 방식의 종속성을 모두 지원할 수 있습니다. 예를 들어 CPU 플러그인은 서로 다른 명령어 집합에 해당하는 여러 키를 정의할 수 있으며, 이 키들은 모두 패키지에서 사용되므로 모두 지원되어야 합니다. 또한 GPU 플러그인은 여러 GPU 유형을 나열하는 단일 키를 정의할 수 있으며, 이는 해당 유형이 모두 패키지에서 지원되므로 사용자가 그중 하나만 보유하면 됨을 나타냅니다.

이 사양은 표현되는 속성 수에 어떠한 공식적인 제한도 부과하지 않으며, 속성 집합이 매우 길어질 가능성도 명시적으로 고려합니다(예를 들어 GPU의 긴 목록이나 CPU 확장 집합이 해당합니다). 정보가 지나치게 많아 휠 파일 이름을 이해하기 어려워지고 길이 때문에 기술적 문제가 발생할 가능성을 피하기 위해, 속성 목록은 휠 내부에 저장되며 패키지 관리자가 선택하고 사람이 읽을 수 있도록 의도된 짧은 레이블에 매핑됩니다.

변형 메타데이터는 Core metadata specifications에 추가하는 대신 별도의 JSON 형식 파일에 저장됩니다. 이는 독립적으로 버전 관리되며, 변형 메타데이터에 특별히 관심이 없는 도구는 해당 호환성 규칙을 무시할 수 있습니다. 이 버전 관리는 핵심 메타데이터의 버전 관리와 유사한 취지입니다. JSON은 구조화된 데이터에 더 편리한 형식을 제공하며, TOML에서 더 자연스럽게 변환할 수 있으므로 데이터를 pyproject.toml에서 가져올 수 있습니다.

휠 파일 이름만으로는 변형 휠 선택을 수행하기에 충분한 메타데이터를 제공하지 않습니다. 도구가 여러 휠 파일에서 변형 메타데이터를 직접 가져와야 하는 상황을 피하기 위해, 각 패키지 버전에 대한 휠의 메타데이터를 결합하여 다시 게시합니다. 이 메타데이터는 단일 패키지 버전에 한정되므로 향후 버전에서 변형이 변경될 수 있습니다.

인덱스 지원은 세 가지 시나리오를 고려하는 것을 목표로 합니다.

  1. 파일 목록 응답의 일부로 추가 메타데이터를 포함할 수 없는 인덱스 구현입니다. 예를 들어, 이는 웹 서버가 생성한 디렉터리 목록에서 직접 설치하는 경우를 포함합니다. 이 시나리오를 고려하기 위해 인덱스 수준 메타데이터는 패키지 관리자가 생성하여 휠과 함께 배치할 수 있는 일반 JSON 파일로 게시됩니다.
  2. 더 완전한 휠 지원을 제공하지만 즉시 완전한 변형 휠 지원을 구현할 의향은 없는 인덱스 구현입니다. 인덱스는 사용자가 해당 JSON 파일을 업로드할 수 있도록 허용하고 휠 목록에 이를 반영해야 하지만, 변형 메타데이터를 직접 처리할 필요는 없습니다.
  3. 완전한 휠 변형 지원을 구현하는 인덱스 구현입니다. 이러한 인덱스는 업로드된 변형 휠을 구문 분석하고 인덱스 수준 메타데이터를 동적으로 생성합니다. 그러면 JSON 파일 경로는 실제 파일이 아니라 API 엔드포인트로 취급됩니다.

JSON 형식에는 집합 타입이 없으므로 메타데이터의 집합은 정렬된 목록으로 표현됩니다. 정렬은 재현성을 보장하며 역직렬화 후 특정 필드를 다시 집합으로 변환하지 않고도 전체 딕셔너리에 등가 비교를 사용할 수 있게 합니다.

변형 정렬 알고리즘은 변형 속성이 플랫폼 호환성 태그보다 우선한다는 가정하에 제안되었습니다. 변형 속성은 주로 사용자 선호를 표현하는 데 사용되기 때문입니다. 이는 플랫폼 태그가 달라질 수 있는 가능성을 고려합니다. 예를 들어 CUDA 변형에 다른 최소 libc 버전이 필요할 수 있으며, 이 경우 선택은 부수적인 플랫폼 태그 차이가 아니라 원하는 CUDA 선호도에 따라 이루어져야 합니다.

향후 PEP에서 변형 속성을 제공하는 방법을 정의하겠지만, 호환 가능한 속성이 해당 선호도에 대응하는 특정 순서로 제공된다는 기본 가정을 둡니다. 이를 통해 일반적인 정렬 알고리즘을 사용할 수 있으며, 나중에 알고리즘을 변경하지 않고 속성을 데이터로 정의할 수 있습니다.

향후 PEP에서 기능과 값의 순서를 제공하는 방법을 정의합니다. 그러나 네임스페이스는 독립적으로 관리되고 동등한 수준에서 고려되므로, 네임스페이스에 대한 표준 순서는 존재하지 않습니다. 대신 네임스페이스의 순서는 변형 메타데이터에 명시적으로 기술되며, 이는 다시 패키지 관리자가 빌드 프로세스의 일부로 제공합니다.

실제 사용 사례의 대다수에서는 속성에 기반한 정렬로 충분합니다. 그러나 병리적인 경우에는 서로 다른 두 변형 휠이 동일한 정렬 키를 갖게 될 수 있습니다. 이 경우 재현 가능한 결과를 제공하기 위해 변형 레이블을 기준으로 대체 정렬을 수행합니다.

전환 기간을 용이하게 하기 위해 비변형 휠과 구별되는 널 변형이라는 개념을 도입합니다. 이 변형은 이 PEP를 구현하는 도구에서 항상 지원되며, 비변형 휠보다 우선합니다. 따라서 다른 변형이 지원되지 않는 경우와 변형 휠이 전혀 지원되지 않는 경우에 사용할 별도의 대체 수단을 제공하는 데 사용할 수 있습니다. 예를 들어 PyTorch는 GPU가 지원되지 않을 때 사용되는 훨씬 더 작은 널 변형과 기본 CUDA 버전용으로 빌드된 대체 비변형 휠을 제공할 수 있습니다.

pylock.toml 통합은 파일을 독립적으로 유지하기 위해 변형 메타데이터를 인라인으로 포함합니다. 이렇게 하면 파일을 가져오는 데 필요한 추가 네트워크 호출을 피할 수 있으며, 변형 메타데이터가 색인에서 변경되었거나 바이트 단위 출력의 안정성을 보장하지 않는 방식으로 생성되어 파일이 변경될 경우 문제를 일으킬 수 있는 특정 해시에 고정하지 않아도 됩니다.

변형 환경 마커

변형 속성은 두 개의 서로 다른 지점에서 변형 휠 설치에 관여하며, 그중 두 번째 지점만 마커와 관련됩니다. 설치 도구는 먼저 패키지 버전을 선택하고, 플랫폼 호환성 태그에 따라 해당 버전의 휠을 필터링한 다음, 대상 시스템이 지원하는 속성과 대조하여 변형 속성을 사용해 남은 변형 휠을 필터링하고 순서를 지정합니다. 도구는 그 결과로 선택된 항목을 재정의할 수 있습니다. 그 이후에야 선택된 휠의 의존성을 읽고 그 안에 포함된 변형 마커를 평가합니다.

따라서 휠의 필터링과 순서 지정은 마커가 아니라 변형 속성에 의해 결정됩니다. 마커는 휠의 선택을 제한하지 않으며, 개별 의존성 지정자만 제한하고 휠이 선택된 후에만 평가됩니다. 그렇지 않다면 마커가 참조하는 속성을 가진 휠이 무엇인지 알려지기 전에 해당 마커를 평가해야 합니다.

세 가지 집합 값 마커의 값은 대상 시스템이 지원하는 변형 속성으로 필터링됩니다. 휠은 자신이 실행되는 모든 값을 나열하므로, 이 단계가 없다면 그중 하나에 의해 제한되는 의존성이 해당 휠이 실행되는 모든 곳에 설치될 것입니다. 80_real부터 120_real까지의 GPU 아키텍처용으로 빌드된 휠은 120_real만 지원하는 라이브러리에 의존할 수 있으며, 이는 단일 CPU 아키텍처를 지원하는 의존성이 platform_machine에 의해 제한되는 것과 유사합니다. 기능의 모든 값에 대해 의존성이 존재하는 경우에는 대신 해당 의존성을 변형 패키지로 게시하고 무조건 의존하도록 하여, 선택을 Variant ordering에 맡길 수 있습니다.

이러한 필터링으로 인해 변형 마커는 환경 마커의 확립된 의미에서 벗어나지 않습니다. variant_properties의 모든 속성은 구성상 대상 시스템에서 지원되므로, 세 가지 집합 값 마커는 Dependency specifiers에 정의된 마커와 마찬가지로 환경을 설명합니다. 변형 휠에 특수한 것은 의미론이 아니라 어휘입니다. 기존 마커는 모든 휠에 동일하게 고정된 환경 속성 집합을 노출하는 반면, 변형 속성은 실제로 관찰되기 전에 휠에서 선언되어야 합니다. 휠의 Variant metadata는 해당 휠의 의존성 지정자가 환경의 어느 부분을 볼 수 있는지 결정합니다. variant_label은 선택된 변형의 이름을 지정하고 이 변형이 호환되는 것으로 판단되었다는 사실 외에는 환경에 대해 아무것도 말하지 않으므로 예외입니다.

이 설계의 세 가지 결과에 주목할 필요가 있습니다.

  • 휠은 선언한 모든 기능에 대해 대상 시스템이 적어도 하나의 값을 지원하는 경우에만 선택될 수 있으므로(자세한 내용은 Variant properties 참조) 필터링은 전체 기능이나 네임스페이스를 제거하지 않습니다. 따라서 variant_featuresvariant_namespaces는 항상 해당 휠이 빌드된 모든 기능과 네임스페이스를 나열합니다. 이것이 Variant ordering에서 허용되는 재정의가 호환성 필터를 넘어설 수 없는 이유입니다. 지원되지 않는데도 선택된 휠은 속성이 필터링되어 사라질 수 있으며, 해당 속성에 의해 제한된 의존성도 조용히 사라지게 됩니다.
  • 널 변형의 경우 variant_label"null"이고 세 가지 집합 값 마커는 빈 집합입니다. 널 변형에는 속성이 전혀 없기 때문입니다. 따라서 variant_label은 널 변형과 비변형 휠을 구별하는 유일한 마커입니다.
  • 휠이 선언하지 않은 속성, 기능 또는 네임스페이스를 참조하는 마커는 필터링이 속성만 제거하므로 어떤 환경에서도 충족될 수 없습니다. 따라서 이러한 마커는 빌드 시점에 확인할 수 있으며, 이것이 Backwards Compatibility에 설명된 부분 평가를 가능하게 합니다.

하위 호환성

변형 휠은 휠 파일 이름에 추가적인 Variant label 구성 요소를 추가합니다. 완전한 파일 이름 검증 단계에서는 이러한 휠을 거부해야 합니다.

  • 빌드 태그와 변형 레이블이 모두 있으면 파일 이름에 구성 요소가 너무 많이 포함됩니다. 예시:
    numpy-2.3.2-1-cp313-cp313t-musllinux_1_2_x86_64-x86_64_v3.whl
                                                   ^^^^^^^^^^
    
  • 변형 레이블만 있는 경우 세 번째 위치의 Python 태그가 빌드 번호로 잘못 해석됩니다. 빌드 번호는 숫자로 시작해야 하므로 파일 이름이 유효하지 않은 것으로 간주됩니다. 예:
    numpy-2.3.2-cp313-cp313t-musllinux_1_2_x86_64-x86_64_v3.whl
                ^^^^^
    

현재 숫자로 시작하는 Python 태그는 없습니다. 모호함이 없도록 명세에서는 앞으로 이를 강제합니다. 작성 시점에 휠 설치에 일반적으로 사용되는 도구는 이러한 검증 알고리즘을 구현하고 있으므로, 변형 휠이 실수로 설치될 위험 없이 비변형 휠과 함께 색인에 변형 휠을 게시할 수 있습니다.

파일 이름을 완전히 검증하지 않는 도구는 일부 또는 모든 변형 휠을 일반 휠로 소비합니다. 해당 도구가 변형 휠을 특별히 처리해야 하는 경우 이로 인해 예기치 않은 동작이나 손상이 발생할 수 있습니다.

휠 파일을 처리하는 라이브러리와 그 소비자는 새로운 파일 이름 구성 요소와 새로운 메타데이터를 처리하도록 업데이트해야 합니다. 예를 들어, 패키징 프로젝트에서 parse_wheel_filename() 함수를 어떻게 조정할지에 대한 공개 토론이 있습니다.

변형 레이블이 추가되면 파일 이름의 길이가 늘어납니다. Windows와 같이 전체 경로 길이 제한이 낮은 플랫폼에서는 긴 파일 이름이 문제가 됩니다. 그러나 이름과 버전 구성 요소에는 이미 제한이 없으므로 이 PEP에서는 특정 제한을 설정하지 않습니다. PyPI와 같은 다른 곳에서는 전체 파일 이름 길이에 제한을 설정할 수 있습니다.

이러한 명시적인 비호환성을 제외하면 명세는 바이너리 패키지 형식에 최소한의 비침해적 변경만 적용합니다. Variant metadata.dist-info 디렉터리의 별도 파일에 저장됩니다. 변형과 직접 관련이 없는 도구는 파일 이름 검증 알고리즘이 있는 경우 이를 업데이트하고 해당 디렉터리의 내용을 보존하기만 하면 됩니다.

새로운 Environment markers가 휠 의존성에 사용되면 이러한 휠은 기존 도구와 호환되지 않습니다. 예를 들어 색인에서 가져온 의존성에서 이러한 마커를 만나면 pip는 역추적하여 가능한 경우 더 오래된 의존성 버전을 사용합니다. 이는 환경 마커 설계의 일반적인 문제이며 휠 변형에만 해당하는 문제는 아닙니다. 빌드 시점에 환경 마커를 부분적으로 평가하고 비변형 휠에서 변형 휠에 특정한 마커나 의존성을 제거하면 이 문제를 우회할 수 있습니다.

보안 관련 영향

변형 휠이 존재하면 일부 변형이 다른 변형보다 덜 면밀하게 검토되어 더 쉬운 공격 대상이 될 수 있습니다. 특히 변형 휠 지원이 일반화되면 일부 패키지의 비변형 휠은 오래된 도구를 사용하는 사용자만 소비하게 될 수 있습니다. 그러나 이러한 공격은 패키지 게시 작업 흐름이 이미 손상되었다고 가정하며, 그런 경우에는 컴파일된 확장을 수정하는 등 더 개연성 높은 공격 벡터를 사용할 수 있습니다.

이를 가르치는 방법

이 PEP는 도구 작성자를 대상으로 합니다. 변경 사항은 Binary distribution format 및 기타 PyPA 사양에 통합됩니다. 최종 사용자에게 변형을 가르치는 내용은 사용자 경험 세부 사항이 다뤄지는 후속 PEP에서 다룹니다.

참조 구현

variantlib 프로젝트에는 완전한 변형 휠 솔루션의 참조 구현이 포함되어 있습니다. 이 구현은 이 PEP를 준수하지만, 유보된 일부 항목에 대한 예시 솔루션도 제공하여 그 범위를 넘어섭니다.

변형 휠을 설치하기 위한 클라이언트가 uv branch에서 구현되어 있습니다.

거부된 아이디어

예측 가능한 변형 레이블

이 사양에서는 변형 레이블이 임의적이며, 변형 속성은 레이블에 직접 표현하는 대신 Variant metadata 파일을 통해 레이블에 매핑하도록 제안합니다. 변형 속성에서 변형 레이블을 만드는 것이 기술적으로 가능할 수도 있지만, 그러려면 일부 플랫폼에서 문제를 일으킬 매우 긴 파일 이름을 허용하거나 변형 속성 개수에 임의의 제한을 설정해야 하므로, 다차원 호환성 매트릭스를 다루는 데 이 사양이 덜 적합해집니다.

대안으로 변형 속성의 해시를 사용하는 방법이 있었습니다. 이러한 방법은 기술적으로 유효하며 임의로 큰 변형 속성 집합에 대해서도 짧고 고유한 레이블을 제공할 수 있지만, 레이블이 불투명해져 읽거나 추론하기 어려워집니다.

플랫폼 호환성 태그의 일부로서의 변형 레이블

이 사양에서는 변형 레이블을 별도 구성 요소로 추가하므로 기존 도구와의 호환성이 깨집니다. 대신 변형 레이블을 플랫폼 호환성 태그 중 하나에 덧붙이면 부분적인 호환성을 유지하는 것이 기술적으로 가능할 수도 있으며, 이 경우 설치 도구는 플랫폼 또는 Python 인터프리터 비호환성을 근거로 휠을 거부하는 반면 다른 도구는 여전히 해당 휠을 사용할 수 있습니다. 그러나 작성자들은 하위 호환성을 깨는 편이 더 안전하다고 결정했습니다. 또한 태그를 재사용하면 휠 레이블이 압축된 태그 집합과 잘못 결합될 잠재적 위험이 있었습니다. 예를 들어 manylinux_2_27_x86_64.manylinux_2_28_x86_64+x86_64_v3 태그는 manylinux_2_27_x86_64 부분 때문에 호환되는 것으로 잘못 판단됩니다.

플랫폼 호환성 태그를 완전히 대체하기

기술적으로는 현재 플랫폼 호환성 태그를 통해 전달되는 정보를 변형 속성을 통해 전달하고, 파일 이름에서 이러한 명시적 태그를 제거하는 것이 충분히 가능했을 것입니다. 그러나 추가 변형이 필요하지 않은 휠에 대해서는 기존 파일 이름을 유지하기로 했습니다. 모든 기존 작업 흐름을 업데이트하는 데 필요한 노력이 더 간결하고 약간 더 일관된 명명 방식이 제공하는 이점을 정당화한다고 생각하지 않기 때문입니다.

휠 파일에서 순서 정보 제거하기

이 사양에서는 변형 휠의 순서를 정하는 데 필요한 모든 데이터를 변형 메타데이터( Default priorities 딕셔너리)에 저장하도록 제안합니다. 이 데이터는 프로젝트별 공통 출처에서 비롯되어야 하며(후속 PEP에서 pyproject.toml 파일 내 통합을 제안할 예정입니다), 빌드 시 모든 변형 휠에 복사된 다음 Index-level metadata 파일에도 복사되어야 합니다.

이렇게 하면 순서 데이터가 휠 수준 속성이 되며, 특정 휠에 삽입된 후 다른 휠에 관한 내용을 나타낸다는 주장이 제기되었습니다. 그렇지 않습니다. 이 데이터는 휠에 복사되는 프로젝트 수준 메타데이터이며, 그곳에 포함된 다른 프로젝트 메타데이터와 마찬가지로 다른 휠을 참조하지 않습니다. 순서 데이터는 특정 릴리스에 변형 휠이 존재하지 않는 네임스페이스를 지정할 수 있으며, 이 형식의 어떤 부분도 특정 다른 휠의 존재 여부에 의존하지 않습니다.

또한 이 설계는 인덱스 수준 메타데이터 파일이 일차 데이터 소스가 아니라 캐시가 되도록 특별히 보장합니다. 모든 데이터가 휠에 저장되므로:

  1. 추가 입력 데이터 없이 사용 가능한 휠만으로 인덱스 수준 메타데이터 파일을 생성할 수 있습니다. 특히 이를 통해 색인은 휠을 업로드하는 데 사용되는 도구나 작업 흐름을 변경하지 않고도 해당 파일을 자동으로 생성할 수 있습니다.
  2. 인덱스 수준 메타데이터 파일이 없는 경우에도 여러 휠 중에서 선택할 수 있으며, 예를 들어 로컬 디렉터리에서 설치할 때도 가능합니다.

서로 다른 시점에 서로 다른 도구로 빌드된 두 휠의 메타데이터가 일관되지 않게 될 실제 위험은 분명히 존재합니다. 그러나 사양에서는 일관성을 요구하며, Metadata consistency에 설명된 대로 패키지 버전 게시자에게 그 책임을 부여합니다.

또한 순서 데이터를 변형 메타데이터에서 분리하면 도구가 표준 형식으로 해당 데이터의 재정의를 허용할 수 있다는 의견도 제시되었습니다. 그러나 둘 사이에는 관련이 없으며, 이러한 형식은 어느 방식으로든 도입할 수 있습니다. 예를 들어 변형 메타데이터의 일부를 사용할 수 있습니다.

범위 외

다음 문제는 이 시리즈의 후속 PEP로 미룹니다.

  • 변형 네임스페이스의 거버넌스
  • 어떤 변형 속성이 시스템과 호환되는지 결정하기
  • 정적 데이터를 사용하여 호환성 감지를 재정의하기
  • 변형 휠 빌드하기

미해결 문제

이 PEP가 승인되기 전에 이러한 질문을 해결해야 합니다.

변형 환경 마커 사용

변형 Environment markers의 설계는 아직 확정되지 않았습니다. 동적 종속성을 통해 동일한 효과를 얻을 수 있습니다. 릴리스 전체에서 종속성 메타데이터를 정적으로 유지하면서 이를 얻는 데 마커가 적절한 메커니즘인지가 미해결 문제입니다. 이는 this thread에서 논의 중입니다. 이 명세는 현재 설계를 반영합니다.

감사의 말

Python 패키징 커뮤니티의 많은 분들이 기여하고 피드백을 제공해 주지 않았다면 이 작업은 불가능했을 것입니다. 특히 다음 분들이 이 PEP를 형성하는 데 도움을 주셨으므로, 그 공로를 기리고자 합니다(알파벳순).

Alban Desmaison, Bradley Dice, Chris Gottbrath, Dmitry Rogozhkin, Emma Smith, Geoffrey Thomas, Henry Schreiner, Jeff Daily, Jeremy Tanner, Jithun Nair, Keith Kraus, Leo Fang, Mike McCarty, Nikita Shulga, Paul Ganssle, Philip Hyunsu Cho, Robert Maynard, Vyas Ramasubramani, Zanie Blue

변경 이력

  • 2026년 8월 19일
    • 색인이 관련 없는 선택적 속성을 게시하지 않고 도구가 이를 무시하도록 색인 규칙을 강화했습니다.
    • 색인 수준 메타데이터 파일에서 누락된 변형을 처리하는 방법에 대한 제안을 추가했습니다.
    • 색인 수준 메타데이터 파일을 비표준 휠 소스에서도 사용할 수 있음을 명시했습니다.
  • 2026년 8월 10일
    • 명세 대부분을 Index-level metadata 에서 분리하고, 이는 휠이 색인에 게시되는 시나리오를 위한 최적화일 뿐임을 명확히 했습니다.
    • 여러 소스에서 변형 휠을 설치하기 위한 비규범적 지침을 추가했습니다.
    • 명시적인 “구현 요구 사항” 섹션을 추가했습니다.
    • 개별 변형 메타데이터 키의 범위를 명확히 하고, 각 키에 대한 일관성 요구 사항을 함께 명시했습니다.
    • “휠 파일에서 순서 정보 제거”를 거부된 아이디어에 추가했습니다.
    • default-priorities.featuredefault-priorities.property를 제거했습니다.
    • 스키마 버전 관리에 시맨틱 버전 관리를 사용하도록 변경했으며, 이에 따른 하위 호환성 영향도 반영했습니다.
    • 환경 마커 내용을 개선했습니다. variant_properties 마커가 메타데이터에 지정된 모든 속성이 아니라 시스템과 호환되는 변형 속성을 사용하도록 변경했습니다.
    • 환경 마커 사용법을 설명하도록 pylock.toml 섹션을 업데이트합니다.
    • 언어 및 설계 일관성을 위한 다양한 소규모 수정 사항입니다.
  • 2026년 5월 11일
    • 플랫폼 호환성 태그를 완전히 대체하는 방안을 거부된 아이디어에 추가했습니다.
    • 정렬 알고리즘과 인덱스 지원에 대한 해석을 명확히 했습니다.
  • 2026년 4월 6일
    • Python 태그가 숫자로 시작해서는 안 된다는 공식 요구 사항을 추가했습니다.
    • 전체 파일 이름 검증을 수행하지 않는 도구와 관련된 하위 호환성 문제를 확장하여 설명했습니다.
  • 2026년 3월 9일
    • variants 딕셔너리의 기능 값이 집합이며, 직렬화할 때 정렬해야 한다는 점을 명확히 했습니다.
    • 변형 메타데이터를 병합하는 규칙을 변경하여 휠 순서와 관계없이 결과가 동일해야 한다고 명시했습니다. 이를 통해 모호한 결과를 방지하려는 목표를 더 명확하게 전달합니다.
  • 2026년 2월 17일
    • 초기 버전이며, PEP 817 초안에서 분리되었습니다.
    • 변형 정렬 알고리즘을 수정하여 모든 호환 가능한 값이 아니라 각 기능에 대해 시스템과 호환되는 최적의 값에 따라 변형을 정렬하고, 변형 레이블을 기준으로 정렬하는 대체 수단을 추가했습니다.
    • 변형 레이블 길이 제한을 제거했습니다.
    • URL과 해시를 저장하는 대신 변형 메타데이터를 인라인으로 포함하도록 pylock.toml 통합을 변경했습니다.

부록