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

Python 개선 제안 한국어 번역

PEP 804 – 외부 의존성 레지스트리 및 이름 매핑 메커니즘

Author:
Pradyun Gedam <pradyunsg at gmail.com>, Ralf Gommers <ralf.gommers at gmail.com>, Michał Górny <mgorny at quansight.com>, Jaime Rodríguez-Guerra <jaime.rogue at gmail.com>, Michael Sarahan <msarahan at gmail.com>
Discussions-To:
Discourse thread
Status:
Draft
Type:
Standards Track
Topic:
Packaging
Requires:
725
Created:
03-Sep-2025
Post-History:
22-Sep-2025

Table of Contents

번역·라이선스 안내

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

초록

이 PEP는 패키징 도구가 외부 의존성 식별자(PEP 725에서 도입됨)를 다른 패키지 저장소의 대응 항목에 매핑할 수 있도록 하는 이름 매핑 메커니즘을 지정합니다.

동기

PyPI의 패키지는 PyPI에 존재하지 않는 빌드 시점 및 런타임 의존성을 요구하는 경우가 많습니다. PEP 725는 이러한 의존성을 표현하기 위한 메타데이터를 도입했습니다. Python 패키지에 구체적인 외부 의존성 메타데이터를 사용하려면 주어진 의존성 식별자를 다른 생태계에서 사용하는 지정자로 매핑해야 하며, 이를 통해 다음을 가능하게 할 수 있습니다.

  • 도구가 외부 의존성을 다른 패키징 저장소/생태계의 패키지에 자동으로 매핑할 수 있도록 함,
  • Python 패키지 설치 프로그램 및 빌드 프런트엔드가 생성하는 오류 메시지에 사용자 시스템의 관련 시스템 패키지 관리자가 사용하는 패키지 이름을 사용하여 필요한 외부 의존성을 포함하고, 사용자가 해당 패키지의 설치 지침을 얻을 수 있도록 함.

Linux 배포판, conda, Homebrew, Spack, Nix와 같은 패키징 생태계는 Python 패키지에 대한 전체 의존성 집합을 필요로 하며, 업스트림 Python 패키지에서 제공되는 메타데이터로부터 의존성 정보를 자동으로 생성하려고 시도하는 pyp2rpm (Fedora), Grayskull (conda), dh_python (Debian)과 같은 도구를 갖추고 있습니다. PEP 725 이전에는 pyproject.toml 또는 기타 표준 메타데이터 파일에 이를 위한 메타데이터가 없었기 때문에 외부 의존성을 수동으로 처리했습니다. 외부 의존성의 자동 변환을 가능하게 하는 것은 이 PEP의 핵심 이점이며, Python 패키징을 더 쉽고 안정적으로 만듭니다. 또한 저자들은 다른 유형의 도구가 이 정보를 활용할 것으로 예상합니다. 예를 들어 Repology, Dependabot, libraries.io_와 같은 의존성 분석 도구가 있습니다.

근거

기존 사례

R 언어에는 apt-get과 같은 패키지 관리자의 설치 명령으로 외부 의존성 메타데이터를 변환하는 방법을 알고 있는 중앙 레지스트리를 갖춘 R 패키지의 시스템 요구 사항이 있습니다. 이 레지스트리는 여러 Linux 배포판과 Windows에 대한 매핑을 중앙에서 관리합니다. macOS는 포함되어 있지 않습니다. 해당 README의 “Rule Coverage”는 이 시스템이 CRAN에서 소스 코드로 패키지를 빌드할 때 성공 가능성을 높인다는 점을 보여 주곤 했습니다. 모든 CRAN 패키지를 기준으로 Ubuntu 18은 78.1%에서 95.8%로, CentOS 7은 77.8%에서 93.7%로, openSUSE 15.0은 78.2%에서 89.7%로 향상되었습니다. 성공 가능성은 레지스트리가 얼마나 잘 유지 관리되는지에 따라 달라지지만, 향상 폭은 상당합니다. Docker 컨테이너에서 Ubuntu와 CentOS의 빌드 실패 패키지 수가 약 4분의 1로 감소합니다.

Fedora와 같은 RPM 기반 배포판은 pyp2rpm_에서 규칙 기반 구현(NameConvertor)을 사용할 수 있습니다. 주요 규칙은 PyPI 패키지의 RPM 이름이 일반적으로 f"python3-{pypi_package_name}"이라는 것입니다. 드문 예외로는 주로 애플리케이션을 배포하는 패키지가 있으며, 이러한 패키지는 접두사를 제거합니다(예: Black 포매터는 python3-black이 아니라 단순히 black입니다). 또한 Python 버전에 따른 변형도 있습니다(예: RHEL 9에서 setuptools는 Python 3.9용 python3-setuptools로 찾을 수 있지만, python3.11-setuptoolspython3.12-setuptools도 사용할 수 있습니다). 자세한 내용은 Python을 위한 Fedora 패키징 지침에서 확인할 수 있습니다.

Debian 패키지는 일반적으로 f"python3-{import_name}" 명명 체계를 따르지만 몇 가지 예외가 있습니다. 일부 하위 커뮤니티는 중위 문자열을 사용하며(예: Django 패키지는 f"python3-django-*" 아래에 위치함), 애플리케이션은 python3- 접두사 없이 이름 그대로 배포되는 경우가 많습니다. 자세한 내용은 Debian의 Python 정책에서 확인할 수 있습니다.

Gentoo는 dev-python/ 카테고리와 일부 명확하게 정의된 규칙을 사용하여 Python 패키지 이름을 지정하는 유사한 접근 방식을 따릅니다.

conda-forge는 PyPI와 conda-forge에서 기본 이름이 동일하기 때문에 더 명시적인 이름 매핑을 사용합니다(예: numpynumpy에 매핑됨). 그러나 이름 충돌과 이름 변경으로 인해 많은 예외가 있습니다(예: PyTorch의 PyPI 이름은 torch인 반면 conda-forge에서는 pytorch임). 여러 팀이 유지 관리하는 이름 매핑 작업이 여러 가지 있습니다. Conda-forge의 인프라는 regro/cf-graph-countyfair에서 하나를 생성합니다. Grayskull은 자체 선별 매핑을 유지 관리합니다. Prefix.dev는 도구에서 conda 및 PyPI 통합을 지원하기 위해 parselmouth 매핑을 만들었습니다. 이들의 접근 방식과 장단점에 대한 더 포괄적인 개요는 conda/grayskull#564에서 확인할 수 있습니다.

OpenStack 생태계도 일부 매핑 작업을 처리해야 합니다. 이 작업은 모두 Linux 배포판에만 집중합니다. pkg-mapdiskimage-builder와 함께 사용되며, 사용자가 임의의 변수 이름과 대상 배포판(Red Hat, Debian, OpenSUSE 등)에서 이에 대응하는 이름을 정의하는 파일 형식을 제공합니다. PyYAML 예제를 참조하십시오. bindep은 사용자가 PyPI에서 설치할 수 없는 의존성을 기록할 수 있는 bindep.txt 파일을 정의합니다(예제참조). 이 형식은 줄 기반이며, 각 줄에는 Debian 생태계에서 사용되는 의존성이 포함됩니다. 다른 배포판의 경우 대괄호 사이에 “filters” 구문을 제공하여 사용자가 다른 대상 플랫폼, 선택적 의존성 및 추가 기능을 지정할 수 있습니다.

SageMath와 같은 다른 생태계에서도 매핑의 필요성이 나타나며, 자신이 선택한 시스템 패키지 관리자를 사용하여 PyPI 패키지를 설치하려는 최종 사용자에게서도 이러한 필요성이 나타납니다(StackOverflow 질문 예시).

이름 매핑의 거버넌스 및 유지 관리 비용

많은 패키징 생태계에 대한 외부 의존성 매핑의 유지 관리 비용은 잠재적으로 높습니다. 따라서 다음과 같은 방식으로 레지스트리를 정의합니다:

  • 중앙 기관이 인식된 DepURL 목록과 알려진 생태계 매핑을 유지 관리합니다.
  • 매핑 자체는 대상 패키징 생태계가 유지 관리합니다.

따라서 이 시스템은 특정 생태계가 선택적으로 참여하는 방식이며, 관련 유지 관리 비용은 분산됩니다.

패키지 관리자별 설치 명령 생성

외부 의존성이 있는 Python 패키지 작성자는 일반적으로 문서에 해당 외부 의존성의 설치 지침을 포함합니다. 이러한 지침은 작성하고 최신 상태로 유지하기 어려우며, 대개 한 개 또는 많아야 소수의 플랫폼만 다룹니다. 예를 들어 SciPy의 외부 빌드 의존성(C/C++/Fortran 컴파일러, OpenBLAS, pkg-config)에 대한 지침은 다음과 같습니다:

  • Debian/Ubuntu: sudo apt install -y gcc g++ gfortran libopenblas-dev liblapack-dev pkg-config python3-pip python3-dev
  • Fedora/CentOS/RHEL: sudo dnf install gcc-gfortran python3-devel openblas-devel lapack-devel pkgconfig
  • Arch Linux: sudo pacman -S gcc-fortran openblas pkgconf
  • macOS의 Homebrew: brew install gfortran openblas pkg-config

패키지 이름은 매우 다양하며, 일부 배포판은 헤더와 기타 빌드 시점 의존성을 별도의 -dev/-devel 패키지로 분리하는 반면 다른 배포판은 그렇지 않은 등의 차이도 있습니다. 이 PEP의 레지스트리를 사용하면 “이 생태계가 선호하는 패키지 관리자의 모든 외부 의존성 설치 명령을 표시”하는 의미 체계를 갖춘 도구 명령을 통해 이를 더욱 포괄적이고 유지 관리하기 쉽게 만들 수 있습니다. 이를 독립 실행형 도구로 구현하거나, Python 개발 워크플로 도구(Pip, Poetry, Hatch, PDM, uv 등)에 새 하위 명령으로 추가할 수 있습니다.

이를 위해 각 생태계 매핑은 호환되는 것으로 알려진 패키지 관리자 목록과 패키지를 설치하고 설치된 패키지를 조회하는 방법에 대한 템플릿화된 지침을 제공할 수 있습니다. 제공되는 설치 명령 템플릿에는 조회 명령 템플릿이 함께 제공되므로, 해당 도구는 설치 작업을 시도하지 않고도 필요한 패키지가 이미 있는지 확인할 수 있습니다. 설치 작업은 비용이 많이 들거나 버전 업그레이드와 같은 의도하지 않은 부작용을 일으킬 수 있습니다.

레지스트리 설계

매핑 인프라는 다음 구성 요소와 속성을 제시하도록 설계되었습니다.

  • PEP 725 식별자(DepURL)의 중앙 레지스트리로, 표준으로 간주되는 잘 알려진 genericvirtual식별자를 최소한 포함합니다.
  • 알려진 생태계 목록으로, 생태계 유지 관리자가 이름 매핑을 등록할 수 있습니다.
  • 매핑의 구조를 정의하는 표준화된 스키마입니다. 각 매핑은 지원하는 패키지 관리자의 작동 방식에 대한 프로그래밍 방식의 세부 정보도 제공할 수 있습니다.

위 문서는 함께 제공되는 JSON 스키마로 검증된 JSON 파일로 제공됩니다. 이러한 리소스를 조회하고 활용할 수 있는 Python 라이브러리와 CLI가 제공됩니다. 사용자는 기본 패키지 매핑과 명령 생성을 위해 선호하는 시스템 패키지 관리자를 구성할 수 있습니다(예를 들어 Ubuntu 사용자는 외부 의존성을 제공할 패키지 관리자로 apt 대신 conda, brew 또는 spack을 선호할 수 있습니다).

사양

중앙 레지스트리

중앙 레지스트리는 정식으로 인식되는 식별자와 알려진 별칭을 정의합니다.

중앙 레지스트리를 사용하면 [external] 테이블을 검증할 수 있습니다. 관련된 모든 도구는 제공된 식별자의 형식이 올바른지 반드시 확인해야 합니다. 또한 일부 도구는 사용 중인 식별자가 정식으로 인식되는지 확인할 수 있습니다. 보다 구체적으로는 다음과 같습니다.

  • 빌드 백엔드, 빌드 프런트엔드 및 설치 프로그램은 기본적으로 식별자가 정식인지 검증해서는 안 됩니다.
  • twine과 같은 업로더는 식별자가 정식인지 검증하고, 선택 해제 메커니즘과 함께 사용자에게 경고하거나 오류를 보고해야 합니다. 사용 가능한 경우 정식 대체 항목을 제안해야 합니다.
  • PyPI와 같은 색인 서버는 업로더와 동일한 검증을 수행하고 필요한 경우 아티팩트를 거부할 수 있습니다.

이 레지스트리는 별칭 모음에서 어떤 항목을 정식 항목으로 선호할지, 또는 가상 DepURL에 어떤 버전 관리 체계를 적용할지(부록 B 참조)와 같이 레지스트리 내용에 관한 권위 있는 결정을 중앙화해야 합니다. 이에 해당하는 답변은 이 PEP에 제시되어 있지 않으며, 대신 해당 책임을 중앙 레지스트리 유지 관리자에게 위임합니다.

중앙 레지스트리 문서의 정식 파일 이름은 반드시 registry.json이어야 합니다.

스키마

중앙 레지스트리는 다음 JSON schema로 지정됩니다.

$schema
Type string
Description URL of the definition list schema in use for the document.
Required False
schema_version
Type integer
Required False
definitions
Type array
Description List of DepURLs currently recognized.
Required True

이 목록의 각 항목은 다음과 같이 정의됩니다.

Field Type Description
id (required) string matching regex ^dep:.+$ The entry identifier MUST be a valid DepURL string.
description string Free-form field to add some details about the package. Allows Markdown.
provides DepURLField | list[DepURLField] List of id strings this entry connects to. Useful to annotate aliases (e.g. dep:generic/arrow and dep:github/apache/arrow) or virtual package implementations (e.g. dep:generic/gcc would provide dep:virtual/compiler/c). This field MUST NOT be present in dep:virtual/ definitions. Entries without provides content or, if populated, only with dep:virtual/ identifiers, are considered canonical.
urls AnyUrl | list[AnyUrl] | dict[NonEmptyString, AnyUrl] Hyperlinks to web locations that provide more information about the definition.

알려진 생태계

알려진 생태계 목록에는 두 가지 역할이 있습니다.

  1. 지정된 생태계 매핑의 정식 URL을 보고합니다.
  2. Mappings에 설명된 대로 각 생태계에 고유하고 짧은 식별자를 할당합니다.

알려진 생태계 목록의 정식 파일 이름은 반드시 known-ecosystems.json이어야 합니다.

스키마

알려진 생태계 목록은 다음 JSON Schema로 지정됩니다.

$schema
Type string
Description URL of the schema in use for the document.
Required False
schema_version
Type integer
Description Version of the schema in use.
Required False
ecosystems
Type dict
Description Ecosystems names and their corresponding details.
Required True

이 딕셔너리는 생태계 식별자를 나타내는 비어 있지 않은 문자열 키를 다음과 같이 정의된 하위 딕셔너리에 매핑합니다.

Key Value type Value description
mapping (required) AnyURL URL to the mapping for this ecosystem.

매핑

매핑은 중앙 레지스트리에서 사용할 수 있는 정식 항목을 제공하는 생태계별 식별자를 지정합니다. 매핑은 주로 두 개의 딕셔너리 목록으로 구성됩니다. 하나는 각 항목이 DepURL을 하나 이상의 생태계별 식별자에 매핑하고, 다른 하나는 하나 이상의 패키지 관리자를 사용하는 방법을 보여 줍니다.

각 매핑에는 온라인 검색을 위한 정식 URL이 반드시 있어야 합니다. 전체 파일 이름은 반드시 {ecosystem-identifier}.mapping.json이어야 하며, 여기서 “생태계 식별자”는 다음 정규 표현식을 반드시 따라야 합니다: [a-z0-9\-_.]+(\+[a-z0-9\-_.]+)?. 즉, 첫 번째 필드 뒤에 + 기호로 구분된 두 번째 필드가 선택적으로 이어집니다.

Linux 배포판에 해당하는 생태계의 경우, 첫 번째 필드는 os-release 사양에 명시된 ID 문자열에 반드시 해당해야 합니다. 두 번째 필드가 제공되고 관련이 있는 경우, 해당 필드는 VERSION_ID 문자열에 반드시 해당해야 합니다.

버전 필드는 선택 사항이므로, 도구는 버전이 지정된 식별자에 먼저 접근하고, 찾지 못하면 이름만 있는 식별자로 대체해야 합니다.

스키마

매핑은 다음 JSON Schema로 지정됩니다.

$schema
Type string
Description URL of the mappings schema in use for the document.
Required False
schema_version
Type integer
Description Version of the schema in use.
Required False
name
Type string
Description Display name for the mapping.
Required True
description
Type string
Description Free-form field to add information this mapping. Allows Markdown.
Required False
mappings
Type array
Description List of DepURL-to-specs mappings.
Required True

mappings의 각 항목은 다음과 같이 정의됩니다.

Field Type Description
id (required) string matching regex ^dep:.+$ DepURL, as provided in the central registry.
description string Free-form field to add some details about the package. Allows Markdown.
specs string | list[string] | dict[Literal['build', 'host', 'run'], string | list[string]] Ecosystem-specific identifiers for this package. The full form is a dictionary that maps the categories build, host and run to their corresponding package identifiers. As a shorthand, a single string or a list of strings can be provided, in which case will be used to populate the three categories identically. An empty list indicates that the ecosystem does not have packages for this entry.
specs_from string matching regex ^dep:.+$ DepURL identifier of another entry whose specs will be reused here.
urls AnyUrl | list[AnyUrl] | dict[NonEmptyString, AnyUrl] Hyperlinks to web locations that provide more information about the definition.
extra_metadata dict[NonEmptyString, Any] Free-form key-value store for arbitrary metadata.

specsspecs_from 중 정확히 하나가 반드시 있어야 합니다.

package_managers
Type array
Description List of tools that can be used to install packages in this ecosystem.
Required True

package_managers의 각 항목은 다음 필드를 가진 딕셔너리여야 합니다.

Field Type Description
name (required) string Short identifier for this package manager (usually the command name).
commands (required) dict See subsection below.
specifier_syntax (required) dict See subsection below.
commands

지정된 패키지를 설치하거나 조회하는 데 사용되는 명령입니다.

이는 허용되는 키가 두 개뿐인 딕셔너리여야 합니다. install(설치 지침 생성용)과 query(주어진 패키지가 이미 설치되어 있는지 확인하는 용도)입니다. 해당 값은 다음을 포함하는 딕셔너리여야 합니다.

  • 필수 command키는 문자열 목록을 값으로 가져야 합니다(subprocess.run에서 예상하는 형식). 이 목록의 항목 중 정확히 하나는 {} 플레이스홀더여야 하며, 매핑된 패키지 지정자로 대체됩니다.
  • 선택적 requires_elevation 불리언은 명령을 상승된 권한으로 실행해야 하는지를 나타냅니다(기본값은 False이며, 예를 들어 Windows에서는 관리자 권한, Linux 및 macOS에서는 슈퍼유저 권한을 의미합니다).
  • 필수 multiple_specifiers 열거형은 명령이 여러 패키지 지정자를 동시에 허용하는지를 결정하며, 다음 중 하나를 사용합니다.
    • always: install에서 기본값입니다.
    • name-only: 버전 제약 조건을 포함하지 않는 경우에만 여러 지정자를 허용하는 명령입니다.
    • neverquery의 기본값입니다.

install명령은 플레이스홀더가 여러 지정자로 대체되는 것을 지원해야 합니다. query는 명령당 하나의 지정자만 받아야 합니다.

install의 경우 패키지가 성공적으로 설치되었거나 이미 존재하면 종료 코드는 0이어야 합니다.

query의 경우 패키지가 설치되어 있으면 명령은 종료 코드 0을 반환해야 합니다. 그 밖의 경우에는 0이 아닌 종료 코드를 반환해야 합니다.

specifier_syntax

PEP 725에서 정한 PEP 440 지정자의 일부를 대상 패키지 관리자로 매핑하는 방법에 대한 지침을 설명하는 딕셔너리입니다. 세 가지 지원 수준인 이름 전용, 정확한 버전 전용, 버전 범위 호환성(연산자별 변환)을 제공합니다. 따라서 이 세 가지 최상위 키는 필수로 지정되어야 합니다. 추가 키는 허용해서는 안 됩니다.

  • name_only는 버전 정보가 포함되지 않은 지정자에 사용되는 구문을 문자열 목록으로 가져야 하며, {name}플레이스홀더를 포함해야 합니다.
  • exact_versionNone이거나 정확한 버전 제약 조건만 표현하는 지정자의 구문을 설명하는 문자열 목록이어야 합니다. 후자의 경우 {name}{version}플레이스홀더가 둘 다 하나 이상의 문자열에 포함되어야 합니다(두 플레이스홀더가 반드시 같은 문자열에 포함될 필요는 없습니다).
  • version_rangesNone이거나 다음 필수 키를 가진 딕셔너리여야 합니다.
    • syntax키는 문자열 목록을 값으로 가지며, 하나 이상은 {ranges}플레이스홀더를 포함해야 합니다. 이 플레이스홀더는 and의 값에 따라 필요할 경우 결합된 버전 제약 조건으로 대체됩니다. 또한 {name}플레이스홀더를 포함할 수도 있습니다.
    • equal, greater_than, greater_than_equal, less_thanless_than_equal키는 해당 연산자가 지원되면 문자열을, 그렇지 않으면 None을 값으로 가집니다. 전자의 경우 값은 {version}플레이스홀더를 포함해야 하며, {name}플레이스홀더를 포함할 수도 있습니다.
    • and키는 여러 버전 제약 조건을 하나의 토큰으로 결합하는 데 사용하는 문자열을 값으로 가지며, 토큰당 하나의 제약 조건만 사용할 수 있는 경우에는 None을 값으로 가집니다. 후자의 경우 서로 다른 제약 조건은 syntax템플릿을 사용하여 여러 토큰으로 “분해됩니다”.

    exact_version또는 version_rangesNone으로 설정되면 패키지 관리자가 해당 유형의 지정자를 지원하지 않는다는 의미입니다.

Note

specifier_syntax매핑은 설치할 패키지 버전을 선택할 수 있는 생태계 간의 상호 운용성을 제공하기 위한 것입니다. 예를 들어 많은 Linux 배포판에서는 그렇지 않습니다. 각 배포판 릴리스가 수명 주기 동안 패키지 버전을 고정하기 때문입니다(필요한 보안 백포트를 제공하는 경우가 많기는 합니다).

이러한 경우 install명령을 낙관적으로 “이름 전용” 모드로 사용하여 운영 체제에서 제공하는 버전이 적합하기를 기대할 수 있습니다. 더 보수적인 대안은 먼저 query명령을 사용하여 사용 가능한 버전이 프로젝트 제약 조건과 일치하는지 확인한 다음 패키지 이름으로 설치하는 것입니다.

이러한 경우에도 서로 다른 생태계가 업스트림 릴리스를 재패키징된 버전에 매핑하는 방식 때문에 완벽한 1:1 버전 일치는 항상 가능하지 않습니다(예: 릴리스 스키마 변경을 수용하기 위해 epoch를 증가시켜야 했던 경우). 이와 관련하여 epoch 또는 사전 릴리스에 대한 명시적인 매핑 의미 체계는 인코딩하지 않습니다.

재배포

중앙 레지스트리, 알려진 생태계 목록 및 매핑 문서는 각 플랫폼에서 오프라인 배포용으로 패키징할 수 있습니다.

작성자는 각 운영 체제에서 데이터 아티팩트에 사용하는 표준 위치에 이를 배치할 것을 권장합니다. 예를 들어 Linux 및 기타 운영 체제에서는 $XDG_DATA_DIRS, macOS에서는 ~/Library/Application Support, Windows에서는 %LOCALAPPDATA%를 사용합니다. 하위 디렉터리 식별자는 external-packaging-metadata-mappings이어야 하며, 앞서 언급한 스키마에 해당하는 문서만 포함해야 하고, 해당 문서는 정식 파일 이름을 사용해야 합니다.

예시

레지스트리

단순화된 레지스트리는 다음과 같은 형태입니다:

{
  "$schema": "https://raw.githubusercontent.com/jaimergp/external-metadata-mappings/main/schemas/central-registry.schema.json",
  "schema_version": 1,
  "definitions": [
    {
      "id": "dep:generic/zlib",
      "description": "A Massively Spiffy Yet Delicately Unobtrusive Compression Library"
    },
    {
      "id": "dep:generic/libwebp",
      "description": "WebP codec is a library to encode and decode images in WebP format. This package contains the library that can be used in other programs to add WebP support"
    },
    {
      "id": "dep:generic/clang",
      "description": "Language front-end and tooling infrastructure for languages in the C language family for the LLVM project."
    }
  ]
}

알려진 생태계

단일 항목으로 구성된 알려진 생태계의 최소 목록은 다음과 같은 형태입니다:

{
  "$schema": "https://raw.githubusercontent.com/jaimergp/external-metadata-mappings/main/schemas/known-ecosystems.schema.json",
  "schema_version": 1,
  "ecosystems": {
    "conda-forge": {
      "mapping": "https://raw.githubusercontent.com/jaimergp/external-metadata-mappings/refs/heads/main/data/conda-forge.mapping.json"
    }
}

대표적인 식별자는 다음과 같습니다:

Ecosystem Identifier Filename
Debian Bookworm debian+12 debian+12.mapping.json
Fedora 40 fedora+40 fedora+40.mapping.json
Ubuntu 24.04 ubuntu+24.04 ubuntu+24.04.mapping.json
Arch Linux (rolling) arch arch.mapping.json
Homebrew homebrew homebrew.mapping.json
conda-forge conda-forge conda-forge.mapping.json

매핑

간결성을 위해 항목을 몇 개만 포함한 가상의 conda-forge 매핑(conda-forge.mapping.json)은 다음과 같은 형태일 수 있습니다:

{
  "schema_version": 1,
  "name": "conda-forge",
  "description": "Mapping for the conda-forge ecosystem",
  "mappings": [
    {
      "id": "dep:generic/zlib",
      "description": "Massively spiffy yet delicately unobtrusive compression library.",
      "specs": "zlib",  // Simplest form
      "urls": {
        "feedstock": "https://github.com/conda-forge/zlib-feedstock"
      }
    },
    {
      "id": "dep:generic/libwebp",
      "description": "WebP image library. libwebp-base ships libraries; libwebp ships the binaries.",
      "specs": {  // expanded form with single spec per category
        "build": "libwebp",
        "host": "libwebp-base",
        "run": "libwebp"
      },
      "urls": {
        "feedstock": "https://github.com/conda-forge/libwebp-feedstock"
      }
    },
    {
      "id": "dep:generic/clang",
      "description": "Development headers and libraries for Clang",
      "specs": { // expanded form with specs list
        "build": [
          "clang",
          "clangxx"
        ],
        "host": [
          "clangdev"
        ],
        "run": [
          "clang",
          "clangxx",
          "clang-format",
          "clang-tools"
        ]
      },
      "urls": {
        "feedstock": "https://github.com/conda-forge/clangdev-feedstock"
      }
    },
  ],
  "package_managers": [
    {
      "name": "conda",
      "commands": {
        "install": {
          "command": [
            "conda",
            "install",
            "{}"
          ],
          "multiple_specifiers": "always",
          "requires_elevation": false,
        },
        "query": {
          "command": [
            "conda",
            "list",
            "-f",
            "{}"
          ],
          "multiple_specifiers": "never",
          "requires_elevation": false,
        }
      },
      "specifier_syntax": {
        "exact_version": [
          "{name}=={version}"
        ],
        "name_only": [
          "{name}"
        ],
        "version_ranges": {
          "and": ",",
          "equal": "={version}",
          "greater_than": ">{version}",
          "greater_than_equal": ">={version}",
          "less_than": "<{version}",
          "less_than_equal": "<={version}",
          "syntax": [
            "{name}{ranges}"
          ]
        }
      }
    }
  ]
}

실용적인 예

다음 저장소는 이러한 스키마가 실제 사례에서 어떤 모습일 수 있는지에 대한 예를 제공합니다. 이는 규범적인 지침이 아니라, 이러한 스키마를 적용하는 방법을 보여 주기 위한 예시일 뿐입니다:

pyproject-external CLI

다음 예시는 이름 매핑 메커니즘을 사용하는 방법을 보여 줍니다. 이 예시에서는 pyproject-external 패키지의 일부로 구현된 CLI를 사용합니다.

my-cxx-pkg라는 Python 패키지의 소스를 복제했으며, 단일 확장 모듈이 C++로 구현되고 zlib에 연결되며 pybind11을 사용하고, 빌드 백엔드로 meson-python을 사용한다고 하겠습니다:

[build-system]
build-backend = 'mesonpy'
requires = [
  "meson-python>=0.13.1",
  "pybind11>=2.10.4",
]

[external]
build-requires = [
  "dep:virtual/compiler/cxx",
]
host-requires = [
  "dep:generic/zlib",
]

Ubuntu에서 apt에 대한 완전한 이름 매핑이 있으면 다음과 같이 표시될 수 있습니다:

# show all external dependencies as DepURLs
$ python -m pyproject_external show .
[external]
build-requires = [
    "dep:virtual/compiler/cxx",
]
host-requires = [
    "dep:generic/zlib",
]

# show all external dependencies, but mapped to the autodetected ecosystem
$ python -m pyproject_external show --output=mapped .
[external]
build-requires = [
    "g++",
    "python3",
]
host-requires = [
    "zlib1g",
    "zlib1g-dev",
]

# show how to install external dependencies
$ python -m pyproject_external show --output=command .
sudo apt install --yes g++ zlib1g zlib1g-dev python3

아직 해당 설치 명령을 실행하지 않았으므로 외부 의존성이 없을 수 있습니다. 빌드에 실패하면 출력은 다음과 같을 수 있습니다:

$ pip install .
...
× Encountered error while generating package metadata.
╰─> See above for output.

note: This is an issue with the package mentioned above, not pip.

This package has the following external dependencies, if those are missing
on your system they are likely to be the cause of this build failure:

  dep:virtual/compiler/cxx
  dep:generic/zlib

Pip이 이름 매핑 레지스트리를 조회하는 기능을 구현했다면 해당 메시지의 끝부분은 다음과 같이 개선될 수 있습니다:

The following external dependencies are needed to install the package
mentioned above. You may need to install them with `apt`:

  g++
  zlib1g
  zlib1g-dev

사용자가 외부 의존성을 설치하기 위해 conda 패키지와 mamba 패키지 관리자를 사용하려는 경우, ~/.config/pyproject-external/config.toml(또는 이에 해당하는) 파일에 이를 지정할 수 있습니다:

preferred_package_manager = "mamba"

그러면 pyproject-external의 출력이 다음과 같이 변경됩니다:

$ python -m pyproject_external show --output command .
mamba install --yes --channel=conda-forge --channel-priority=strict cxx-compiler zlib python

pyproject-external CLI는 식별자가 표준으로 간주되는지 확인하기 위해 중앙 레지스트리를 대상으로 [external] 테이블 유효성 검사를 수행하는 간단한 방법도 제공합니다:

$ python -m pyproject_external show --validate grpcio-1.71.0.tar.gz
WARNING  Dep URL 'dep:virtual/compiler/cpp' is not recognized in the
central registry. Did you mean any of ['dep:virtual/compiler/c',
'dep:virtual/compiler/cxx', 'dep:virtual/compiler/cuda',
'dep:virtual/compiler/go', 'dep:virtual/compiler/c-sharp']?
[external]
build-requires = [
    "dep:virtual/compiler/c",
    "dep:virtual/compiler/cpp",
]

pyproject-external API

pyproject-external Python API를 사용하면 이러한 작업을 프로그래밍 방식으로 수행할 수도 있습니다:

>>> from pyproject_external import External
>>> external = External.from_pyproject_data(
      {
        "external": {
          "build-requires": [
            "dep:virtual/compiler/c",
            "dep:virtual/compiler/cpp",
          ]
        }
      }
    )
>>> external.validate()
Dep URL 'dep:virtual/compiler/cpp' is not recognized in the central registry. Did you
mean any of ['dep:virtual/compiler/c', 'dep:virtual/compiler/cxx',
'dep:virtual/compiler/cuda', 'dep:virtual/compiler/go', 'dep:virtual/compiler/c-sharp']?
>>> external = External.from_pyproject_data(
      {
        "external": {
          "build-requires": [
            "dep:virtual/compiler/c",
            "dep:virtual/compiler/cxx",  # fixed
          ]
        }
      }
    )
>>> external.validate()
>>> external.to_dict()
{'external': {'build_requires': ['dep:virtual/compiler/c', 'dep:virtual/compiler/cxx']}}
>>> from pyproject_external import detect_ecosystem_and_package_manager
>>> ecosystem, package_manager = detect_ecosystem_and_package_manager()
>>> ecosystem
'conda-forge'
>>> package_manager
'pixi'
>>> external.to_dict(mapped_for=ecosystem, package_manager=package_manager)
{'external': {'build_requires': ['c-compiler', 'cxx-compiler', 'python']}}
>>> external.install_commands(ecosystem, package_manager=package_manager)
# {"command": ["pixi", "add", "{}"]}
[
  ['pixi', 'add', 'c-compiler', 'cxx-compiler', 'python'],
]
>>> external.query_commands(ecosystem, package_manager=package_manager)
# {"command": ["pixi", "list", "{}"]}
[
  ['pixi', 'list', 'c-compiler'],
  ['pixi', 'list', 'cxx-compiler'],
  ['pixi', 'list', 'python'],
]

Grayskull

Python 패키지를 위한 conda 레시피 제너레이터인 Grayskull에 conda/grayskull#518을 통한 개념 증명 프로토타입 구현이 기여되었습니다.

이제 우리 패키지의 레시피 제너레이터에 대한 이름 매핑을 사용하려면 Grayskull을 실행할 수 있습니다.

$ grayskull pypi my-cxx-pkg
#### Initializing recipe for my-cxx-pkg (pypi) ####

Recovering metadata from pypi...
Starting the download of the sdist package my-cxx-pkg
my-cxx-pkg 100% Time:  0:00:10   5.3 MiB/s|###########|
Checking for pyproject.toml
...

Build requirements:
  - python                                 # [build_platform != target_platform]
  - cross-python_{{ target_platform }}     # [build_platform != target_platform]
  - meson-python >= 0.13.1                 # [build_platform != target_platform]
  - pybind11 >= 2.10.4                     # [build_platform != target_platform]
  - ninja                                  # [build_platform != target_platform]
  - libboost-devel                         # [build_platform != target_platform]
  - {{ compiler('cxx') }}
Host requirements:
  - python
  - meson-python >=0.13.1
  - pybind11 >=2.10.4
  - ninja
  - libboost-devel
Run requirements:
  - python

#### Recipe generated on /path/to/recipe/dir for my-cxx-pkg ####

하위 호환성

하위 호환성에는 영향이 없습니다.

보안 영향

이 제안은 기존 프로젝트에 어떠한 보안 영향도 부과하지 않습니다. 제안된 스키마, 레지스트리 및 매핑은 다운스트림 도구가 적절하다고 판단하는 방식으로 자유롭게 사용할 수 있는 리소스입니다.

향후 구현자를 위한 몇 가지 권고 사항도 있습니다. 매핑 스키마는 명령 실행 지침을 인코딩하기 위한 필드를 제안합니다(package_managers[].commands). 변조된 매핑은 이러한 지침을 다른 내용으로 변경할 수 있습니다. 따라서 도구는 온라인 출처에서 매핑을 가져오기 위해 인터넷 연결에 의존해서는 안 됩니다. 대신 다음 중 하나를 수행해야 합니다:

  • 배포된 패키지에 관련 문서를 함께 포함하거나,
  • 이러한 문서의 사전 패키징된 오프라인 배포판에 의존하거나,
  • 가져온 문서의 진위 여부를 검증하기 위한 모범 사례를 구현해야 합니다.

설치 명령은 사용자의 시스템 구성을 변경할 가능성이 있습니다. 가능한 경우 도구는 외부 의존성 설치를 위해 일시적이고 격리된 환경을 생성하는 방식을 우선해야 합니다. 생태계에 해당 기능이 기본적으로 없다면 컨테이너화와 같은 다른 해결책을 사용할 수 있습니다. 최소한 해당 작업의 영향을 알리는 정보성 메시지를 제공해야 합니다.

이 내용을 가르치는 방법

이 PEP의 내용에 익숙해져야 할 대상은 최소 네 부류 이상입니다:

  1. 잘 알려진 DepURL 및 매핑된 생태계 목록을 관리하는 중앙 레지스트리 유지 관리자입니다.
  2. 해당 생태계의 매핑을 최신 상태로 유지하는 패키징 생태계 유지 관리자입니다.
  3. 외부 의존성이 필요한 Python 프로젝트의 관리자
  4. 외부 의존성 메타데이터가 있는 패키지의 최종 사용자

중앙 DepURL 레지스트리 관리자

중앙 DepURL 레지스트리 관리자는 DepURL 모음과 알려진 생태계를 관리합니다. 이러한 기여자는 새로운 DepURL을 정의할 수 있는 경우에 관한 명확하게 정의된 규칙을 참조할 수 있어야 합니다. 표준 DepURL 정의를 느슨하게 관리하는 것은 바람직하지 않습니다. 추가된 각 정의가 대상 생태계의 매핑 유지 관리 부담을 증가시키기 때문입니다.

중앙 레지스트리 관리자는 기본 원칙에 합의하고 이를 저장소 문서의 일부로 작성해야 하며, 이슈 및 풀 리퀘스트 템플릿이나 린팅 도구와 같은 추가 지원 기능을 활용할 수도 있습니다.

패키지 생태계 관리자의 사용

매핑 항목이 누락되면 영향을 받는 생태계의 최종 사용자를 위한 맞춤형 오류 메시지와 기타 UX 지원 기능이 제공되지 않습니다. 따라서 각 패키지 생태계는 중앙 레지스트리에 맞춰 매핑을 최신 상태로 유지하는 것이 권장됩니다. 이를 위한 핵심은 린팅 스크립트와 같은 자동화입니다(예시는 external-metadata-mappings 참조). 또는 이슈나 초안 제출을 통한 정기적인 알림을 활용할 수도 있습니다.

초기 매핑을 설정하는 데는 많은 작업이 필요할 가능성이 높지만, 이상적으로는 지속적인 유지 관리에는 더 적은 노력이 필요해야 합니다.

모범 사례를 발견하고 합의하면, 이를 중앙 레지스트리 저장소에 매핑 관리자용 학습 자료로 문서화해야 합니다.

Python 프로젝트의 관리자

패키지 관리자의 책임은 패키지에 필요한 외부 의존성을 가장 잘 나타내는 DepURL을 결정하는 것입니다. 이는 PEP 725에서 다루며, external-metadata-mappings.streamlit.app에 있는 대화형 매핑 브라우저 데모가 유용할 수 있습니다. 중앙 레지스트리 문서에는 신규 사용자가 결정을 내리는 데 도움이 되는 예제와 자주 묻는 질문이 포함될 수 있습니다.

주어진 의존성에 적합한 DepURL을 사용할 수 없는 경우, 관리자는 중앙 레지스트리에 요청을 제출하는 것을 고려할 수 있습니다. 이를 수행하는 방법에 관한 지침은 중앙 레지스트리 문서의 일부로 제공해야 합니다.

최종 사용자 패키지 소비자

기본적으로 사용자 경험에는 변화가 없습니다. 이는 사용자가 휠에만 의존하는 경우에 특히 그러합니다. 유일한 영향은 외부 런타임 의존성에 의해 발생하며(일반적으로 드물 것으로 예상됨), 그러한 경우에도 호환 가능한 도구를 설치하여 사용자가 선택적으로 참여해야 하기 때문입니다.

선택적으로 참여하는 사용자는 대상 생태계에 누락된 항목이 있음을 발견할 수 있으며, 이 경우 관련 문서 섹션을 안내하는 유익한 오류 메시지를 확인할 수 있어야 합니다. 이를 통해 사용자는 문제의 성격과 가능한 해결책을 파악할 수 있습니다.

이를 통해 일부 사용자가 누락된 항목을 보고하거나, 영향을 받는 매핑에 대한 수정 사항을 제출하거나, 항목이 완전히 없는 경우에는 직접 새 매핑을 유지 관리하기로 결정하기를 바랍니다. 이를 위해 사용자는 매핑 관리자의 책임(앞에서 설명함)을 숙지해야 합니다.

참조 구현

참조 구현에는 다음 세 가지 구성 요소가 포함되어야 합니다.

  1. 최소한 DepURL과 그 설명을 포함하는 중앙 레지스트리입니다. 이 레지스트리에는 패키지 생태계 매핑의 세부 사항이 포함되어서는 안 됩니다(MUST NOT).
  2. 매핑 모음에 대한 표준 사양입니다. JSON Schema는 많은 텍스트 편집기에서 스키마에 널리 사용되므로 표준 사양을 표현하는 자연스러운 선택이 될 수 있습니다.
  3. (2)의 구현으로, 중앙 레지스트리의 내용에서 생태계별 패키지 이름으로의 매핑을 제공합니다.

(1)의 경우 JSON 스키마는 central-registry.schema.json에 정의되어 있습니다. 예시 레지스트리는 registry.json에서 확인할 수 있습니다. (2)의 경우 JSON 스키마는 external-mapping.schema.json에 정의되어 있습니다. 일부 패키지에 대한 예시 매핑 모음은 external-metadata-mappings에서 확인할 수 있습니다. (3)의 경우 JSON 스키마는 known-ecosystems.schema.json에 정의되어 있습니다. 예시 목록은 known-ecosystems.json에서 확인할 수 있습니다. JSON 스키마는 these Pydantic models을 사용하여 생성됩니다.

서로 다른 JSON 문서와 [external] 테이블을 사용하는 참조 CLI 및 Python API는 pyproject-external에서 확인할 수 있습니다.

거부된 아이디어

동일한 기관이 관리하는 중앙 집중식 매핑

레지스트리를 위한 중앙 기관은 유용하지만, PyPI 규모에서 여러 생태계의 매핑을 처리하는 유지 관리 부담은 감당할 수 없습니다. 따라서 중앙 기관은 중앙 레지스트리와 알려진 생태계 목록만 관리하고, 매핑 자체의 유지 관리는 대상 생태계가 담당할 것을 제안합니다.

생태계별 패키지 변형 허용

일부 생태계에는 알려진 패키지의 자체 변형이 있습니다. 예를 들어 Debian의 libsymspg2-dev가 있습니다. dep:deb/debian/libsymspg2-dev와 같은 식별자는 문법적으로 유효하지만, 중앙 레지스트리는 이를 잘 알려진 식별자로 인식하지 않고 대신 generic 대응 항목을 선호해야 합니다. 사용자는 여전히 이를 사용하도록 선택할 수 있지만, 도구는 이에 대해 경고하고 일반적인 식별자를 사용하도록 제안할 수 있습니다. 이는 가능한 경우 생태계에 구애받지 않는 메타데이터를 사용하도록 장려하여 플랫폼과 운영 체제 전반의 도입을 촉진하기 위한 것입니다.

중앙 레지스트리에 더 많은 패키지 메타데이터 추가

중앙 레지스트리에는 식별을 용이하게 하기 위한 DepURL 목록과 최소한의 메타데이터 필드 집합(자유 형식의 텍스트 설명과 관련 위치를 가리키는 하나 이상의 URL)만 포함해야 합니다.

중앙 레지스트리에서 추가 세부 정보를 제외하고, 외부 기여자가 자체 매핑을 유지 관리하면서 자유 형식의 extra_metadata 필드를 통해 식별자에 추가 메타데이터를 주석으로 추가하도록 제안하기로 했습니다.

그 이유는 다음과 같습니다.

  • 기존 필드만으로도 프로젝트 홈을 식별하기에 충분하며, 해당 추가 메타데이터는 그곳에서 얻을 수 있습니다(예를 들어 URL의 저장소에는 저작자와 라이선스에 관한 세부 정보가 포함되어 있을 가능성이 높습니다).
  • 이러한 세부 정보는 실제 대상 생태계에서도 얻을 수 있습니다. 일부 경우에는 이것이 오히려 바람직할 수도 있습니다. 예를 들어 라이선스의 경우, 다운스트림 패키징이 종속성의 번들 해제 또는 선택적 기능 조정을 통해 실제로 라이선스에 영향을 줄 수 있습니다.
  • 이러한 세부 정보는 프로젝트의 수명 동안 변경될 수 있으며, 최신 상태로 유지하려면 거버넌스 기관의 유지 관리 부담이 증가합니다.
  • 따라서 추가 메타데이터를 중앙 집중화하면 대상 생태계 전반에 모호성과 불일치가 발생하며, 서로 다른 버전을 사용할 수 있거나 요구할 수 있습니다.

PyPI 프로젝트를 대상 생태계의 재패키징된 대응 항목에 매핑

다른 생태계가 자체 패키징 시스템을 사용하여 Python 프로젝트를 재배포하는 것은 일반적입니다. 컴파일된 확장이 포함된 패키지에는 이것이 필요하지만, 순수 Python 휠에는 이론적으로 불필요하며, 여기서 유일한 필요성은 메타데이터 변환인 것으로 보입니다. 이 방향의 논의 사례는 Wanting a singular packaging tool/vision #68, Wanting a singular packaging tool/vision #103, spack/spack#28282에서 확인할 수 있습니다.

이 PEP의 제안에서는 PyPI -> 생태계 매핑을 고려하지 않지만, 동일한 스키마를 이러한 용도로 재사용할 수 있습니다. 무엇보다 PyPI 이름에서 PURL 또는 DepURL을 만드는 일은 간단합니다(예: numpypkg:pypi/numpy가 됩니다). 가상의 매핑 유지 관리자는 소스 PURL 식별자를 사용하여 자신의 재패키징 작업에 주석을 달고, 그런 다음 해당 메타데이터를 사용하여 다음과 같은 호환 가능한 매핑을 생성할 수 있습니다.

{
  "$schema": "https://raw.githubusercontent.com/jaimergp/external-metadata-mappings/main/schemas/external-mapping.schema.json",
  "schema_version": 1,
  "name": "PyPI packages in Ubuntu 24.04",
  "description": "PyPI mapping for the Ubuntu 24.04 LTS (Noble) distro",
  "mappings": [
    {
      "id": "dep:pypi/numpy",
      "description": "The fundamental package for scientific computing with Python",
      "specs": ["python3-numpy"],
      "urls": {
        "home": "https://numpy.org/"
      }
    }
  ]
}

이러한 매핑을 사용하면 다운스트림 재배포 작업은 컴파일된 패키지에 집중하고, 순수 휠은 대신 Python 패키징 솔루션에 직접 위임할 수 있습니다.

식별자의 엄격한 검증

중앙 레지스트리는 정식 식별자 목록을 제공하므로, 구현자가 제공된 모든 식별자가 실제로 정식 식별자인지 확인하려 할 수 있습니다. 저자들은 일부 도구 범주에서만 이 관행을 권장하는 것으로 결정했으며, 어떠한 경우에도 이러한 검사를 요구하지 않기로 했습니다.

패키징 커뮤니티에서 [external] 메타데이터 테이블을 채택함에 따라, 여러 프로젝트에서 발견되는 요구 사항을 수용할 수 있도록 정식 식별자 목록이 늘어날 것으로 예상됩니다. 예를 들어, 새로운 C++ 라이브러리나 새로운 언어 컴파일러가 도입될 수 있습니다.

검증이 지나치게 엄격하여 알 수 없는 식별자를 거부하면 external 메타데이터 도입에 불필요한 마찰이 발생하고, 새로 요청된 식별자를 사람이 검토하고 승인해야 하므로 시간이 촉박한 상황에서 중앙 레지스트리에 새 식별자를 추가해야 하는 패키지의 배포가 차단될 가능성이 있습니다.

제공된 식별자가 올바른 형식인지 간단히 확인할 것을 제안합니다. 중앙 레지스트리가 상당한 채택을 통해 성숙해진 후에는 식별자가 정식 식별자로 인식되는지도 강제하도록 향후 작업에서 결정할 수 있습니다.

상속 및 상호 참조 매핑

매핑의 재사용성을 높이는 한 가지 방법은 부모 매핑을 상속하고 추가 값으로 확장하거나 대체할 수 있는 메커니즘을 제공하는 것입니다. 저자들은 URL 확인, 중첩된 종속성, 손상된 리소스의 가능성 등 암시된 복잡성을 고려하여 이 기능을 추가하지 않기로 결정했습니다. 대신 다음과 같은 대안을 제안합니다.

  • 매핑 작성자는 스크립팅과 cron 작업을 통해 파생 매핑 생성을 자동화하십시오. 예를 들어 부모 매핑을 가져오고, 필요한 수정 사항을 적용한 다음 대상 위치에 다시 게시하는 간단한 로직은 많은 유지 관리 부담을 초래하지 않아야 합니다.
  • 지정된 매핑을 사용자 지정 재정의로 확장하려는 최종 사용자를 위해서는 클라이언트 측 도구가 이를 쉽게 수행하는 데 필요한 기능을 구현해야 합니다. 예를 들어 pyproject-external과 같은 도구는 다음 CLI 플래그 또는 환경 변수를 제공할 수 있습니다.
    • --use-mapping / <TOOL>_USE_MAPPING: 정식 위치 대신 지정된 로컬 또는 원격 매핑을 사용합니다.
    • --patch-mapping / <TOOL>_PATCH_MAPPING: 로컬 또는 원격 매핑이 주어지면 정식 위치에서 일치하는 키를 대체하고 일치하지 않는 키를 추가합니다.
    • --extend-mapping / <TOOL>_EXTEND_MAPPING: 로컬 또는 원격 매핑이 주어지면 해당 내용을 정식 매핑에 추가합니다. 도구에서 둘 이상의 매핑 옵션을 사용할 수 있는 경우 사용자가 서로 다른 매핑 옵션을 선택할 수 있다고 가정하면, 이 옵션은 완전히 재정의하지 않고 선택지 집합을 확장합니다.

예를 들어 다음과 같은 external 테이블이 있는 패키지가 있다고 하겠습니다.

[external]
build-requires = [
  "dep:virtual/compiler/c",
]
host-requires = [
  "dep:generic/libffi",
]

그리고 대상 생태계에서 dep:virtual/compiler/cgcc에 매핑하지만 clang이 선호된다면, 다음과 같은 매핑 재정의를 제공할 수 있습니다.

{
  "$schema": "https://raw.githubusercontent.com/jaimergp/external-metadata-mappings/main/schemas/external-mapping.schema.json",
  "schema_version": 1,
  "name": "ecosystem override",
  "description": "Mapping override for my ecosystem of choice",
  "mappings": [
    {
      "id": "dep:virtual/compiler/c",
      "description": "Clang override",
      "specs": "clang"
    }
  ]
}

그러면 다음과 같이 사용합니다.

$ python -m my-tool show \
    sdist/cryptography-46.0.2.tar.gz \
    --output install-command \
    --patch-mapping=my-override.mapping.json

패키지 이름 변경 추적

패키징 생태계에서는 사용되는 명명 체계를 수정하고, 확장하며, 발전시키는 경향이 있습니다. 모놀리식 빌드로 시작한 것을 더 작은 구성 요소로 분할하는 일은 일반적입니다(예: 런타임 전용 환경에 개발 파일을 함께 제공하지 않아 대역폭을 절약할 수 있습니다). 일부 실무자는 SONAME 변경 전반에서 ABI 호환성을 추적하기 위해 패키지 이름을 사용하기도 합니다. 이유는 여러 가지이고 다양할 수 있지만 문제는 동일합니다. 특정 업스트림 프로젝트 이름이 시간이 지남에 따라 서로 다른 이름으로 배포될 수 있습니다.

매핑에서 이러한 변경 사항을 추적하자는 제안에서는 valid_fromvalid_to와 같은 추가 날짜 필드를 포함하자고 제안했지만, 작성자들은 이 아이디어를 거부하기로 결정했습니다. 이는 구현에 복잡성을 더하고, 최신 상태로 유지하기 어려우며, 최종 사용자에게 가치를 더하지 않고 단순히 과거 기록으로만 기능합니다.

대신 버전이 지정된 배포판은 릴리스마다 별도의 매핑을 유지할 것으로 예상합니다(제안된 매핑 명명 체계를 참조하십시오). 롤링 생태계는 필요하고 실행 가능한 경우 지원 중단 경고를 제공하면서 별칭 패키지를 유지하도록 노력해야 합니다. 일반적으로 필요한 경우 최종 사용자가 이전 버전을 참조할 수 있도록 매핑 파일을 공개 버전 관리하에 유지할 것도 권장합니다.

기존 데이터베이스를 중앙 레지스트리로 재사용하기

패키지의 생태계 간 데이터베이스를 간단히 온라인 검색해 보면 이 제안의 필요에 가까운 서로 다른 결과 집합이 나오겠지만, 정확히 부합하지는 않습니다. 예를 들면:

  • 일부 솔루션은 Repology 또는 pkgs.org와 같이 Linux 배포판이나 Unix 시스템에만 초점을 맞춥니다.
  • Libraries.io와 같은 다른 서비스는 로그인이 필요합니다.
  • ecosyste.ms와 같은 다른 제공업체는 API를 통해서만 이용할 수 있습니다.
  • purldb 서비스는 입력 요구 사항 식별과 관련된 추상 PURL 대신 특정 패키지 아티팩트를 식별하는 구체적인 PURL을 수집하는 데만 초점을 맞춥니다.

제안된 매핑은 라이브 서버와 API의 유지 관리를 요구하지 않으면서 가능한 한 경량화를 지향합니다. 단순히 온라인과 오프라인에서 쉽게 업데이트하고 배포할 수 있는 정적 JSON 파일 모음입니다.

향후 다음 기능을 제공하는 서비스가 존재한다면, 이 PEP를 대체할 강력한 후보가 될 것입니다.

  • 소스 DepURL, PURL 및 재패키징된 대응 항목 간 매핑을 제공합니다. 이는 PURL에 가상 패키지라는 개념과 편리한 버전 범위 표현식이 추가되었음을 의미합니다.
  • 주어진 입력 PURL에 대한 패키지 관리자 지침을 생성할 수 있습니다.
  • 오프라인에서 사용할 수 있도록 로컬 아티팩트로 배포할 수 있습니다.
  • 라이브 서버나 API가 필요하지 않습니다.
  • FOSS 라이선스가 적용됩니다.

공개된 문제

현재는 없습니다.

참고 자료

부록 A: 운영 제안

생태계 매핑과 달리 중앙 레지스트리와 알려진 생태계 목록은 중앙 기관에서 유지 관리해야 합니다. 작성자들은 다음을 제안합니다.

  • external-metadata-mappingspyproject-external 저장소를 PyPA GitHub 조직(또는 PEP 772에 따른 동등한 조직)에서 호스팅합니다.
  • 이 두 저장소의 관리자 팀을 만들고, 이 PEP의 작성자들을 초기 구성원으로 삼아 PEP 772에 따라 운영하십시오.

부록 B: 가상 버전 관리 제안

가상 의존성은 비가상 의존성과 동일한 구문으로 버전 관리할 수 있지만, 그 의미는 모호할 수 있습니다(예를 들어 구현이 여러 개일 수 있고 가상 인터페이스는 명확하게 버전 관리되지 않을 수 있습니다). 아래에서는 이러한 의미를 표준화할 때 중앙 레지스트리 관리자들이 고려할 몇 가지 제안을 제시합니다.

  • OpenMP: 표준에 일반적인 MAJOR.MINOR 버전이 있으므로 >=4.5처럼 표시됩니다.
  • BLAS/LAPACK: 표준 API를 정의하는 Reference LAPACK을 사용하는 버전 관리 방식을 사용해야 합니다. MAJOR.MINOR.MICRO를 사용하므로 >=3.10.0처럼 표시됩니다.
  • 컴파일러: 언어 표준을 구현합니다. C, C++ 및 Fortran의 경우 이러한 표준은 연도로 버전이 지정됩니다. 버전이 올바르게 정렬되도록 전체 연도(네 자리)를 사용할 것을 권장합니다. 따라서 “at least C99”는 >=1999가 되고, C++14 또는 Fortran 77을 선택하면 각각 ==2014또는 ==1977이 됩니다. 다른 언어에서는 다른 버전 관리 방식을 사용할 수 있습니다. 이러한 방식은 pyproject.toml에서 사용되기 전에 어딘가에 설명되어야 합니다.