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

Python 개선 제안 한국어 번역

PEP 440 – 버전 식별 및 의존성 명세

Author:
Alyssa Coghlan <ncoghlan at gmail.com>, Donald Stufft <donald at stufft.io>
BDFL-Delegate:
Alyssa Coghlan <ncoghlan at gmail.com>
Discussions-To:
Distutils-SIG list
Status:
Final
Type:
Standards Track
Topic:
Packaging
Created:
18-Mar-2013
Post-History:
30-Mar-2013, 27-May-2013, 20-Jun-2013, 21-Dec-2013, 28-Jan-2014, 08-Aug-2014, 22-Aug-2014
Replaces:
386
Resolution:
Distutils-SIG message

Table of Contents

번역·라이선스 안내

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

Important

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

×

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

초록

이 PEP는 Python 소프트웨어 배포판의 버전을 식별하고 특정 버전에 대한 의존성을 선언하는 체계를 설명합니다.

이 문서는 PEP 345 및 PEP 386에 설명된, 버전 관리 방식을 표준화하려던 이전 시도의 여러 한계를 다룹니다.

정의

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

“프로젝트”는 통합에 사용할 수 있도록 제공되는 소프트웨어 구성 요소입니다. 프로젝트에는 Python 라이브러리, 프레임워크, 스크립트, 플러그인, 애플리케이션, 데이터나 기타 리소스의 모음, 그리고 이들의 다양한 조합이 포함됩니다. 공개 Python 프로젝트는 일반적으로 Python Package Index에 등록됩니다.

“릴리스”는 고유하게 식별되는 프로젝트의 스냅숏입니다.

“배포판”은 릴리스를 게시하고 배포하는 데 사용되는 패키징된 파일입니다.

“빌드 도구”는 개발 시스템에서 실행되어 소스 및 바이너리 배포 아카이브를 생성하도록 만들어진 자동화 도구입니다. 빌드 도구는 미리 빌드된 바이너리 아카이브가 아닌 sdist로 배포되는 소프트웨어를 빌드하기 위해 통합 도구에 의해 호출될 수도 있습니다.

“색인 서버”는 버전 및 의존성 메타데이터를 게시하고 허용되는 메타데이터에 제약을 두는 활성 배포 레지스트리입니다.

“게시 도구”는 개발 시스템에서 실행되어 소스 및 바이너리 배포 아카이브를 색인 서버에 업로드하도록 만들어진 자동화 도구입니다.

“설치 도구”는 배포 대상에서 실행되도록 특별히 만들어진 통합 도구로, 색인 서버나 기타 지정된 위치에서 소스 및 바이너리 배포 아카이브를 가져와 대상 시스템에 배포합니다.

“자동화 도구”는 빌드 도구, 색인 서버, 게시 도구, 통합 도구, 그리고 배포판의 버전 및 의존성 메타데이터를 생성하거나 사용하는 기타 모든 소프트웨어를 통칭하는 용어입니다.

버전 체계

배포판은 정의된 모든 버전 비교 연산을 지원하는 공개 버전 식별자로 식별됩니다

버전 체계는 특정 배포 아카이브가 제공하는 배포판 버전을 설명하는 데에도, 소프트웨어를 빌드하거나 실행하는 데 필요한 의존성의 버전에 제약을 두는 데에도 사용됩니다.

공개 버전 식별자

정규 공개 버전 식별자는 반드시 다음 체계를 따라야 합니다(MUST):

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

공개 버전 식별자는 앞뒤에 공백을 포함해서는 안 됩니다(MUST NOT).

공개 버전 식별자는 주어진 배포판 내에서 반드시 고유해야 합니다(MUST).

설치 도구는 이 체계를 따르지 않는 공개 버전을 무시해야 하지만(SHOULD), 아래에 명시된 정규화도 반드시 포함해야 합니다(MUST). 설치 도구는 규격에 맞지 않거나 모호한 버전이 감지되면 사용자에게 경고할 수 있습니다(MAY).

정규 형식을 엄격하게 준수하는지 검사하는 정규 표현식과, 이후 정규화가 필요할 수 있는 입력까지 허용하는 더 관대한 정규 표현식을 제공하는 Appendix B : Parsing version strings with regular expressions도 참고하십시오.

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

  • 에포크 세그먼트: N!
  • 릴리스 세그먼트: N(.N)*
  • 사전 릴리스 세그먼트: {a|b|rc}N
  • 사후 릴리스 세그먼트: .postN
  • 개발 릴리스 세그먼트: .devN

모든 릴리스는 다음 절들에서 정의하는 “최종 릴리스”, “사전 릴리스”, “사후 릴리스”, “개발 릴리스” 중 하나입니다.

모든 숫자 구성 요소는 반드시 ASCII 숫자의 나열로 표현되는 음이 아닌 정수여야 합니다.

모든 숫자 구성 요소는 반드시 텍스트 문자열이 아닌 숫자 값에 따라 해석되고 정렬되어야 합니다.

모든 숫자 구성 요소는 0이어도 됩니다. 아래에서 릴리스 세그먼트에 대해 설명하는 경우를 제외하면, 값이 0인 숫자 구성 요소는 버전 순서에서 항상 가능한 가장 낮은 값이라는 점 외에는 특별한 의미가 없습니다.

Note

기존의 공개 및 비공개 Python 프로젝트 전반에 걸친 다양한 버전 관리 관행을 더 잘 수용하기 위해, 이 체계에서는 읽기 어려운 일부 버전 식별자도 허용합니다.

따라서 이 PEP에서 기술적으로 허용하는 버전 관리 관행 중 일부는 새 프로젝트에서 사용하지 않을 것을 강력히 권장합니다. 이러한 경우에 해당하는 관련 세부 사항은 다음 절들에 명시되어 있습니다.

로컬 버전 식별자

로컬 버전 식별자는 반드시 다음 체계를 따라야 합니다:

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

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

로컬 버전 식별자는 업스트림 프로젝트의 패치된 버전 중 API(그리고 해당하는 경우 ABI)가 완전히 호환되는 버전을 나타내는 데 사용합니다. 예를 들어, 새 업스트림 릴리스로 업그레이드하는 것이 애플리케이션이나 (Linux 배포판과 같은) 기타 통합 시스템에 지나치게 큰 지장을 줄 때, 애플리케이션 개발자와 시스템 통합자가 백포트한 특정 버그 수정을 적용하여 이러한 버전을 만들 수 있습니다.

로컬 버전 레이블을 포함하면 업스트림 릴리스와 다운스트림 통합자가 수정했을 수 있는 재빌드를 구별할 수 있습니다. 로컬 버전 식별자를 사용해도 릴리스의 종류는 바뀌지 않지만, 소스 배포판에 적용하면 해당 배포판이 대응하는 업스트림 릴리스와 정확히 같은 코드를 담고 있지 않을 수 있음을 나타냅니다.

로컬 버전 식별자를 파일 이름과 URL의 일부로 쉽게 포함할 수 있도록 하고 16진수 해시 표현에서 형식이 일관되지 않는 문제를 피하기 위해, 로컬 버전 레이블은 반드시 다음과 같이 허용된 문자로만 구성되어야 합니다:

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

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

로컬 버전을 비교하고 정렬할 때는 (.으로 구분된) 로컬 버전의 각 세그먼트를 따로 고려합니다. 세그먼트가 전부 ASCII 숫자로 이루어져 있으면 비교할 때 그 세그먼트를 정수로 간주해야 하며, 세그먼트에 ASCII 문자가 하나라도 있으면 그 세그먼트는 대소문자를 구분하지 않고 사전순으로 비교합니다. 숫자 세그먼트와 사전순 세그먼트를 비교할 때는 항상 숫자 세그먼트가 사전순 세그먼트보다 큰 것으로 비교됩니다. 또한 짧은 로컬 버전의 세그먼트들이 긴 로컬 버전의 앞부분 세그먼트들과 정확히 일치하는 한, 세그먼트가 더 많은 로컬 버전은 항상 세그먼트가 더 적은 로컬 버전보다 큰 것으로 비교됩니다.

“업스트림 프로젝트”는 자신의 공개 버전을 직접 정의하는 프로젝트입니다. “다운스트림 프로젝트”는 업스트림 프로젝트를 추적하고 재배포하는 프로젝트이며, 업스트림 프로젝트의 이후 버전에서 보안 수정과 버그 수정을 백포트할 수도 있습니다.

업스트림 프로젝트를 공개 색인 서버에 게시할 때는 로컬 버전 식별자를 사용하지 않아야 하지만, 프로젝트 소스에서 직접 만든 비공개 빌드를 식별하는 데에는 사용해도 됩니다. 다운스트림 프로젝트가 공개 버전 식별자로 식별되는 업스트림 프로젝트 버전과 API가 호환되지만 (버그 수정과 같은) 추가 변경 사항을 담은 버전을 릴리스할 때는 로컬 버전 식별자를 사용해야 합니다. Python 패키지 색인은 오직 업스트림 프로젝트의 색인과 호스팅만을 위한 것이므로, 로컬 버전 식별자의 사용을 절대 허용해서는 안 됩니다.

로컬 버전 식별자를 사용하는 소스 배포판은 (PEP 459에서 정의한) python.integrator 확장 메타데이터를 제공해야 합니다.

최종 릴리스

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

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

N(.N)*

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

릴리스 세그먼트를 비교하고 정렬할 때는 릴리스 세그먼트의 각 구성 요소의 숫자 값을 차례로 고려합니다. 구성 요소 수가 서로 다른 릴리스 세그먼트를 비교할 때는 더 짧은 세그먼트에 필요한 만큼 0을 추가로 채웁니다.

이 체계에서는 첫 번째 구성 요소 뒤에 추가 구성 요소를 몇 개든 둘 수 있지만, 가장 흔한 형태는 구성 요소 두 개(“major.minor”) 또는 세 개(“major.minor.micro”)를 사용하는 것입니다.

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

0.9
0.9.1
0.9.2
...
0.9.10
0.9.11
1.0
1.0.1
1.1
2.0
2.0.1
...

릴리스 시리즈란 공통 접두사로 시작하는 최종 릴리스 번호의 집합을 말합니다. 예를 들어, 3.3.1, 3.3.5, 3.3.9.45는 모두 3.3 릴리스 시리즈에 속합니다.

Note

X.Y와 X.Y.0은 서로 다른 릴리스 번호로 간주하지 않습니다. 릴리스 세그먼트 비교 규칙에 따라 구성 요소가 세 개인 릴리스 세그먼트와 비교할 때 구성 요소가 두 개인 형태가 암묵적으로 X.Y.0으로 확장되기 때문입니다.

날짜 기반 릴리스 세그먼트도 허용됩니다. 릴리스 연도와 월을 사용하는 날짜 기반 릴리스 체계의 예는 다음과 같습니다.:

2012.4
2012.7
2012.10
2013.1
2013.6
...

사전 릴리스

일부 프로젝트는 최종 릴리스 전에 사용자가 테스트할 수 있도록 “알파, 베타, 릴리스 후보” 사전 릴리스 주기를 사용합니다.

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

X.YaN   # Alpha release
X.YbN   # Beta release
X.YrcN  # Release Candidate
X.Y     # Final release

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

사전 릴리스 세그먼트는 사전 릴리스 단계를 나타내는 알파벳 식별자와 음이 아닌 정수 값으로 구성됩니다. 특정 릴리스의 사전 릴리스는 먼저 단계(알파, 베타, 릴리스 후보)에 따라 정렬되고, 그다음 해당 단계 안의 숫자 구성 요소에 따라 정렬됩니다.

설치 도구는 기존 레거시 배포판 일부를 처리하기 위해 같은 릴리스 세그먼트에 대해 c 릴리스와 rc 릴리스를 모두 받아들일 수 있습니다(MAY).

설치 도구는 c 버전을 rc 버전과 동등한 것으로 해석해야 합니다(SHOULD). 즉, c1은 rc1과 같은 버전을 나타냅니다.

빌드 도구, 게시 도구, 색인 서버는 같은 릴리스 세그먼트에 대해 rc 릴리스와 c 릴리스를 모두 만드는 것을 허용하지 않아야 합니다(SHOULD).

사후 릴리스

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

프로젝트 개발 주기의 일부로 사용하는 경우, 이러한 사후 릴리스는 버전 식별자에 사후 릴리스 세그먼트를 포함하여 나타냅니다:

X.Y.postN    # Post-release

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

사후 릴리스 세그먼트는 문자열 .post와 그 뒤에 오는 음이 아닌 정수 값으로 구성됩니다. 사후 릴리스는 숫자 구성 요소에 따라 정렬되며, 해당 릴리스 바로 뒤에 오고 그 이후의 어떤 릴리스보다도 앞에 옵니다.

Note

실제 버그 수정을 포함하는 유지보수 릴리스를 게시하기 위해 사후 릴리스를 사용하는 것은 강력히 권장하지 않습니다. 일반적으로는 더 긴 릴리스 번호를 사용하고 유지보수 릴리스마다 마지막 구성 요소를 증가시키는 것이 좋습니다.

사후 릴리스는 사전 릴리스에도 허용됩니다:

X.YaN.postM   # Post-release of an alpha release
X.YbN.postM   # Post-release of a beta release
X.YrcN.postM  # Post-release of a release candidate

Note

사전 릴리스의 사후 릴리스를 만들면 사람이 버전 식별자를 해석하기 어려워지므로 강력히 권장하지 않습니다. 일반적으로는 숫자 구성 요소를 증가시켜 새 사전 릴리스를 만드는 편이 훨씬 명확합니다.

개발 릴리스

일부 프로젝트는 정기적으로 개발 릴리스를 만들며, 시스템 패키저(특히 Linux 배포판의 패키저)는 이후의 프로젝트 릴리스와 충돌하지 않는 초기 릴리스를 소스 관리 시스템에서 직접 만들고자 할 수 있습니다.

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

X.Y.devN    # Developmental release

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

개발 릴리스 세그먼트는 .dev 문자열과 그 뒤에 오는 음이 아닌 정수 값으로 구성됩니다. 개발 릴리스는 숫자 구성 요소에 따라 정렬되며, 대응하는 릴리스의 바로 앞(그리고 같은 릴리스 세그먼트를 가진 모든 사전 릴리스의 앞)에, 그리고 이전의 모든 릴리스(모든 사후 릴리스 포함)의 뒤에 위치합니다.

사전 릴리스와 사후 릴리스에 대해서도 개발 릴리스가 허용됩니다:

X.YaN.devM       # Developmental release of an alpha release
X.YbN.devM       # Developmental release of a beta release
X.YrcN.devM      # Developmental release of a release candidate
X.Y.postN.devM   # Developmental release of a post-release

Note

지속적 통합 용도로는 유용할 수 있지만, 사전 릴리스의 개발 릴리스를 범용 공개 색인 서버에 게시하면 사람이 버전 식별자를 해석하기 어려워지므로 강력히 권장하지 않습니다. 그러한 릴리스를 게시해야 한다면, 대신 숫자 구성 요소를 증가시켜 새 사전 릴리스를 만드는 편이 훨씬 명확합니다.

사후 릴리스의 개발 릴리스 역시 강력히 권장하지 않지만, 코드 변경을 포함할 수 있는 완전한 유지보수 릴리스에 사후 릴리스 표기법을 사용하는 프로젝트에는 적절할 수 있습니다.

버전 에포크

버전 식별자에 포함되는 경우, 에포크는 다른 모든 구성 요소보다 앞에 나타나며 느낌표로 릴리스 세그먼트와 구분됩니다:

E!X.Y  # Version identifier with epoch

명시적인 에포크가 주어지지 않으면 암묵적인 에포크는 0입니다.

명시적인 에포크는 프로젝트가 버전 번호를 처리하는 방식을 일반적인 버전 정렬 규칙으로는 잘못된 결과가 나오는 방식으로 변경하는 경우에만 필요하므로, 대부분의 버전 식별자에는 에포크가 포함되지 않습니다. 예를 들어, 프로젝트가 2014.04와 같은 날짜 기반 버전을 사용하다가 1.0과 같은 의미적 버전(semantic version)으로 전환하려는 경우, 일반적인 정렬 방식을 사용하면 새 릴리스가 날짜 기반 릴리스보다 오래된 것으로 식별됩니다.:

1.0
1.1
2.0
2013.10
2014.04

그러나 명시적인 에포크를 지정하면, 나중 에포크의 모든 버전은 이전 에포크의 버전 뒤에 정렬되므로 정렬 순서를 적절하게 바꿀 수 있습니다:

2013.10
2014.04
1!1.0
1!1.1
1!2.0

정규화

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

대소문자 구분

버전 내의 모든 ASCII 문자는 대소문자를 구분하지 않고 해석해야 하며, 정규 형식은 소문자입니다. 이에 따라 1.1RC1과 같은 버전이 허용되며, 이는 1.1rc1로 정규화됩니다.

정수 정규화

모든 정수는 int() 내장 함수를 통해 해석되며, 그 출력의 문자열 형식으로 정규화됩니다. 즉, 00이라는 정수 버전은 0으로 정규화되고, 09000은 9000으로 정규화됩니다. 이는 1.0+foo0100과 같은 로컬 버전의 영숫자 세그먼트 내부에 있는 정수에는 해당하지 않으며, 이러한 버전은 이미 정규화된 형식입니다.

사전 릴리스 구분자

사전 릴리스는 릴리스 세그먼트와 사전 릴리스 세그먼트 사이에 ., -, _ 구분자를 허용해야 합니다. 이에 대한 정규 형식은 구분자가 없는 형식입니다. 이에 따라 1.1.a1이나 1.1-a1 같은 버전이 허용되며, 이들은 1.1a1로 정규화됩니다. 또한 사전 릴리스 표지와 숫자 사이에도 구분자를 사용할 수 있도록 허용해야 합니다. 이에 따라 1.0a.1 같은 버전이 허용되며, 이는 1.0a1로 정규화됩니다.

사전 릴리스 철자

사전 릴리스는 a, b, rc, rc, rc에 대해 각각 alpha, beta, c, pre, preview라는 추가 철자를 허용합니다. 이에 따라 1.1alpha1, 1.1beta2, 1.1c3 같은 버전이 허용되며, 이들은 각각 1.1a1, 1.1b2, 1.1rc3으로 정규화됩니다. 모든 경우에 추가 철자는 해당 정규 형식과 동등한 것으로 간주해야 합니다.

암묵적 사전 릴리스 번호

사전 릴리스는 숫자를 생략하는 것을 허용하며, 이 경우 숫자는 암묵적으로 0으로 간주됩니다. 이에 대한 정규 형식은 0을 명시적으로 포함하는 것입니다. 이에 따라 1.2a 같은 버전이 허용되며, 이는 1.2a0으로 정규화됩니다.

사후 릴리스 구분자

사후 릴리스는 ., -, _ 구분자를 허용하며, 구분자를 완전히 생략하는 것도 허용합니다. 이에 대한 정규 형식은 . 구분자를 사용하는 형식입니다. 이에 따라 1.2-post2나 1.2post2 같은 버전이 허용되며, 이들은 1.2.post2로 정규화됩니다. 사전 릴리스 구분자와 마찬가지로, 사후 릴리스 표지와 숫자 사이에도 선택적으로 구분자를 사용할 수 있습니다. 이에 따라 1.2.post-2 같은 버전이 허용되며, 이는 1.2.post2로 정규화됩니다.

사후 릴리스 철자

사후 릴리스는 rev와 r이라는 추가 철자를 허용합니다. 이에 따라 1.0-r4 같은 버전이 허용되며, 이는 1.0.post4로 정규화됩니다. 사전 릴리스와 마찬가지로, 추가 철자는 해당 정규 형식과 동등한 것으로 간주해야 합니다.

암묵적 사후 릴리스 번호

사후 릴리스는 숫자를 생략하는 것을 허용하며, 이 경우 숫자는 암묵적으로 0으로 간주됩니다. 이에 대한 정규 형식은 0을 명시적으로 포함하는 것입니다. 이에 따라 1.2.post 같은 버전이 허용되며, 이는 1.2.post0으로 정규화됩니다.

암묵적 사후 릴리스

사후 릴리스에서는 post 표시자를 완전히 생략할 수 있습니다. 이 형식을 사용할 때 구분자는 반드시 - 문자여야 하며, 다른 형식은 허용되지 않습니다. 이를 통해 1.0-1 같은 버전을 1.0.post1로 정규화할 수 있습니다. 이 정규화는 암묵적 사후 릴리스 번호 규칙과 함께 사용해서는 절대 안 됩니다. 다시 말해, 1.0-은 유효한 버전이 아니며 1.0.post0으로 정규화되지도 않습니다.

개발 릴리스 구분자

개발 릴리스에서는 ., -, _ 구분자를 쓸 수 있으며, 구분자를 완전히 생략할 수도 있습니다. 이때 정규 형식은 . 구분자를 사용하는 것입니다. 이를 통해 1.2-dev2나 1.2dev2 같은 버전을 쓸 수 있으며, 이들은 1.2.dev2로 정규화됩니다.

암묵적 개발 릴리스 번호

개발 릴리스에서는 숫자를 생략할 수 있으며, 이 경우 숫자는 암묵적으로 0으로 간주됩니다. 이때 정규 형식은 0을 명시적으로 포함하는 것입니다. 이를 통해 1.2.dev 같은 버전을 쓸 수 있으며, 이는 1.2.dev0으로 정규화됩니다.

로컬 버전 세그먼트

로컬 버전에서는 세그먼트 구분자로 . 문자를 사용하는 것 외에 - 문자와 _ 문자를 사용하는 것도 허용됩니다. 정규 형식은 . 문자를 사용하는 것입니다. 이를 통해 1.0+ubuntu-1 같은 버전을 1.0+ubuntu.1로 정규화할 수 있습니다.

앞에 붙는 v 문자

흔히 쓰이는 v1.0 버전 표기법을 지원하기 위해, 버전 앞에 리터럴 v 문자 하나를 붙일 수 있습니다. 이 문자는 어떤 목적에서든 반드시 무시되어야 하며, 버전의 모든 정규화된 형식에서 생략되어야 합니다. 같은 버전이라면 v가 있든 없든 동등한 것으로 간주됩니다.

앞뒤 공백

앞뒤 공백은 아무런 알림 없이 무시되어야 하며, 버전의 모든 정규화된 형식에서 제거되어야 합니다. 여기에는 " ", \t, \n, \r, \f, \v가 포함됩니다. 이를 통해 실수로 들어간 공백을 적절히 처리할 수 있습니다. 예를 들어 1.0\n 같은 버전은 1.0으로 정규화됩니다.

규격을 준수하는 버전 체계의 예

표준 버전 체계는 공개 및 비공개 Python 프로젝트 전반에서 쓰이는 다양한 버전 식별 방식을 포괄하도록 설계되었습니다. 위의 규칙은 규격을 준수하는 모든 도구가 버전을 일관되게 정렬하도록 보장하지만, 실제로 한 프로젝트가 이 체계가 제공하는 유연성을 모두 활용하려고 하면 사람 사용자가 버전 간의 상대적 순서를 파악하기 어려운 상황이 생깁니다.

다음 예는 프로젝트가 릴리스를 식별하는 데 선택할 수 있는 여러 접근 방식 가운데 일부를 보여 줍니다. 이 방식들을 따르더라도 사람 사용자와 자동화 도구 모두 “최신 릴리스”와 “최신 안정 릴리스”를 쉽게 판별할 수 있습니다.

단순한 “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
...

개발 릴리스, 릴리스 후보, 사소한 수정을 위한 사후 릴리스를 포함하는 “major.minor” 버전 관리:

0.9
1.0.dev1
1.0.dev2
1.0.dev3
1.0.dev4
1.0c1
1.0c2
1.0
1.0.post1
1.1.dev1
...

연도마다 0을 건너뛰고 1씩 증가하는 일련번호를 사용하는 날짜 기반 릴리스:

2012.1
2012.2
2012.3
...
2012.15
2013.1
2013.2
...

허용되는 접미사와 상대적 순서 요약

Note

이 절은 버전 관리 체계를 정하려는 Python 배포판 개발자보다는 배포판 메타데이터를 자동으로 처리하는 도구의 작성자를 주 대상으로 합니다.

버전 식별자의 에포크 세그먼트는 해당 에포크의 숫자 값에 따라 정렬해야 합니다(MUST). 에포크 세그먼트가 없으면 암묵적인 숫자 값은 0입니다.

버전 식별자의 릴리스 세그먼트는 정규화된 릴리스 세그먼트를 다음과 같이 파싱했을 때 Python의 튜플 정렬과 같은 순서로 정렬해야 합니다(MUST):

tuple(map(int, release_segment.split(".")))

비교 대상인 모든 릴리스 세그먼트는 필요에 따라 짧은 세그먼트를 0으로 채워 같은 길이로 변환해야 합니다(MUST).

숫자 릴리스(1.0, 2.7.3) 안에서는 다음 접미사가 허용되며, 표시된 순서대로 정렬해야 합니다(MUST):

.devN, aN, bN, rcN, <no suffix>, .postN

c는 의미상 rc와 동등한 것으로 간주되므로 rc인 것처럼 정렬해야 한다는 점에 유의하십시오. 도구는 같은 릴리스 세그먼트에서 c와 rc가 같은 N을 갖는 경우를 모호하다는 이유로 거부할 수 있으며(MAY), 그렇게 하더라도 이 PEP를 준수하는 것으로 간주됩니다.

알파(1.0a1), 베타(1.0b1), 릴리스 후보(1.0rc1, 1.0c1) 안에서는 다음 접미사가 허용되며, 표시된 순서대로 정렬해야 합니다(MUST):

.devN, <no suffix>, .postN

사후 릴리스(1.0.post1) 안에서는 다음 접미사가 허용되며, 표시된 순서대로 정렬해야 합니다(MUST):

.devN, <no suffix>

devN과 postN은 숫자 버전 바로 뒤에 쓰일 때에도(예: 1.0.dev456, 1.0.post1) 항상 앞에 점이 와야 한다는(MUST) 점에 유의하십시오.

같은 접두사를 공유하는 사전 릴리스, 사후 릴리스, 개발 릴리스 세그먼트 안에서는 숫자 구성 요소의 값에 따라 정렬해야 합니다(MUST).

다음 예시는 가능한 조합의 상당수를 다룹니다:

1.dev0
1.0.dev456
1.0a1
1.0a2.dev456
1.0a12.dev456
1.0a12
1.0b1.dev456
1.0b2
1.0b2.post345.dev456
1.0b2.post345
1.0rc1.dev456
1.0rc1
1.0
1.0+abc.5
1.0+abc.7
1.0+5
1.0.post456.dev34
1.0.post456
1.0.15
1.1.dev1

서로 다른 메타데이터 버전 간의 버전 순서

메타데이터 v1.0(PEP 241)과 메타데이터 v1.1(PEP 314)은 표준 버전 식별 체계나 순서 체계를 규정하지 않습니다. 그러나 메타데이터 v1.2(PEP 345)는 PEP 386에 정의된 체계를 분명히 규정합니다.

단순 설치 프로그램 API의 특성상, 설치 프로그램은 특정 배포가 어떤 메타데이터 버전을 사용했는지 알 수 없습니다. 또한 설치 프로그램은 어떤 버전을 설치할지 결정하기 위해 프로젝트의 모든 버전, 또는 가능한 한 많은 버전을 포함하며 합리적으로 우선순위가 매겨진 목록을 만들 수 있어야 했습니다. 이러한 요구 사항 때문에 프로젝트의 모든 버전에 사용할 하나의 파싱 방식으로 표준화해야 합니다.

이러한 이유로 이 PEP는 모든 메타데이터 버전에 사용해야 하며(MUST), 메타데이터 v1.2에 대해서도 PEP 386을 대체합니다. 도구는 이 PEP의 규칙으로 파싱할 수 없는 버전을 무시해야 하지만(SHOULD), 이 PEP를 준수하는 버전이 하나도 없는 경우에는 구현에서 정의한 버전 파싱 및 순서 체계로 대체할 수 있습니다(MAY).

배포판 사용자는 자신이 관리하는 비공개 패키지 색인에서 규격에 맞지 않는 버전을 명시적으로 제거하고 싶을 수 있습니다.

다른 버전 체계와의 호환성

일부 프로젝트는 이 PEP에 정의된 공개 버전 체계를 준수하려면 변환이 필요한 버전 체계를 사용하기로 할 수 있습니다. 이런 경우 프로젝트 고유의 버전은 메타데이터에 저장하고, 변환된 공개 버전은 버전 필드에 게시할 수 있습니다.

이렇게 하면 자동화된 배포 도구는 게시된 릴리스의 순서를 일관되고 올바르게 매길 수 있으며, 개발자는 여전히 자신의 프로젝트에 원하는 내부 버전 관리 체계를 사용할 수 있습니다.

의미적 버전 관리(Semantic versioning)

Semantic versioning은 릴리스 번호를 이루는 각 요소의 의미를 이 PEP보다 더 엄격하게 규정하는, 널리 쓰이는 버전 식별 체계입니다. 프로젝트가 의미적 버전 관리의 세부 사항을 따르지 않기로 하더라도, 이 방식은 다른 배포에 의존할 때나 다른 이들이 의존하는 배포를 게시할 때 발생할 수 있는 많은 문제를 다루므로 이해해 둘 가치가 있습니다.

의미적 버전 관리의 “Major.Minor.Patch”(이 PEP에서는 “major.minor.micro”로 설명함) 측면(2.0.0 명세의 1-8절)은 이 PEP에서 정의한 버전 체계와 완전히 호환되며, 이러한 측면을 따르는 것을 권장합니다.

하이픈(사전 릴리스 - 10절)이나 더하기 기호(빌드 - 11절)를 포함하는 의미적 버전은 이 PEP와 호환되지 않으며 공개 버전 필드에 허용되지 않습니다.

이러한 의미적 버전 관리 기반 소스 레이블을 호환되는 공개 버전으로 변환하는 한 가지 방법은 .devN 접미사를 사용하여 적절한 버전 순서를 지정하는 것입니다.

구체적인 빌드 정보는 로컬 버전 레이블에 포함할 수도 있습니다.

DVCS 기반 버전 레이블

많은 빌드 도구는 버전 식별자에 식별용 해시를 추가하기 위해 Git이나 Mercurial 같은 분산 버전 관리 시스템과 통합됩니다. 해시는 신뢰성 있게 정렬할 수 없으므로 이러한 버전은 공개 버전 필드에 허용되지 않습니다.

의미적 버전 관리와 마찬가지로, 공개 .devN 접미사를 사용하여 게시용 릴리스를 고유하게 식별할 수 있으며, 원래의 DVCS 기반 레이블은 프로젝트 메타데이터에 저장할 수 있습니다.

식별용 해시 정보는 로컬 버전 레이블에 포함할 수도 있습니다.

Olson 데이터베이스 버전 관리

pytz 프로젝트는 해당하는 Olson 시간대 데이터베이스의 버전 관리 체계를 그대로 물려받습니다. 즉, 연도 뒤에 그 연도 안에서의 데이터베이스 버전을 나타내는 소문자 한 글자가 붙습니다.

이는 <year>.<serial> 형태의 규격에 맞는 공개 버전 식별자로 변환할 수 있습니다. 여기서 serial은 0 또는 1(‘<year>a’ 릴리스의 경우)에서 시작하며, 해당 연도 내에서 데이터베이스가 갱신될 때마다 증가합니다.

다른 변환된 버전 식별자와 마찬가지로, 대응하는 Olson 데이터베이스 버전은 프로젝트 메타데이터에 기록할 수 있습니다.

버전 지정자

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

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

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

쉼표(“,”)는 논리 and 연산자와 동등합니다. 후보 버전이 지정자 전체와 일치하려면 주어진 모든 버전 절과 일치해야 합니다.

조건 연산자와 그 뒤에 오는 버전 식별자 사이의 공백은 선택 사항이며, 쉼표 주위의 공백도 마찬가지입니다.

여러 후보 버전이 버전 지정자와 일치하는 경우, 표준 Version scheme에서 정의하는 일관된 순서에 따라 결정되는 최신 버전을 우선해야 합니다(SHOULD). 사전 릴리스를 후보 버전으로 간주할지 여부는 Handling of pre-releases에서 설명하는 대로 처리해야 합니다(SHOULD).

아래에서 특별히 언급하는 경우를 제외하고, 버전 지정자에 로컬 버전 식별자를 허용해서는 안 되며(MUST NOT), 후보 버전이 주어진 버전 지정자와 일치하는지 확인할 때 로컬 버전 레이블은 완전히 무시해야 합니다(MUST).

호환 릴리스

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

지정된 버전 식별자는 Version scheme에 설명된 표준 형식이어야 합니다. 이 버전 지정자에서는 로컬 버전 식별자를 사용할 수 없습니다.

주어진 릴리스 식별자 V.N에 대해, 호환 릴리스 절은 다음 비교 절 쌍과 대략 동등합니다:

>= V.N, == V.*

이 연산자는 ~=1과 같이 세그먼트가 하나뿐인 버전 번호와 함께 사용해서는 절대 안 됩니다.

예를 들어, 다음 버전 절 그룹들은 서로 동등합니다:

~= 2.2
>= 2.2, == 2.*

~= 1.4.5
>= 1.4.5, == 1.4.*

사전 릴리스, 사후 릴리스 또는 개발 릴리스가 호환 릴리스 절에서 V.N.suffix로 지정된 경우, 필요한 접두사 일치를 결정할 때 접미사는 무시됩니다:

~= 2.2.post3
>= 2.2.post3, == 2.*

~= 1.4.5a4
>= 1.4.5a4, == 1.4.*

릴리스 세그먼트 비교의 0 채움 규칙에 따라, 버전 지정자에 0을 추가로 덧붙여 호환 릴리스 절에서 가정하는 상위 호환성의 정도를 조절할 수 있습니다:

~= 2.2.0
>= 2.2.0, == 2.2.*

~= 1.4.5.0
>= 1.4.5.0, == 1.4.5.*

버전 일치

버전 일치 절은 버전 일치 연산자 ==와 버전 식별자를 포함합니다.

지정된 버전 식별자는 Version scheme에 설명된 표준 형식이어야 하지만, 아래에서 설명하는 것처럼 공개 버전 식별자에는 끝에 .*를 붙일 수 있습니다.

기본적으로 버전 일치 연산자는 엄격한 동등 비교에 기반합니다. 즉, 지정된 버전은 요청된 버전과 정확히 같아야 합니다. 수행되는 유일한 치환은 릴리스 세그먼트들이 같은 길이로 비교되도록 릴리스 세그먼트를 0으로 채우는 것입니다.

엄격한 버전 일치가 적절한지 여부는 버전 지정자의 구체적인 사용 사례에 따라 달라집니다. 엄격한 버전 일치가 부적절하게 사용되는 경우, 자동화 도구는 최소한 경고를 내야 하며 이를 완전히 거부할 수도 있습니다.

버전 일치 절의 버전 식별자 끝에 .*를 덧붙여 엄격한 비교 대신 접두사 일치를 요청할 수 있습니다. 이는 버전 식별자가 해당 절과 일치하는지 여부를 판단할 때 뒤에 오는 추가 세그먼트가 무시된다는 뜻입니다. 지정된 버전이 릴리스 세그먼트만 포함하는 경우, 릴리스 세그먼트의 후행 구성 요소(또는 그것이 없다는 사실)도 무시됩니다.

예를 들어, 버전 1.1.post1이 주어지면 다음 절들은 표시된 대로 일치하거나 일치하지 않습니다:

== 1.1        # Not equal, so 1.1.post1 does not match clause
== 1.1.post1  # Equal, so 1.1.post1 matches clause
== 1.1.*      # Same prefix, so 1.1.post1 matches clause

접두사 일치에서는 사전 릴리스 세그먼트 앞에 .이 암묵적으로 있는 것으로 간주하므로, 버전 1.1a1이 주어지면 다음 절들은 표시된 대로 일치하거나 일치하지 않습니다:

== 1.1        # Not equal, so 1.1a1 does not match clause
== 1.1a1      # Equal, so 1.1a1 matches clause
== 1.1.*      # Same prefix, so 1.1a1 matches clause if pre-releases are requested

정확한 일치도 접두사 일치로 간주합니다(이 해석은 버전 식별자의 릴리스 세그먼트에 대한 일반적인 0 채움 규칙에 이미 함축되어 있습니다). 버전 1.1이 주어지면 다음 절들은 표시된 대로 일치하거나 일치하지 않습니다:

== 1.1        # Equal, so 1.1 matches clause
== 1.1.0      # Zero padding expands 1.1 to 1.1.0, so it matches clause
== 1.1.dev1   # Not equal (dev-release), so 1.1 does not match clause
== 1.1a1      # Not equal (pre-release), so 1.1 does not match clause
== 1.1.post1  # Not equal (post-release), so 1.1 does not match clause
== 1.1.*      # Same prefix, so 1.1 matches clause

1.0.dev1.* 또는 1.0+foo1.*처럼 개발 릴리스나 로컬 릴리스를 포함하는 접두사 일치는 유효하지 않습니다. 개발 릴리스 세그먼트는 있다면 항상 공개 버전의 마지막 세그먼트이고, 로컬 버전은 비교할 때 무시되므로, 접두사 일치에 둘 중 어느 것을 사용하든 아무런 의미가 없습니다.

공개된 배포판의 의존성을 정의할 때 (최소한 와일드카드 접미사 없이) ==를 사용하는 것은 보안 수정 사항의 배포를 크게 복잡하게 만들므로 강력히 권장하지 않습니다. 엄격한 버전 비교 연산자는 주로 공유 배포 색인을 사용하면서 반복 가능한 애플리케이션 배포를 위한 의존성을 정의할 때 사용하도록 만들어졌습니다.

지정된 버전 식별자가 공개 버전 식별자(로컬 버전 레이블 없음)인 경우, 버전을 일치시킬 때 모든 후보 버전의 로컬 버전 레이블을 반드시 무시해야 합니다.

지정된 버전 식별자가 로컬 버전 식별자인 경우, 버전을 일치시킬 때 후보 버전의 로컬 버전 레이블을 반드시 고려해야 하며, 공개 버전 식별자는 위에 설명한 대로 일치시키고, 로컬 버전 레이블은 엄격한 문자열 동등 비교를 사용하여 동등성을 검사합니다.

버전 제외

버전 제외 절은 버전 제외 연산자 !=와 버전 식별자를 포함합니다.

허용되는 버전 식별자와 비교 의미는 Version matching 연산자와 같지만, 일치 여부가 반대로 뒤집힌다는 점이 다릅니다.

예를 들어, 버전 1.1.post1이 주어지면 다음 절들은 표시된 대로 일치하거나 일치하지 않습니다:

!= 1.1        # Not equal, so 1.1.post1 matches clause
!= 1.1.post1  # Equal, so 1.1.post1 does not match clause
!= 1.1.*      # Same prefix, so 1.1.post1 does not match clause

경계 포함 순서 비교

포함 순서 비교 절은 비교 연산자와 버전 식별자로 이루어지며, 표준 Version scheme에 정의된 일관된 순서에 따라 후보 버전과 지정된 버전의 상대적 위치를 기준으로 비교가 참이 되는 모든 버전과 일치합니다.

포함 순서 비교 연산자는 <=와 >=입니다.

버전 일치와 마찬가지로, 릴리스 세그먼트끼리 같은 길이로 비교되도록 필요에 따라 릴리스 세그먼트를 0으로 채웁니다.

이 버전 지정자에서는 로컬 버전 식별자가 허용되지 않습니다(NOT permitted).

배타 순서 비교

배타 순서 비교 >와 <는 표준 Version scheme에 정의된 일관된 순서에 따라 후보 버전과 지정된 버전의 상대적 위치에 의존한다는 점에서 포함 순서 비교와 비슷합니다. 그러나 이 비교들은 지정된 버전의 사전 릴리스, 사후 릴리스, 로컬 버전을 명시적으로 제외합니다.

배타 순서 비교 >V는 V 자체가 사후 릴리스가 아니라면 주어진 버전의 사후 릴리스를 허용해서는 안 됩니다(MUST NOT). >V.postN을 사용하면 릴리스가 추가 사후 릴리스를 포함하여 특정 사후 릴리스보다 이후여야 한다고 요구할 수 있습니다. 예를 들어, >1.7은 1.7.1은 허용하지만 1.7.0.post1은 허용하지 않으며, >1.7.post2는 1.7.1과 1.7.0.post3은 허용하지만 1.7.0은 허용하지 않습니다.

배타 순서 비교 >V는 지정된 버전의 로컬 버전과 일치해서는 안 됩니다(MUST NOT).

배타 순서 비교 <V는 지정된 버전 자체가 사전 릴리스가 아니라면 지정된 버전의 사전 릴리스를 허용해서는 안 됩니다(MUST NOT). 특정 사전 릴리스보다 이전이되 그와 같지는 않은 사전 릴리스를 허용하려면 <V.rc1 등을 사용하면 됩니다.

버전 일치와 마찬가지로, 릴리스 세그먼트끼리 같은 길이로 비교되도록 필요에 따라 릴리스 세그먼트를 0으로 채웁니다.

이 버전 지정자에서는 로컬 버전 식별자가 허용되지 않습니다(NOT permitted).

임의 동등성

임의 동등성 비교는 0 채우기나 로컬 버전 같은 의미 정보를 전혀 고려하지 않는 단순한 문자열 동등성 연산입니다. 또한 이 연산자는 == 연산자와 달리 접두사 일치를 지원하지 않습니다.

임의 동등의 주된 사용 사례는 이 PEP로는 달리 표현할 수 없는 버전을 지정할 수 있게 하는 것입니다. 이 연산자는 특수한 연산자로서, 이 PEP를 구현한 도구를 사용하는 사람이 이 PEP와 호환되지 않는 레거시 버전도 설치할 수 있도록 하는 탈출구 역할을 합니다.

===foobar가 그 예이며, 이는 foobar라는 버전과 일치합니다.

이 연산자는 ===1.0처럼 프로젝트의 패치되지 않은 버전을 명시적으로 요구하는 데에도 사용할 수 있으며, 이 경우 1.0+downstream1 버전과는 일치하지 않습니다.

이 연산자의 사용은 강력히 권장되지 않으며, 도구는 이 연산자가 사용될 때 경고를 표시할 수 있습니다(MAY).

사전 릴리스 처리

개발 릴리스를 포함한 모든 종류의 사전 릴리스는 이미 시스템에 존재하거나, 사용자가 명시적으로 요청했거나, 버전 지정자를 만족하는 유일한 사용 가능 버전이 사전 릴리스인 경우가 아니라면 모든 버전 지정자에서 암묵적으로 제외됩니다.

기본적으로 의존성 해석 도구는 다음과 같이 동작해야 합니다(SHOULD):

  • 모든 버전 지정자에 대해 이미 설치된 사전 릴리스를 수용합니다.
  • 버전 지정자를 만족하는 최종 릴리스나 사후 릴리스가 없는 버전 지정자에 대해서는 원격에서 사용 가능한 사전 릴리스를 수용합니다.
  • 그 밖의 모든 사전 릴리스는 고려 대상에서 제외합니다.

의존성 해석 도구는 버전 지정자를 만족하는 데 사전 릴리스가 필요한 경우 경고를 표시할 수 있습니다(MAY).

의존성 해석 도구는 또한 사용자가 다음과 같은 대체 동작을 요청할 수 있도록 해야 합니다(SHOULD):

  • 모든 버전 지정자에 대해 사전 릴리스 수용
  • 모든 버전 지정자에서 사전 릴리스를 제외(사전 릴리스가 이미 로컬에 설치되어 있거나, 사전 릴리스로만 특정 지정자를 만족할 수 있는 경우에는 오류나 경고를 보고)

의존성 해결 도구는 위의 동작을 배포 패키지 단위로 제어할 수 있도록 허용할 수도 있습니다(MAY).

사후 릴리스와 최종 릴리스는 버전 지정자에서 특별하게 취급되지 않습니다. 명시적으로 제외하지 않는 한 항상 포함됩니다.

예시

  • ~=3.1: 버전 3.1 이상이지만 버전 4.0 이상은 아닙니다.
  • ~=3.1.2: 버전 3.1.2 이상이지만 버전 3.2.0 이상은 아닙니다.
  • ~=3.1a1: 버전 3.1a1 이상이지만 버전 4.0 이상은 아닙니다.
  • == 3.1: 정확히 버전 3.1(또는 3.1.0)이며, 모든 사전 릴리스, 사후 릴리스, 개발 릴리스, 3.1.x 유지보수 릴리스를 제외합니다.
  • == 3.1.*: 3.1로 시작하는 모든 버전입니다. ~=3.1.0 호환 릴리스 절과 동등합니다.
  • ~=3.1.0, != 3.1.3: 버전 3.1.0 이상이지만 버전 3.1.3은 아니며 버전 3.2.0 이상도 아닙니다.

직접 참조

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

직접 참조가 적절한지는 버전 지정자의 구체적인 사용 사례에 따라 달라집니다. 직접 참조가 부적절하게 사용되는 경우, 자동화 도구는 최소한 경고를 표시해야 하며(SHOULD) 이를 완전히 거부할 수도 있습니다(MAY).

공개 색인 서버는 업로드된 배포 패키지에서 직접 참조를 사용하도록 허용하지 않아야 합니다(SHOULD NOT). 직접 참조는 배포자가 아니라 소프트웨어 통합자를 위한 도구입니다.

사용 사례에 따라 직접 URL 참조의 적절한 대상으로는 sdist나 wheel 바이너리 아카이브 등이 있을 수 있습니다. 지원되는 정확한 URL과 대상은 도구에 따라 다릅니다.

예를 들어, 로컬 소스 아카이브를 직접 참조할 수 있습니다:

pip @ file:///localbuilds/pip-1.3.1.zip

또는 미리 빌드된 아카이브를 참조할 수도 있습니다:

pip @ file:///localbuilds/pip-1.3.1-py33-none-any.whl

로컬 파일 URL을 가리키지 않는 모든 직접 참조는 안전한 전송 메커니즘(예: https)을 지정해야 하며(SHOULD), 그와 함께(AND) 검증을 위해 예상 해시값을 URL에 포함해야 합니다. 직접 참조에 해시 정보가 전혀 없거나, 도구가 이해하지 못하는 해시 정보가 있거나, 도구가 신뢰하기에 너무 약하다고 판단하는 해시 알고리즘이 선택된 경우, 자동화 도구는 최소한 경고를 내보내야 하며(SHOULD) 해당 URL에 의존하기를 거부할 수도 있습니다(MAY). 그러한 직접 참조가 안전하지 않은 전송 방식까지 사용한다면, 자동화 도구는 해당 URL에 의존하지 않아야 합니다(SHOULD NOT).

소스 아카이브 해시에는 표준 라이브러리 hashlib 모듈의 최신 버전이 무조건 제공하는 해시만 사용할 것을 권장합니다(RECOMMENDED). 이 글을 쓰는 시점에서 해당 목록은 'md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512'입니다.

소스 아카이브 참조와 wheel 참조에서는 URL 프래그먼트에 <hash-algorithm>=<expected-hash> 항목을 포함하여 예상 해시값을 지정할 수 있습니다.

버전 관리 참조에서는 버전 관리 시스템과 안전한 전송 방식을 모두 식별할 수 있도록 VCS+protocol 스킴을 사용해야 하며(SHOULD), 해시 기반 커밋 식별자를 사용하는 버전 관리 시스템을 사용해야 합니다(SHOULD). 해시 기반 커밋 식별자를 제공하지 않는 버전 관리 시스템의 경우, 자동화 도구는 해시 누락에 관한 경고를 생략할 수 있습니다(MAY).

커밋 참조나 태그 참조를 URL에 직접 포함하는 기능을 지원하지 않는 버전 관리 시스템에서는 @<commit-hash> 표기법이나 @<tag>#<commit-hash> 표기법으로 해당 정보를 URL 끝에 덧붙일 수 있습니다.

Note

이것은 pip이 지원하는 기존 VCS 참조 표기법과 완전히 같지는 않습니다. 첫째, 배포 패키지 이름은 URL의 일부로 포함되는 대신 앞쪽으로 옮겨졌습니다. 둘째, 위조를 더 어렵게 하려면 모든 링크에 해시가 포함되어야 한다는 앞의 요구 사항을 충족하기 위해, 태그를 기준으로 가져오는 경우에도 커밋 해시를 포함합니다(특정 태그를 가진 악의적인 저장소를 만드는 것은 쉽지만, 특정 해시를 가진 저장소를 만드는 것은 그보다 어렵습니다).

원격 URL 예시:

pip @ https://github.com/pypa/pip/archive/1.3.1.zip#sha1=da9234ee9982d4bbb3c72346a6de940a148ea686
pip @ git+https://github.com/pypa/pip.git@7921be1537eac1e97bc40179a57f0349c2aee67d
pip @ git+https://github.com/pypa/pip.git@1.3.1#7921be1537eac1e97bc40179a57f0349c2aee67d

파일 URL

파일 URL은 file://<host>/<path> 형식을 취합니다. <host>가 생략되면 localhost로 간주되며, <host>가 생략되더라도 세 번째 슬래시는 반드시(MUST) 있어야 합니다. <path>는 접근할 파일 시스템상의 파일 경로를 정의합니다.

여러 *nix 운영 체제에서 <host>에 허용되는 값은 생략하는 것, localhost, 또는 현재 머신이 자신의 호스트와 일치한다고 판단하는 다른 FQDN뿐입니다. 즉, *nix에서 file:// 스킴은 로컬 머신의 경로에 접근하는 데에만 사용할 수 있습니다.

Windows에서는 해당하는 경우 파일 형식에 드라이브 문자를 <path>의 일부로 포함해야 합니다(예: file:///c:/path/to/a/file). *nix와 달리 Windows에서는 <host> 매개변수를 사용하여 네트워크 공유에 있는 파일을 지정할 수 있습니다. 즉, \\machine\volume\file을 file:// URL로 변환하면 file://machine/volume/file이 됩니다. Windows의 file:// URL에 대한 자세한 내용은 MSDN [4]을 참조하십시오.

버전 관리 명세 갱신

버전 관리 명세는 새 PEP나 메타데이터 버전 변경 없이도 명확화를 위해 갱신될 수 있습니다.

버전 식별 및 비교의 문법과 의미에 영향을 주는 기술적 변경은 모두 새 PEP에서 갱신된 버전 관리 체계를 정의해야 합니다.

pkg_resources.parse_version과의 차이점 요약

  • 참고: 이 비교는 이 PEP가 작성될 당시의 pkg_resourses.parse_version을 기준으로 합니다. 이 PEP가 승인된 후, setuptools 6.0 이상 버전은 이 PEP에 설명된 동작을 채택했습니다.
  • 로컬 버전은 다르게 정렬됩니다. 이 PEP는 로컬 버전이 로컬 버전이 없는 동일한 버전보다 크게 정렬되도록 요구하는 반면, pkg_resources.parse_version은 이를 사전 릴리스 표시로 간주합니다.
  • 이 PEP는 유효한 버전을 구성하는 문법을 의도적으로 제한하는 반면, pkg_resources.parse_version은 임의의 문자열에서도 어떤 의미를 끌어내려고 시도합니다.
  • pkg_resources.parse_version은 1.0.dev1.post1.dev5와 같이 임의로 깊게 중첩된 버전 표시자를 허용합니다. 그러나 이 PEP는 각 유형을 한 번씩만 사용할 수 있도록 허용하며, 이들은 정해진 순서로 나타나야 합니다.

PEP 386과의 차이점 요약

  • 버전 지정자에 대한 설명을 버전 관리 PEP로 옮겼습니다.
  • 리소스에 대한 직접 참조의 표준 표기법으로 “직접 참조” 개념을 추가했습니다(각 도구가 저마다 표기법을 고안할 필요가 없도록 하기 위함입니다).
  • 시스템 통합자가 업스트림 도구에서 지원하는 방식으로 패치된 빌드를 표시할 수 있도록 하고, 바이너리 배포판의 버전 관리에 빌드 태그를 포함할 수 있도록 “로컬 버전 식별자”와 “로컬 버전 레이블” 개념을 추가했습니다.
  • “호환 릴리스” 절을 추가했습니다.
  • 접두사 기반 버전 매칭 및 제외를 위한 후행 와일드카드 문법을 추가했습니다
  • .devN 접미사의 최상위 정렬 위치를 변경했습니다.
  • 단일 값 버전 번호를 허용했습니다.
  • 앞뒤 공백의 명시적 배제
  • 날짜 기반 버전의 명시적 지원
  • 모호성을 유발하지 않는 범위에서 PyPI의 기존 버전 메타데이터와의 호환성을 높이기 위한 명시적 정규화 규칙
  • 사전 릴리스가 이미 존재하거나 의존성을 충족하는 데 필요한 경우가 아니면 암묵적으로 제외
  • 사후 릴리스를 한정자 없는 릴리스와 동일하게 취급
  • 메타데이터 버전 간 순서 및 의존성에 대한 논의
  • c를 선호하던 방식에서 rc를 선호하는 방식으로 전환합니다.

주요 변경 사항의 근거는 다음 절들에서 설명합니다.

버전 체계 변경

이 PEP의 버전 체계가 PEP 386의 버전 체계와 비교하여 크게 달라진 점 하나는 X.Y.devN 같은 최상위 개발 릴리스를 X.Ya1 같은 알파 릴리스보다 앞에 정렬한다는 것입니다. 개발 릴리스와 알파/베타/릴리스 후보를 모두 사용하고 있는 프로젝트들은 개발 릴리스가 릴리스 후보와 최종 릴리스 사이에 정렬되기를 원하지 않으므로, 이것이 훨씬 더 논리적인 정렬 순서입니다. 단순히 릴리스 후보를 추가로 만드는 대신 그 위치에 dev 릴리스를 사용할 근거는 없습니다.

또한 갱신된 정렬 순서에 따라 이제 dev 버전의 정렬이 메타데이터 표준과 기존 pkg_resources의 동작(따라서 현재 설치 도구들의 동작) 사이에서 일관됩니다.

이 변경으로 영향을 받는 기존 프로젝트들이 최신 버전의 메타데이터 표준으로 더 쉽게 이전할 수 있을 것입니다.

버전 체계의 또 다른 변경 사항은 Mozilla Firefox, Google Chrome, Fedora Linux 배포판 같은 Python 외 프로젝트에서 사용하는 것과 비슷한 단일 숫자 버전을 허용한다는 것입니다. 사실 이는 버전 지정자에 더 유용할 것으로 예상되지만, 두 정의를 분리하기보다는 버전 지정자와 릴리스 번호 모두에 허용하는 편이 더 간단합니다.

앞뒤 공백의 배제는 끝에 붙은 \n 문자 하나만 다른 버전 식별자를 가진 프로젝트 몇 개가 PyPI에서 발견된 뒤에 명시되었습니다.

아래의 버전 정규화에 관한 별도 절에서 설명하는 것처럼 그 밖의 다양한 정규화 규칙도 추가되었습니다.

Appendix A는 2014년 8월 8일에 수집한 PyPI 배포 패키지 버전 정보를 분석한 상세 결과를 보여 줍니다. 이 분석은 이 PEP에서 정의한, 명시적으로 순서가 정해진 버전 체계의 동작을 setuptools의 동작으로 정의되는 사실상의 표준과 비교합니다. 이 PEP의 의도는 순서를 정할 수 없는 버전에 대해서는 (setuptools처럼 적절한 순서를 추측하려 하지 않고) 여전히 예외를 발생시키면서도 기존 setuptools의 동작을 가능한 한 가깝게 따르는 것이므로, 이러한 지표는 유용합니다.

버전 관리 체계에 대한 보다 확고한 관점의 설명

PEP 386과 마찬가지로, 주된 초점은 기존 프로젝트에 워크플로를 크게 바꾸도록 요구하기보다는 기존 관행을 명문화하여 자동화하기 쉽게 만드는 데 있습니다. 하지만 표준 체계는 대다수의 단순한 Python 패키지에 필요한 것보다 훨씬 더 많은 유연성을 허용합니다(이러한 패키지는 대개 유지보수 릴리스조차 필요하지 않으며, 많은 사용자는 버그 수정을 받기 위해 새 기능 릴리스로 업그레이드해야 하는 것에 만족합니다).

초보 개발자, 그리고 다양한 사용 사례를 더 잘 이해하고자 하는 숙련된 개발자를 위해, 이제 명세는 정의된 버전 체계의 구성 요소를 훨씬 더 자세히 다루며, 각 구성 요소를 실제로 어떻게 사용할 수 있는지에 대한 예시도 포함합니다.

또한 이 PEP는 개발자를 의미적 버전 관리 방향으로 명시적으로 안내하며(요구하지는 않음), 기존 프로젝트의 관행과 Linux 배포판용 소프트웨어 재패키징에서 나타나는 난해한 예외 사례를 다루기 위해 주로 포함된 전체 버전 관리 체계의 여러 측면은 사용하지 않도록 권장합니다.

버전 관리 체계와 함께 버전 지정자를 설명

애초에 표준화된 버전 체계를 두는 주된 이유는 신뢰할 수 있는 자동화된 의존성 분석을 더 쉽게 하기 위해서입니다. 버전 식별자의 주요 사용 사례를 그 정의와 함께 설명하는 것이 더 합리적입니다.

버전 지정자 해석 방식 변경

이전의 버전 지정자 해석 방식에서는 의존성의 사전 릴리스 버전을 실수로 내려받기가 매우 쉬웠습니다. 이 때문에 개발자가 소프트웨어의 사전 릴리스 버전을 Python 패키지 색인에 게시하기가 어려웠는데, 패키지를 숨김으로 표시하는 것만으로는 자동화 도구가 그 패키지를 내려받지 못하게 막기에 충분하지 않았기 때문입니다. 또한 사용자가 PyPI의 주 웹 인터페이스를 통해 테스트 릴리스를 수동으로 받기도 더 어려워졌습니다.

이전 해석은 또한 충분히 정당화되지 않은 이유로 일부 버전 지정자에서 사후 릴리스(post-release)를 제외했습니다.

갱신된 해석의 목적은 사전 릴리스(pre-release) 버전이 의존성을 충족하는 것으로 실수로 받아들여지기 어렵게 하는 것입니다. 다만 그것이 의존성을 충족하는 유일한 방법일 때에는 사전 릴리스 버전을 여전히 자동으로 가져올 수 있게 합니다.

“어느 정도의 상위 호환성을 가정하는” 버전 제약은 Ruby 커뮤니티의 “비관적 버전 제약(pessimistic version constraint)” 연산자 [2]에서 파생되었습니다. 이 제약을 사용하면 프로젝트가 상위 호환성 약속에 신중하게 접근하면서도 의존성에 필요한 최소 버전을 쉽게 설정할 수 있습니다. 호환 릴리스 절의 표기(~=)는 Ruby(~>)와 PHP(~)의 동등한 표기에서 영감을 받았습니다.

같은 라이브러리의 여러 버전을 병렬로 설치하는 방식도 추가로 개선할 계획입니다. 다만 이는 설치 데이터베이스 정의의 갱신과 동적 경로 조작을 위한 도구의 개선에 달려 있습니다.

호환 릴리스 절을 합리적으로 정의할 수 있도록 접두사 기반 버전 매칭을 요청하는 후행 와일드카드 문법을 추가했습니다.

날짜 기반 버전 식별자 지원

날짜 기반 버전을 제외하자 pytz를 새 메타데이터 표준으로 이전하는 데 심각한 문제가 생겼습니다. 이는 OpenStack 개발자들에게도 우려를 불러일으켰습니다. 그들은 날짜 기반 버전 관리 체계를 사용하며, 이를 바꾸지 않고 새 메타데이터 표준으로 이전하기를 원했기 때문입니다.

버전 에포크 추가

버전 에포크를 추가한 이유는 Fedora와 Debian Linux 배포판의 체계 같은 다른 버전 관리 체계에 에포크가 들어 있는 이유와 같습니다. 새 릴리스가 이전 릴리스보다 낮은 버전 번호를 가진 것처럼 보이지 않고 프로젝트 이름도 바꿀 필요 없이, 프로젝트가 릴리스 번호를 매기는 방식을 매끄럽게 변경할 수 있게 하려는 것입니다.

특히 버전 에포크를 지원하면, 이전에 날짜 기반 버전 관리를 사용하던 프로젝트가 새 버전 에포크를 지정하여 의미적 버전 관리로 전환할 수 있습니다.

에포크 버전을 구분하는 문자로는 다른 시스템에서 흔히 사용하는 : 문자 대신 ! 문자를 선택했습니다. : 문자는 Windows 디렉터리 이름에 사용할 수 없기 때문입니다.

직접 참조 추가

직접 참조는 표준 배포 모델에 깔끔하게 대응하지 않는 복잡한 현실 상황을 처리하기 위한 “예외 절”로 추가되었습니다. 여기에는 내부용으로 쓰는 미공개 소프트웨어에 대한 의존성이 포함됩니다. 서드파티 라이브러리를 C 확장으로 감쌀 때 생길 수 있는 더 복잡한 호환성 문제를 처리하는 것도 포함됩니다(이는 과학 커뮤니티에서 특히 중요한 관심사입니다).

직접 참조는 주로 배포자보다는 통합자를 위한 도구입니다. 그래서 색인 서버에는 직접 참조를 허용하지 않을 수 있는 폭넓은 재량을 의도적으로 부여합니다. 특히 PyPI는 현재 외부 참조에 대한 의존성을 제거하는 과정을 밟고 있습니다. 신뢰할 수 없는 외부 서비스는 설치 작업을 느리게 할 뿐만 아니라 겉으로 보이는 PyPI 자체의 신뢰성까지 떨어뜨리기 때문입니다.

임의 동등성 추가

임의 동등 비교는 누군가 규격에 맞지 않는 버전을 사용하는 프로젝트를 설치해야 하는 경우를 처리하기 위한 “예외 절”로 추가되었습니다. 이 PEP는 이미 PyPI에 있는 버전과 약 97%의 호환성을 달성할 수 있지만, 여전히 파싱할 수 없는 버전이 약 3% 있습니다. 이 연산자를 사용하면 그러한 버전의 의미를 “추측”하지 않고도 여전히 간단하고 효과적으로 그 버전에 의존할 수 있습니다(엄격한 문자열 기반 동등성 외의 방식을 지원한다면 그러한 추측이 필요했을 것입니다).

로컬 버전 식별자 추가

다운스트림 통합자가 업스트림 버그 수정을 이전 버전으로 백포트해야 하는 경우가 많다는 것은 엄연한 현실입니다. 이는 Linux 배포판 벤더가 돈을 받고 제공하는 서비스 중 하나입니다. 애플리케이션 개발자도 번들로 포함한 의존성에 필요한 패치를 적용할 수 있습니다.

지금까지 크로스 플랫폼 언어별 배포 도구는 이러한 관행을 알아볼 수 없었습니다. 업스트림 메타데이터에 보고되는 “버전”이 수정되지 않은 코드의 버전과 같기 때문입니다. 이러한 부정확성 때문에 통합자가 제공한 코드와 수정되지 않은 업스트림 코드를 섞어서 다루려고 할 때 문제가 생길 수 있습니다. 단순히 소프트웨어의 어떤 버전이 설치되어 있는지 정확히 확인하려고 할 때조차 문제가 생길 수 있습니다.

버전 관리 체계에 로컬 버전 식별자와 “로컬 버전 레이블”을 도입하고, 이에 대응하는 python.integrator 메타데이터 확장을 함께 도입하면 이러한 활동을 정확하게 표현할 수 있습니다. 이를 통해 업스트림 도구와 다양한 통합 플랫폼 간의 상호 운용성이 향상될 것입니다.

선택한 구체적인 체계는 대체로 pkg_resources.parse_version과 pkg_resources.parse_requirements의 기존 동작을 본떴습니다. 주된 차이점은 다음과 같습니다. 현재 pkg_resources는 정확한 일치를 확인하려고 버전을 비교할 때 항상 접미사를 고려합니다. 반면 이 PEP는 버전 지정자 절에 로컬 버전 레이블이 없으면 후보 버전의 로컬 버전 레이블을 무시하도록 요구합니다. 또한 이 PEP는 로컬 버전 레이블에 어떠한 구조도 부과하려 하지 않습니다(허용되는 문자 집합을 제한하고 그 순서를 정의하는 것은 예외입니다).

이 변경의 목적은 pip 1.5+1이나 pip 1.5+1.git.abc123de 같은 통합자 제공 버전도 pip>=1.5 같은 버전 지정자를 여전히 충족하도록 보장하는 것입니다.

플러스 기호는 주로 로컬 버전 식별자의 가독성을 위해 선택되었습니다. 하이픈 대신 플러스 기호를 선택한 것은 pkg_resources.parse_version이 이를 사전 릴리스로 해석하지 않도록 하기 위해서입니다. 이는 새롭고 더 구조화된 버전 관리 체계로 성공적으로 이전하는 데 중요합니다. 틸드 대신 플러스 기호를 선택한 이유는 Debian의 버전 정렬 알고리즘에서 틸드가 특별한 의미를 갖기 때문입니다.

명시적인 버전 정규화 규칙 제공

역사적으로 Python에서 버전을 해석하는 사실상의 표준은 setuptools 프로젝트의 pkg_resources.parse_version 명령이었습니다. 이 명령은 어떤 버전도 거부하려 하지 않습니다. 대신 주어진 것이 무엇이든 그로부터 의미 있는 무언가를 만들어 내려고 시도하며, 그 성공 정도는 경우마다 다릅니다. 몇 가지 간단한 규칙이 있기는 하지만, 그 외에는 대체로 문자열 비교에 크게 의존합니다.

이 PEP에서 제공하는 정규화 규칙이 존재하는 주된 목적은 두 가지입니다. 하나는 pkg_resources.parse_version과의 호환성을 높이는 것이며, 특히 rev, r, pre 등 문서화된 사용 사례에서 그렇습니다. 다른 하나는 PyPI에 이미 존재하는 버전들을 더 합리적으로 처리하는 것입니다.

가능한 모든 정규화 규칙은 모호함을 일으킬 가능성이 높은지 여부를 기준으로 검토되었습니다(예를 들어 누군가 v1.0과 1.0을 서로 다른 릴리스로 간주하는 체계를 고안할 수도 있겠지만, 실제로 그렇게 하는 사람이 있을 가능성은 상당히 낮으며, 눈에 띌 만한 규모로 그렇게 할 가능성은 더욱 낮습니다). 또한 pkg_resources.parse_version이 특정 버전 문자열을 어떻게 처리했는지, 특히 그것을 어떻게 정렬했는지를 기준으로도 검토되었습니다. 마지막으로 각 규칙은 네 가지 기준으로 검토되었습니다. 그 규칙이 추가로 허용하는 버전의 종류, 그러한 버전이 얼마나 “보기 흉한지”, (사람이 읽을 때와 기계가 처리할 때 모두) 해석하기가 얼마나 어려운지, 그리고 호환성을 추가로 얼마나 높여 주는지입니다.

가능한 정규화의 범위는 버전을 해석하는 과정의 일부로 쉽게 구현할 수 있는 것들로 한정되었으며, 해석 전에 버전에 적용하는 변환은 포함하지 않았습니다. 이는 각 변환의 부작용을 제한하기 위한 것입니다. 단순한 검색 및 치환 방식의 변환은 모호하거나 “쓸모없는” 버전이 생길 가능성을 높이기 때문입니다.

검토된 다양한 유형의 정규화에 대한 자세한 논의는 pip에서의 PEP 440 개념 증명을 참조하십시오 [5].

정규화에서 밑줄 허용

PyPI에는 버전 문자열에 _를 사용하는 프로젝트가 많지 않습니다. 그러나 이 PEP는 -가 허용되는 곳이라면 어디서든 이를 사용할 수 있도록 허용합니다. 그 이유는 Wheel 정규화 체계가 파일 이름을 더 쉽게 해석할 수 있도록 -를 _로 정규화하도록 규정하기 때문입니다.

PEP 440 변경 사항 요약

setuptools 8.0과 pip 6.0에서 최초의 참조 구현이 배포된 후 받은 피드백을 바탕으로 이 PEP에 다음과 같은 변경이 이루어졌습니다:

  • 배타적 순서 비교가 더 이상 !=V.*를 함축하지 않도록 수정되었습니다. 이 동작은 예상 밖이었고 정확하게 설명하기도 너무 어렵다고 판단되었기 때문입니다. 대신 배타적 순서 비교는 지정된 버전의 사전 릴리스, 사후 릴리스, 로컬 버전과의 일치를 단순히 허용하지 않게 됩니다(지정된 버전 자체가 사전 릴리스, 사후 릴리스 또는 로컬 버전인 경우는 제외합니다). 자세한 논의는 distutils-sig의 스레드를 참조하십시오 [6] [7].
  • 릴리스 후보의 정규화된 형식이 ‘c’에서 ‘rc’로 변경되었습니다. 이 변경은 setuptools 8.0이 PyPI 게시를 위해 패키지를 준비할 때 생성되는 릴리스 메타데이터에 정규화를 적용하기 시작한 후 받은 사용자 피드백에 따른 것입니다 [8].
  • PEP 본문과 is_canonical 정규식이 수정되었습니다. 이제 숫자 구성 요소는 임의의 유니코드 [Nd] 코드 포인트가 아니라 반드시 ASCII 숫자의 시퀀스로 표현되어야 한다는 점을 명시합니다. 이는 이전에도 부록 B의 버전 해석 정규식에 함축되어 있었지만, 명시적으로 언급되지는 않았습니다 [10].

참고 문헌

표준화된 버전 체계를 처음 시도한 내용과 그러한 표준이 필요한 이유는 PEP 386에서 찾아볼 수 있습니다.

부록 A

메타데이터 v2.0 지침 대 setuptools:

$ invoke check.pep440
Total Version Compatibility:              245806/250521 (98.12%)
Total Sorting Compatibility (Unfiltered): 45441/47114 (96.45%)
Total Sorting Compatibility (Filtered):   47057/47114 (99.88%)
Projects with No Compatible Versions:     498/47114 (1.06%)
Projects with Differing Latest Version:   688/47114 (1.46%)

부록 B : 정규 표현식으로 버전 문자열 파싱하기

앞서 Public version identifiers 절에서 언급했듯이, 공개되는 버전 식별자는 정규 형식을 사용해야 합니다(SHOULD). 이 절에서는 어떤 버전이 이미 그 형식인지 검사하고, 그렇지 않다면 이후 정규화를 위해 여러 구성 요소를 추출하는 데 사용할 수 있는 정규 표현식을 제공합니다.

버전 식별자가 정규 형식인지 검사하려면 다음 함수를 사용할 수 있습니다:

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,
)