[Final] PEP 440 - Version Identification and Dependency Specification

원문 링크: PEP 440 - Version Identification and Dependency Specification

상태: Final 유형: Standards Track 작성일: 18-Mar-2013

PEP 440 – 버전 식별 및 의존성 명세 (Version Identification and Dependency Specification)

개요 (Abstract)

이 PEP는 Python 소프트웨어 배포판의 버전을 식별하고 특정 버전에 대한 의존성을 선언하는 표준화된 체계를 설명합니다. 이 문서는 이전 버전 관리 표준화 시도인 PEP 345 및 PEP 386의 여러 한계점을 다루고 있습니다.

정의 (Definitions)

  • 프로젝트 (Projects): 통합을 위해 제공되는 소프트웨어 구성 요소입니다. Python 라이브러리, 프레임워크, 스크립트, 플러그인, 애플리케이션, 데이터 또는 기타 리소스 모음 등이 포함됩니다. 공개 Python 프로젝트는 일반적으로 Python Package Index (PyPI)에 등록됩니다.
  • 릴리스 (Releases): 프로젝트의 고유하게 식별되는 스냅샷입니다.
  • 배포판 (Distributions): 릴리스를 게시하고 배포하는 데 사용되는 패키지 파일입니다.
  • 빌드 도구 (Build tools): 개발 시스템에서 실행되어 소스 및 바이너리 배포 아카이브를 생성하는 자동화된 도구입니다.
  • 인덱스 서버 (Index servers): 버전 및 의존성 메타데이터를 게시하고 허용되는 메타데이터에 제약을 가하는 활성 배포 레지스트리입니다.
  • 설치 도구 (Installation tools): 배포 대상에서 실행되도록 특별히 고안된 통합 도구로, 인덱스 서버 또는 기타 지정된 위치에서 소스 및 바이너리 배포 아카이브를 사용하고 대상 시스템에 배포합니다.
  • 자동화된 도구 (Automated tools): 빌드 도구, 인덱스 서버, 게시 도구, 통합 도구 및 배포 버전 및 의존성 메타데이터를 생성하거나 사용하는 기타 모든 소프트웨어를 포함하는 총칭입니다.

버전 체계 (Version Scheme)

배포판은 모든 정의된 버전 비교 작업을 지원하는 공개 버전 식별자로 식별됩니다. 이 버전 체계는 특정 배포 아카이브가 제공하는 배포 버전을 설명하는 데 사용될 뿐만 아니라 소프트웨어를 빌드하거나 실행하는 데 필요한 의존성 버전에 대한 제약을 설정하는 데도 사용됩니다.

공개 버전 식별자 (Public version identifiers)

표준 공개 버전 식별자는 다음 체계를 따라야 합니다.

[N!]N(.N)*[{a|b|rc}N][.postN][.devN]

공개 버전 식별자는 선행 또는 후행 공백을 포함해서는 안 됩니다. 또한 주어진 배포판 내에서 고유해야 합니다.

설치 도구는 이 체계를 따르지 않는 공개 버전을 무시해야 하지만, 아래에 명시된 정규화(normalization)를 포함해야 합니다.

공개 버전 식별자는 최대 5개의 세그먼트로 나뉩니다.

  • Epoch 세그먼트 (Epoch segment): N!
  • 릴리스 세그먼트 (Release segment): N(.N)*
  • 프리-릴리스 세그먼트 (Pre-release segment): {a|b|rc}N
  • 포스트-릴리스 세그먼트 (Post-release segment): .postN
  • 개발 릴리스 세그먼트 (Development release segment): .devN

모든 숫자 구성 요소는 ASCII 숫자의 시퀀스로 표현된 음이 아닌 정수여야 합니다. 또한 텍스트 문자열이 아닌 숫자 값에 따라 해석되고 정렬되어야 합니다.

로컬 버전 식별자 (Local version identifiers)

로컬 버전 식별자는 다음 체계를 따라야 합니다.

<public version identifier>[+<local version label>]

이는 일반적인 공개 버전 식별자(이전 섹션에서 정의됨)와 임의의 “로컬 버전 레이블”로 구성되며, 더하기 기호(+)로 구분됩니다. 로컬 버전 레이블에는 특정 의미가 할당되지 않지만, 일부 구문 제한이 적용됩니다.

로컬 버전 식별자는 상위 프로젝트의 완전히 API (및 해당되는 경우 ABI) 호환 패치 버전을 나타내는 데 사용됩니다.

로컬 버전 레이블은 다음 허용 문자 집합으로 제한되어야 합니다.

  • ASCII 문자 ([a-zA-Z])
  • ASCII 숫자 ([0-9])
  • 마침표 (.)

로컬 버전 레이블은 ASCII 문자 또는 숫자로 시작하고 끝나야 합니다.

최종 릴리스 (Final releases)

릴리스 세그먼트와 선택적으로 epoch 식별자로만 구성된 버전 식별자를 “최종 릴리스”라고 합니다.

릴리스 세그먼트는 점으로 구분된 하나 이상의 음이 아닌 정수 값으로 구성됩니다.

N(.N)*

프로젝트 내의 최종 릴리스는 일관되게 증가하는 방식으로 번호가 매겨져야 합니다. 그렇지 않으면 자동화된 도구가 올바르게 업그레이드할 수 없습니다.

프리-릴리스 (Pre-releases)

일부 프로젝트는 최종 릴리스 이전에 사용자 테스트를 지원하기 위해 “알파, 베타, 릴리스 후보” 프리-릴리스 주기를 사용합니다.

프로젝트의 개발 주기 일부로 사용되는 경우, 이러한 프리-릴리스는 버전 식별자에 프리-릴리스 세그먼트를 포함하여 표시됩니다.

  • X.YaN (알파 릴리스)
  • X.YbN (베타 릴리스)
  • X.YrcN (릴리스 후보)
  • X.Y (최종 릴리스)

릴리스 세그먼트와 프리-릴리스 세그먼트로만 구성된 버전 식별자를 “프리-릴리스”라고 합니다.

포스트-릴리스 (Post-releases)

일부 프로젝트는 배포된 소프트웨어에 영향을 미치지 않는 최종 릴리스의 사소한 오류(예: 릴리스 노트의 오류 수정)를 해결하기 위해 포스트-릴리스를 사용합니다.

프로젝트의 개발 주기 일부로 사용되는 경우, 이러한 포스트-릴리스는 버전 식별자에 포스트-릴리스 세그먼트를 포함하여 표시됩니다.

X.Y.postN (포스트-릴리스)

개발 릴리스 세그먼트 없이 포스트-릴리스 세그먼트를 포함하는 버전 식별자를 “포스트-릴리스”라고 합니다.

개발 릴리스 (Developmental releases)

일부 프로젝트는 정기적인 개발 릴리스를 수행하며, 시스템 패키지 관리자(특히 Linux 배포판의 경우)는 나중에 나올 프로젝트 릴리스와 충돌하지 않는 소스 컨트롤에서 직접 초기 릴리스를 생성할 수 있습니다.

프로젝트의 개발 주기 일부로 사용되는 경우, 이러한 개발 릴리스는 버전 식별자에 개발 릴리스 세그먼트를 포함하여 표시됩니다.

X.Y.devN (개발 릴리스)

개발 릴리스 세그먼트를 포함하는 버전 식별자를 “개발 릴리스”라고 합니다.

버전 Epoch (Version epochs)

버전 식별자에 포함되는 경우, epoch는 다른 모든 구성 요소 이전에 나타나며 느낌표(!)로 릴리스 세그먼트와 구분됩니다.

E!X.Y (epoch가 있는 버전 식별자)

명시적인 epoch가 주어지지 않으면 암시적인 epoch는 0입니다. 대부분의 버전 식별자는 epoch를 포함하지 않습니다. 명시적인 epoch는 프로젝트가 버전 번호 지정 방식을 변경하여 일반적인 버전 정렬 규칙이 잘못된 결과를 제공하는 경우에만 필요합니다.

정규화 (Normalization)

기존 버전과의 더 나은 호환성을 유지하기 위해 버전을 파싱할 때 고려해야 할 여러 “대체” 구문이 있습니다. 이러한 구문은 버전을 파싱할 때 고려되어야 하지만, 위에서 정의된 표준 구문으로 “정규화”되어야 합니다.

  • 대소문자 구분 (Case sensitivity): 모든 ASCII 문자는 버전 내에서 대소문자를 구분하지 않고 해석되어야 하며, 표준 형식은 소문자입니다. (예: 1.1RC11.1rc1로 정규화됩니다.)
  • 정수 정규화 (Integer Normalization): 모든 정수는 int() 내장 함수를 통해 해석되며 출력의 문자열 형식으로 정규화됩니다. (예: 000으로 정규화됩니다.)
  • 프리-릴리스 구분자 (Pre-release separators): 프리-릴리스는 릴리스 세그먼트와 프리-릴리스 세그먼트 사이에 . , - 또는 _ 구분자를 허용합니다. 표준 형식은 구분자가 없는 것입니다.
  • 프리-릴리스 철자 (Pre-release spelling): 프리-릴리스는 a, b, rc에 대해 alpha, beta, c, pre, preview와 같은 추가 철자를 허용합니다.
  • 암시적 프리-릴리스 번호 (Implicit pre-release number): 프리-릴리스는 숫자를 생략할 수 있으며, 이 경우 암시적으로 0으로 가정됩니다.
  • 포스트-릴리스 구분자 (Post release separators): 포스트-릴리스는 . , - 또는 _ 구분자를 허용하며 구분자를 모두 생략하는 것도 허용합니다. 표준 형식은 . 구분자를 사용하는 것입니다.
  • 포스트-릴리스 철자 (Post release spelling): 포스트-릴리스는 revr과 같은 추가 철자를 허용합니다.
  • 암시적 포스트-릴리스 번호 (Implicit post release number): 포스트-릴리스는 숫자를 생략할 수 있으며, 이 경우 암시적으로 0으로 가정됩니다.
  • 암시적 포스트-릴리스 (Implicit post releases): 포스트-릴리스는 포스트 식별자를 모두 생략할 수 있습니다. 이 형식을 사용할 때 구분자는 반드시 -여야 하며 다른 형식은 허용되지 않습니다.
  • 개발 릴리스 구분자 (Development release separators): 개발 릴리스는 . , - 또는 _ 구분자를 허용하며 구분자를 모두 생략하는 것도 허용합니다. 표준 형식은 . 구분자를 사용하는 것입니다.
  • 암시적 개발 릴리스 번호 (Implicit development release number): 개발 릴리스는 숫자를 생략할 수 있으며, 이 경우 암시적으로 0으로 가정됩니다.
  • 로컬 버전 세그먼트 (Local version segments): 로컬 버전에서는 세그먼트 구분자로 . 외에 -_의 사용도 허용됩니다. 표준 형식은 . 문자를 사용하는 것입니다.
  • 선행 v 문자 (Preceding v character): 일반적인 버전 표기인 v1.0을 지원하기 위해 버전 앞에 단일 리터럴 v 문자가 올 수 있습니다. 이 문자는 모든 목적을 위해 무시되어야 하며, 버전의 모든 정규화된 형식에서 생략되어야 합니다.
  • 선행 및 후행 공백 (Leading and Trailing Whitespace): 선행 및 후행 공백은 묵시적으로 무시되고 버전의 모든 정규화된 형식에서 제거되어야 합니다.

호환 버전 체계 예시 (Examples of compliant version schemes)

  • 간단한 “major.minor” 버전 관리: 0.1, 0.2, 0.3, 1.0, 1.1
  • 간단한 “major.minor.micro” 버전 관리: 1.1.0, 1.1.1, 1.1.2, 1.2.0
  • 알파, 베타, 후보 프리-릴리스를 포함하는 “major.minor” 버전 관리: 0.9, 1.0a1, 1.0a2, 1.0b1, 1.0rc1, 1.0, 1.1a1

버전 지정자 (Version specifiers)

버전 지정자는 쉼표로 구분된 일련의 버전 절로 구성됩니다. 예를 들어:

~= 0.9, >= 1.0, != 1.3.4.*, < 2.0

비교 연산자는 버전 절의 종류를 결정합니다.

  • ~= : 호환 릴리스 절 (Compatible release clause)
  • == : 버전 일치 절 (Version matching clause)
  • != : 버전 제외 절 (Version exclusion clause)
  • <=, >= : 포괄적 순서 비교 절 (Inclusive ordered comparison clause)
  • <, > : 배타적 순서 비교 절 (Exclusive ordered comparison clause)
  • === : 임의 동등성 절 (Arbitrary equality clause)

쉼표(,)는 논리 and 연산자와 같습니다. 후보 버전은 지정자 전체와 일치하기 위해 모든 주어진 버전 절과 일치해야 합니다.

호환 릴리스 (~=) (Compatible release)

호환 릴리스 절은 호환 릴리스 연산자 ~=와 버전 식별자로 구성됩니다. 이는 지정된 버전과 호환될 것으로 예상되는 모든 후보 버전과 일치합니다.

예를 들어, ~= 2.22.2 이상이지만 3.0 미만인 버전을 의미합니다.

버전 일치 (==) (Version matching)

버전 일치 절은 버전 일치 연산자 ==와 버전 식별자를 포함합니다. 기본적으로 버전 일치 연산자는 엄격한 동등성 비교를 기반으로 합니다.

== 1.1.*와 같이 후행 .*를 추가하여 접두사 일치를 요청할 수 있습니다.

버전 제외 (!=) (Version exclusion)

버전 제외 절은 버전 제외 연산자 !=와 버전 식별자를 포함합니다. 허용되는 버전 식별자와 비교 의미론은 버전 일치 연산자와 동일하지만, 일치의 의미가 반전됩니다.

프리-릴리스 처리 (Handling of pre-releases)

개발 릴리스를 포함한 모든 종류의 프리-릴리스는 다음 경우를 제외하고 모든 버전 지정자에서 묵시적으로 제외됩니다.

  • 시스템에 이미 존재하는 경우
  • 사용자가 명시적으로 요청한 경우
  • 버전 지정자를 충족하는 유일한 사용 가능한 버전이 프리-릴리스인 경우

의존성 해결 도구는 기본적으로 다음을 수행해야 합니다.

  • 모든 버전 지정자에 대해 이미 설치된 프리-릴리스를 허용합니다.
  • 버전 지정자를 충족하는 최종 또는 포스트 릴리스가 없는 버전 지정자에 대해 원격으로 사용 가능한 프리-릴리스를 허용합니다.
  • 다른 모든 프리-릴리스는 고려 대상에서 제외합니다.

직접 참조 (Direct references)

일부 자동화된 도구는 일반 버전 지정자의 대안으로 직접 참조 사용을 허용할 수 있습니다. 직접 참조는 지정자 @와 명시적인 URL로 구성됩니다.

예를 들어, 로컬 소스 아카이브는 직접 참조될 수 있습니다. pip @ file:///localbuilds/pip-1.3.1.zip

모든 직접 참조는 보안 전송 메커니즘(예: https)을 지정하고, 확인을 위해 URL에 예상 해시 값을 포함해야 합니다.

버전 관리 명세 업데이트 (Updating the versioning specification)

버전 관리 명세는 새로운 PEP 또는 메타데이터 버전 변경 없이 설명을 통해 업데이트될 수 있습니다. 버전 식별 및 비교 구문 및 의미론에 영향을 미치는 모든 기술적 변경은 새로운 PEP에서 정의될 업데이트된 버전 관리 체계를 필요로 합니다.

PEP 386과의 차이점 요약 (Summary of differences from PEP 386)

  • 버전 지정자에 대한 설명이 버전 관리 PEP로 이동되었습니다.
  • 리소스에 대한 직접 참조를 위한 표준 표기법으로 “직접 참조(direct reference)” 개념이 추가되었습니다.
  • 시스템 통합자가 패치된 빌드를 업스트림 도구에서 지원되는 방식으로 표시하고, 바이너리 배포판의 버전에 빌드 태그를 통합할 수 있도록 “로컬 버전 식별자(local version identifier)” 및 “로컬 버전 레이블(local version label)” 개념이 추가되었습니다.
  • “호환 릴리스(compatible release)” 절이 추가되었습니다.
  • 접두사 기반 버전 일치를 위한 후행 와일드카드 구문 및 제외가 추가되었습니다.
  • .devN 접미사의 최상위 정렬 위치가 변경되었습니다.
  • 단일 값 버전 번호가 허용되었습니다.
  • 선행 또는 후행 공백의 명시적인 제외가 이루어졌습니다.
  • 날짜 기반 버전에 대한 명시적인 지원이 이루어졌습니다.
  • PyPI의 기존 버전 메타데이터와의 호환성을 향상시키기 위한 명시적인 정규화 규칙이 추가되었습니다.
  • 프리-릴리스는 이미 존재하거나 의존성을 충족하기 위해 필요한 경우가 아니면 묵시적으로 제외됩니다.
  • 포스트 릴리스는 한정되지 않은 릴리스와 동일하게 처리됩니다.
  • 메타데이터 버전 간의 순서 지정 및 의존성이 논의되었습니다.
  • c에서 rc를 선호하도록 전환되었습니다.

부록 B: 정규 표현식을 사용한 버전 문자열 파싱 (Appendix B : Parsing version strings with regular expressions)

공개 버전 식별자 섹션에서 언급했듯이, 게시된 버전 식별자는 표준 형식을 사용해야 합니다. 이 섹션에서는 버전이 이미 해당 형식인지 테스트하는 데 사용할 수 있는 정규 표현식과, 그렇지 않은 경우 후속 정규화를 위해 다양한 구성 요소를 추출하는 데 사용할 수 있는 정규 표현식을 제공합니다.

버전 식별자가 표준 형식인지 테스트하는 함수 예시는 다음과 같습니다.

import re

def is_canonical(version):
    return re.match(r'^([1-9][0-9]*!)?(0|[1-9][0-9]*)(\.(0|[1-9][0-9]*))*((a|b|rc)(0|[1-9][0-9]*))?(\.post(0|[1-9][0-9]*))?(\.dev(0|[1-9][0-9]*))?$', version) is not None

버전 식별자의 구성 요소를 추출하기 위해 packaging 프로젝트에서 정의한 다음 정규 표현식을 사용할 수 있습니다.

VERSION_PATTERN = r"""
    v?
    (?:
        (?:(?P<epoch>[0-9]+)!)?             # epoch
        (?P<release>[0-9]+(?:\.[0-9]+)*)    # release segment
        (?P<pre>                            # pre-release
            [-_\.]?
            (?P<pre_l>alpha|a|beta|b|preview|pre|c|rc)
            [-_\.]?
            (?P<pre_n>[0-9]+)?
        )?
        (?P<post>                           # post release
            (?:-(?P<post_n1>[0-9]+))
            |
            (?:
                [-_\.]?
                (?P<post_l>post|rev|r)
                [-_\.]?
                (?P<post_n2>[0-9]+)?
            )
        )?
        (?P<dev>                            # dev release
            [-_\.]?
            (?P<dev_l>dev)
            [-_\.]?
            (?P<dev_n>[0-9]+)?
        )?
    )
    (?:\+(?P<local>[a-z0-9]+(?:[-_\.][a-z0-9]+)*))? # local version
"""
_regex = re.compile(
    r"^\s*" + VERSION_PATTERN + r"\s*$",
    re.VERBOSE | re.IGNORECASE,
)

⚠️ 알림: 이 문서는 AI를 활용하여 번역되었으며, 기술적 정확성을 보장하지 않습니다. 정확한 내용은 반드시 원문을 확인하시기 바랍니다.

Comments