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

Python 개선 제안 한국어 번역

PEP 427 – 휠 바이너리 패키지 형식 1.0

Author:
Daniel Holth <dholth at gmail.com>
BDFL-Delegate:
Alyssa Coghlan <ncoghlan at gmail.com>
Discussions-To:
Distutils-SIG list
Status:
Final
Type:
Standards Track
Topic:
Packaging
Created:
20-Sep-2012
Post-History:
18-Oct-2012, 15-Feb-2013
Resolution:
Python-Dev message

Table of Contents

번역·라이선스 안내

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

Important

This PEP is a historical document. The up-to-date, canonical spec, Binary distribution format, is maintained on the PyPA specs page.

×

See the PyPA specification update process for how to propose changes.

초록

이 PEP는 “wheel”이라고 하는 Python용 빌드 패키지 형식을 설명합니다.

휠은 특수한 형식의 파일 이름과 .whl확장자를 가진 ZIP 형식의 아카이브입니다. 특정 설치 스킴에 따라 PEP 376에 정의된 방식으로 설치되는 것과 거의 동일한 단일 배포 패키지를 포함합니다. 특수한 설치 프로그램을 사용하는 것이 권장되지만, 휠 파일은 표준 ‘unzip’ 도구를 사용하여 site-packages에 간단히 압축 해제하는 방식으로 설치할 수 있으며, 나중에 해당 콘텐츠를 최종 경로로 분산할 수 있을 만큼 충분한 정보를 보존합니다.

PEP 승인

이 PEP는 2013년 2월 16일 Alyssa Coghlan에 의해 승인되었으며, 정의된 휠 버전은 1.0으로 업데이트되었습니다 [1]

근거

Python에는 sdist보다 설치하기 쉬운 패키지 형식이 필요합니다. Python의 sdist 패키지는 distutils 및 setuptools 빌드 시스템에 의해 정의되고 이를 필요로 하며, 새 가상 환경에 설치할 수 있도록 임의의 코드를 실행하여 빌드 및 설치하고 코드를 다시 컴파일합니다. 빌드와 설치를 결합하는 이 시스템은 느리고 유지 관리가 어려우며, 빌드 시스템과 설치 프로그램 모두에서 혁신을 저해합니다.

휠은 빌드 시스템과 설치 프로그램 사이에 더 단순한 인터페이스를 제공하여 이러한 문제를 해결하려고 합니다. 휠 바이너리 패키지 형식은 설치 프로그램이 빌드 시스템을 알 필요가 없도록 하고, 여러 설치에 걸쳐 컴파일 시간을 분산하여 시간을 절약하며, 대상 환경에 빌드 시스템을 설치할 필요를 없앱니다.

세부 사항

휠 ‘distribution-1.0-py32-none-any.whl’ 설치

휠 설치는 개념적으로 두 단계로 구성됩니다.

  • 압축 해제합니다.
    1. distribution-1.0.dist-info/WHEEL을 구문 분석합니다.
    2. 설치 프로그램이 Wheel-Version과 호환되는지 확인합니다. 다음의 경우 경고합니다. 부 버전이 더 크면 경고하고, 주 버전이 더 크면 중단합니다.
    3. Root-Is-Purelib == ‘true’이면 아카이브를 purelib (site-packages)에 압축 해제합니다.
    4. 그렇지 않으면 아카이브를 platlib(site-packages)에 압축 해제합니다.
  • 분산합니다.
    1. 압축 해제된 아카이브에는 distribution-1.0.dist-info/와 (데이터가 있는 경우) distribution-1.0.data/가 포함됩니다.
    2. distribution-1.0.data/의 각 하위 트리를 해당 대상 경로로 이동합니다. distribution-1.0.data/의 각 하위 디렉터리는 대상 디렉터리 딕셔너리의 키이며, 예를 들면 distribution-1.0.data/(purelib|platlib|headers|scripts|data)와 같습니다. 처음 지원되는 경로는 distutils.command.install에서 가져옵니다.
    3. 해당하는 경우 #!python으로 시작하는 스크립트를 올바른 인터프리터를 가리키도록 올바른 인터프리터로.
    4. distribution-1.0.dist-info/RECORD를 설치된 경로로 업데이트합니다.
    5. 비어 있는 distribution-1.0.data디렉터리를 제거합니다.
    6. 설치된 모든 .py를 .pyc로 컴파일합니다. (제거 프로그램은 RECORD에 언급되지 않은 경우에도 .pyc를 제거할 수 있을 만큼 충분히 지능적이어야 합니다.)

권장 설치 프로그램 기능

#!python을 다시 작성하십시오.
wheel에서는 스크립트가 {distribution}-{version}.data/scripts/에 패키징됩니다. scripts/의 파일 첫 번째 줄이 정확히 b'#!python'으로 시작하면 올바른 인터프리터를 가리키도록 다시 작성합니다. 아카이브가 Windows에서 생성된 경우 Unix 설치 프로그램은 이러한 파일에 +x 비트를 추가해야 할 수 있습니다.

b'#!pythonw'규칙이 허용됩니다. b'#!pythonw'은 콘솔 스크립트가 아닌 GUI 스크립트를 나타냅니다.

스크립트 래퍼를 생성합니다.
wheel에서는 Unix 시스템에서 패키징된 스크립트에 함께 제공되는 .exe 래퍼가 확실히 포함되지 않습니다. Windows 설치 프로그램은 설치 중에 이를 추가할 수 있습니다.

권장 아카이버 기능

아카이브 끝에 .dist-info를 배치합니다.
아카이버는 .dist-info파일을 물리적으로 아카이브 끝에 배치하는 것이 좋습니다. 이를 통해 전체 아카이브를 다시 작성하지 않고도 메타데이터를 수정하는 기능을 비롯하여 잠재적으로 흥미로운 ZIP 트릭을 사용할 수 있습니다.

파일 형식

파일 이름 규칙

wheel 파일 이름은 {distribution}-{version}(-{build tag})?-{python tag}-{abi tag}-{platform tag}.whl입니다.

배포판
배포판 이름, 예: ‘django’, ‘pyramid’입니다.
버전
배포판 버전, 예: 1.0입니다.
빌드 태그
선택적 빌드 번호입니다. 숫자로 시작해야 합니다. 다른 모든 측면(즉, 이름, 버전 및 기타 태그)이 동일한 두 wheel 파일 이름이 있을 때 동률을 가르는 기준으로 사용됩니다. 지정되지 않은 경우 빈 튜플로 정렬하고, 그렇지 않은 경우 첫 번째 항목이 초기 숫자를 int로 나타낸 값이고 두 번째 항목이 태그의 나머지를 str로 나타낸 값인 두 항목 튜플로 정렬합니다.
언어 구현 및 버전 태그
예: ‘py27’, ‘py2’, ‘py3’입니다.
ABI 태그
예: ‘cp33m’, ‘abi3’, ‘none’입니다.
플랫폼 태그
예: ‘linux_x86_64’, ‘any’입니다.

예를 들어, distribution-1.0-1-py27-none-any.whl은 ‘distribution’이라는 패키지의 첫 번째 빌드이며, Python 2.7(Python 2.7의 모든 구현)과 호환되고, ABI가 없으며(순수 Python), 모든 CPU 아키텍처에서 사용할 수 있습니다.

확장자 앞에 있는 파일 이름의 마지막 세 구성 요소를 “호환성 태그”라고 합니다. 호환성 태그는 패키지의 기본 인터프리터 요구 사항을 나타내며 PEP 425에 자세히 설명되어 있습니다.

이스케이프 및 유니코드

파일 이름의 각 구성 요소는 영숫자가 아닌 문자의 연속 부분을 밑줄 _로 바꾸어 이스케이프합니다.:

re.sub("[^\w\d.]+", "_", distribution, re.UNICODE)

아카이브 파일 이름은 유니코드입니다. 도구가 비ASCII 파일 이름을 지원하도록 업데이트되기까지는 시간이 걸리겠지만, 이 사양에서는 해당 파일 이름을 지원합니다.

아카이브 내부의 파일 이름은 UTF-8로 인코딩됩니다. 일반적으로 사용되는 일부 ZIP 클라이언트는 UTF-8 파일 이름을 제대로 표시하지 않지만, ZIP 사양과 Python의 zipfile모두 해당 인코딩을 지원합니다.

파일 내용

wheel 파일의 내용은 {distribution}을 패키지 이름(예: beaglevote)으로, {version}을 패키지 버전(예: 1.0.0)으로 대체했을 때 다음으로 구성됩니다.

  1. 아카이브의 루트인 /에는 WHEEL에 지정된 대로 purelib 또는 platlib에 설치할 모든 파일이 포함됩니다. purelibplatlib은 일반적으로 둘 다 site-packages입니다.
  2. {distribution}-{version}.dist-info/에는 메타데이터가 포함됩니다.
  3. {distribution}-{version}.data/에는 아직 포함되지 않은 비어 있지 않은 각 설치 스킴 키에 대해 하나의 하위 디렉터리가 포함되며, 하위 디렉터리 이름은 설치 경로 딕셔너리의 인덱스입니다(예: data, scripts, headers, purelib, platlib).
  4. Python 스크립트는 scripts에 있어야 하며, 설치 시 스크립트 래퍼 생성 및 #!python 재작성을 사용하려면 정확히 b'#!python'으로 시작해야 합니다. 확장자가 있거나 없어도 됩니다.
  5. {distribution}-{version}.dist-info/METADATA은 메타데이터 버전 1.1 이상 형식의 메타데이터입니다.
  6. {distribution}-{version}.dist-info/WHEEL은 동일한 기본 key: value 형식으로 아카이브 자체에 대한 메타데이터입니다.:
    Wheel-Version: 1.0
    Generator: bdist_wheel 1.0
    Root-Is-Purelib: true
    Tag: py2-none-any
    Tag: py3-none-any
    Build: 1
    
  7. Wheel-Version은 Wheel 사양의 버전 번호입니다.
  8. Generator는 아카이브를 생성한 소프트웨어의 이름이며, 선택적으로 버전을 나타냅니다.
  9. Root-Is-Purelib은 아카이브의 최상위 디렉터리를 purelib에 설치해야 하는 경우 참이고, 그렇지 않으면 루트를 platlib에 설치해야 합니다.
  10. Tag는 휠의 확장된 호환성 태그이며, 이 예제에서 파일 이름에는 py2.py3-none-any가 포함됩니다.
  11. Build는 빌드 번호이며, 빌드 번호가 없으면 생략됩니다.
  12. 휠 설치 프로그램은 Wheel-Version이 지원하는 버전보다 높으면 경고해야 하며, Wheel-Version의 주 버전이 지원하는 버전보다 높으면 실패해야 합니다.
  13. 휠은 여러 Python 버전에서 작동하도록 설계된 설치 형식이므로 일반적으로 .pyc 파일을 포함하지 않습니다.
  14. 휠에는 setup.py 또는 setup.cfg가 포함되지 않습니다.

이 버전의 휠 사양은 distutils 설치 체계를 기반으로 하며, 다른 위치에 파일을 설치하는 방법은 정의하지 않습니다. 이 레이아웃은 기존 wininst 및 egg 바이너리 형식이 제공하는 기능의 상위 집합을 제공합니다.

디렉터리인 .dist-info
  1. 휠 .dist-info 디렉터리에는 최소한 METADATA, WHEEL 및 RECORD가 포함됩니다.
  2. METADATA는 패키지 메타데이터이며, sdists의 루트에 있는 PKG-INFO와 동일한 형식입니다.
  3. WHEEL은 패키지 빌드에 특화된 휠 메타데이터입니다.
  4. RECORD는 휠에 포함된 (거의) 모든 파일과 해당 보안 해시의 목록입니다. 관련 PEP 376과 달리, 자체 해시를 포함할 수 없는 RECORD를 제외한 모든 파일은 해당 해시를 포함해야 합니다. 해시 알고리즘은 sha256 이상이어야 하며, 특히 md5와 sha1은 허용되지 않습니다. 서명된 휠 파일은 아카이브의 무결성을 검증하기 위해 RECORD의 강력한 해시에 의존하기 때문입니다.
  5. PEP 376의 INSTALLER와 REQUESTED는 아카이브에 포함되지 않습니다.
  6. RECORD.jws는 디지털 서명에 사용됩니다. 이는 RECORD에 언급되지 않습니다.
  7. RECORD.p7s는 휠 파일을 보호하기 위해 S/MIME 서명을 사용하려는 사람을 배려하여 허용됩니다. 이는 RECORD에 언급되지 않습니다.
  8. 압축을 해제하는 동안 휠 설치 프로그램은 RECORD의 모든 해시를 파일 내용과 대조하여 검증합니다. RECORD와 그 서명을 제외하고, 아카이브의 파일 중 RECORD에 언급되어 있지 않거나 올바른 해시가 기록되어 있지 않은 파일이 하나라도 있으면 설치에 실패합니다.
해당 .data 디렉터리

일반적으로 site-packages 내부에 설치되지 않는 모든 파일은 .data 디렉터리로 들어가며, .dist-info 디렉터리와 같은 이름을 사용하되 .data/ 확장자를 사용합니다.:

distribution-1.0.dist-info/

distribution-1.0.data/

해당 .data 디렉터리에는 배포 패키지의 스크립트, 헤더, 문서 등이 포함된 하위 디렉터리가 들어 있습니다. 설치 중에는 이러한 하위 디렉터리의 내용이 해당 대상 경로로 이동됩니다.

서명된 휠 파일

휠 파일에는 디지털 서명을 가능하게 하는 확장된 RECORD가 포함됩니다. PEP 376의 RECORD는 md5sum 대신 두 번째 열에 보안 해시 digestname=urlsafe_b64encode_nopad(digest) (뒤에 = 문자를 붙이지 않는 URL 안전 base64 인코딩)를 포함하도록 변경됩니다. 가능한 모든 항목에 해시가 적용되며, .pyc 파일과 같은 생성된 파일도 포함되지만 자체 해시를 포함할 수 없는 RECORD는 제외됩니다. 예를 들어:

file.py,sha256=AVTFPZpEKzuHr7OvQZmhaU3LvwKz06AJw8mT\_pNh2yI,3144
distribution-1.0.dist-info/RECORD,,

서명 파일인 RECORD.jws 및 RECORD.p7s는 RECORD가 생성된 후에만 추가할 수 있으므로 RECORD에는 전혀 언급되지 않습니다. 아카이브의 다른 모든 파일에는 RECORD에 올바른 해시가 있어야 하며, 그렇지 않으면 설치가 실패합니다.

JSON 웹 서명을 사용하는 경우, 하나 이상의 JSON Web Signature JSON Serialization (JWS-JS) 서명이 RECORD에 인접한 RECORD.jws 파일에 저장됩니다. JWS는 RECORD의 SHA-256 해시를 서명의 JSON 페이로드로 포함하여 RECORD에 서명하는 데 사용됩니다.:

{ "hash": "sha256=ADD-r2urObZHcxBW3Cr-vDCu5RJwT4CaRTHiFmbcIYY" }

(해시 값은 RECORD에서 사용되는 것과 동일한 형식입니다.)

RECORD.p7s를 사용하는 경우, RECORD의 분리된 S/MIME 형식 서명을 포함해야 합니다.

휠 설치 프로그램은 디지털 서명을 이해할 필요는 없지만 RECORD의 해시를 추출된 파일 내용과 반드시 대조하여 검증해야 합니다. 설치 프로그램이 RECORD에 대해 파일 해시를 검사하면, 별도의 서명 검사기는 RECORD가 서명과 일치하는지만 확인하면 됩니다.

다음을 참조하십시오.

비교 대상: .egg

  1. 휠은 설치 형식이고, egg는 임포트할 수 있습니다. 휠 아카이브에는 .pyc를 포함할 필요가 없으며, 특정 Python 버전이나 구현에 덜 종속됩니다. 휠은 이전 버전의 Python으로 빌드된 (순수 Python) 패키지를 설치할 수 있으므로 패키저가 따라잡을 때까지 항상 기다릴 필요는 없습니다.
  2. 휠은 .dist-info 디렉터리를 사용하고, egg는 .egg-info를 사용합니다. 휠은 Python 패키징의 새로운 세계 및 그것이 가져오는 새로운 개념과 호환됩니다.
  3. 휠은 오늘날의 다중 구현 환경에 적합한 더 풍부한 파일 이름 지정 규칙을 사용합니다. 하나의 휠 아카이브는 여러 Python 언어 버전 및 구현, ABI와 시스템 아키텍처에 대한 호환성을 나타낼 수 있습니다. 역사적으로 ABI는 특정 CPython 릴리스에 종속되었지만, 휠은 안정 ABI를 사용할 준비가 되어 있습니다.
  4. 휠은 손실이 없습니다. 최초의 휠 구현인 bdist_wheel은 항상 egg-info를 생성한 다음 이를 .whl로 변환합니다. 기존 egg 및 bdist_wininst 배포판을 변환하는 것도 가능합니다.
  5. 휠에는 버전이 지정됩니다. 모든 휠 파일에는 휠 사양의 버전과 이를 패키징한 구현이 포함됩니다. 다음 마이그레이션은 간단히 Wheel 2.0으로 진행할 수 있기를 바랍니다.
  6. 휠은 다른 Python에 대한 참조입니다.

FAQ

휠은 .data 디렉터리를 정의합니다. 모든 데이터를 그곳에 넣어야 합니까?

이 명세는 코드를 어떻게 구성해야 하는지에 대해서는 특정한 입장을 취하지 않습니다. 해당 .data 디렉터리는 일반적으로 site-packages 내부나 PYTHONPATH에 설치되지 않는 파일을 위한 장소일 뿐입니다. 다시 말해, 그러한 파일들이 보통 wheel.data 디렉터리에 배포되지 않더라도 pkgutil.get_data(package, resource)를 계속 사용할 수 있습니다.

wheel은 왜 첨부 서명(attached signature)을 포함합니까?

첨부 서명은 아카이브와 함께 이동하기 때문에 분리 서명(detached signature)보다 더 편리합니다. 개별 파일만 서명되므로, 서명을 무효화하지 않고도 아카이브를 재압축할 수 있으며, 전체 아카이브를 내려받지 않고도 개별 파일을 검증할 수 있습니다.

wheel은 왜 JWS 서명을 허용합니까?

JWS가 속한 JOSE 명세들은 구현하기 쉽도록 설계되어 있으며, 이는 wheel의 주요 설계 목표 중 하나이기도 합니다. JWS는 유용하고 간결한 순수 Python 구현을 만들어냅니다.

wheel은 왜 S/MIME 서명도 허용합니까?

S/MIME 서명은 기존 공개 키 인프라를 wheel과 함께 사용해야 하거나 사용하고자 하는 사용자를 위해 허용됩니다.

서명된 패키지는 안전한 패키지 업데이트 시스템에서 하나의 기본 구성 요소일 뿐입니다. Wheel은 그 구성 요소만을 제공합니다.

“purelib”와 “platlib”의 차이는 무엇입니까?

Wheel은 일부 플랫폼에서 중요한 의미를 갖는 “purelib”와 “platlib”의 구분을 유지합니다. 예를 들어, Fedora는 순수 Python 패키지를 ‘/usr/lib/pythonX.Y/site-packages’에, 플랫폼 종속 패키지를 ‘/usr/lib64/pythonX.Y/site-packages’에 설치합니다.

모든 파일이 {name}-{version}.data/purelib에 있고 “Root-Is-Purelib: false”인 wheel은, 동일한 파일들이 루트에 있고 “Root-Is-Purelib: true”인 wheel과 동등하며, “purelib”와 “platlib”두 범주 모두에 파일이 있어도 합법입니다.

실제로 wheel은 순수 Python인지 여부에 따라 “purelib”나 “platlib”중 하나만 가져야 하며, 해당 파일들은 “Root-is-purelib”에 맞는 설정과 함께 루트에 있어야 합니다.

wheel 파일에서 Python 코드를 직접 임포트하는 것이 가능합니까?

기술적으로는, 단순 추출을 통한 설치 지원과 zipimport와 호환되는 아카이브 형식 사용이 결합되어 있기 때문에, wheel 파일의 일부는 sys.path에 직접 놓이는 것을 실제로 지원합니다. 그러나 이러한 동작이 형식 설계의 자연스러운 결과이기는 하지만, 실제로 이에 의존하는 것은 일반적으로 권장되지 않습니다.

첫째, wheel 주로 배포 형식으로 설계되었기 때문에, 설치 단계를 건너뛴다는 것은 완전한 설치를 전제로 하는 기능들(예: 감사 및 보안 업데이트 목적으로 제대로 추적할 수 있는 방식으로 의존성을 포착하고 관리하기 위해 pipvirtualenv같은 표준 도구를 사용하는 것, 또는 헤더 파일을 적절한 위치에 게시하여 C 확장을 위한 표준 빌드 체계와 완전히 통합하는 것)에 의존하지 않도록 의도적으로 피한다는 것을 의미합니다.

둘째, 일부 Python 소프트웨어는 zip 아카이브에서 직접 실행되도록 지원하게끔 작성되어 있지만, 완전히 설치되었다는 전제하에 코드를 작성하는 것이 여전히 흔합니다. 이러한 전제가 zip 아카이브에서 소프트웨어를 실행하려는 시도로 인해 깨지면, 실패가 흔히 모호하고 진단하기 어려워질 수 있습니다(특히 서드파티 라이브러리에서 발생할 경우). 이와 관련된 문제의 가장 흔한 두 가지 원인은, zip 아카이브에서 C 확장 모듈을 임포트하는 것이 CPython에서 지원되지 않는다는 사실(어떤 플랫폼에서도 동적 로딩 메커니즘이 이를 직접 지원하지 않기 때문입니다)과, zip 아카이브에서 실행할 때 __file__ 속성이 더 이상 일반적인 파일 시스템 경로가 아니라 파일 시스템 상의 zip 아카이브 위치와 아카이브 내부 모듈의 상대 경로를 모두 포함하는 결합 경로를 가리킨다는 사실입니다. 소프트웨어가 내부적으로 추상 리소스 API를 올바르게 사용하는 경우에도, 외부 구성 요소와의 인터페이스에는 여전히 실제 디스크상의 파일이 필요할 수 있습니다.

메타클래스, 몽키패칭, 메타패스 임포터와 마찬가지로, 이 기능을 활용해야 한다는 확신이 없다면 거의 확실히 필요하지 않습니다. 그럼에도 불구하고 사용하기로 결정한다면, 많은 프로젝트가 완전히 설치된 패키지로 재현된 실패를 진짜 버그로 인정하기 전에 요구할 것이라는 점을 유의하십시오.

참고 문헌

부록

urlsafe-base64-nopad 구현 예시:

# urlsafe-base64-nopad for Python 3
import base64

def urlsafe_b64encode_nopad(data):
    return base64.urlsafe_b64encode(data).rstrip(b'=')

def urlsafe_b64decode_nopad(data):
    pad = b'=' * (4 - (len(data) & 3))
    return base64.urlsafe_b64decode(data + pad)