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

Python 개선 제안 한국어 번역

PEP 396 – 모듈 버전 번호

Author:
Barry Warsaw <barry at python.org>
Status:
Withdrawn
Type:
Informational
Topic:
Packaging
Created:
16-Mar-2011
Post-History:
05-Apr-2011

Table of Contents

번역·라이선스 안내

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

Important

This PEP has been withdrawn.

×

런타임에 패키지 버전 정보에 접근하는 방법과, 패키지 배포 메타데이터와 자동으로 일관되게 유지되는 런타임 __version__ 속성을 정의하는 방법에 대한 최신 권장 사항은 Python 패키징 사용자 가이드의 Accessing version information at runtime 및 Single-sourcing the Project Version 문서를 참고하십시오

초록

Python 모듈에 버전 번호를 지정하는 것은 유용하고 흔한 일이며, 이를 위한 여러 방법이 Python 커뮤니티 안에서 자연스럽게 생겨났으므로, 모듈 작성자가 따르고 참고할 수 있는 표준 관례를 정립하는 것이 유용합니다. 이 정보성 PEP는 자신의 Python 모듈에 버전 번호를 정의하려는 Python 모듈 작성자를 위한 모범 사례를 설명합니다.

이 PEP를 준수하는 것은 선택 사항이지만, 다른 Python 도구(예: distutils2 [1])가 여기서 정의한 관례를 사용하도록 조정될 수 있습니다.

PEP 거부/철회

이 PEP는 2021-04-14에 공식적으로 거부되었습니다. 이 PEP가 처음 작성된 이후 몇 년 사이에 패키징 생태계는 크게 변화했으며, importlib.metadata.version() [11] 같은 API가 훨씬 나은 사용 경험을 제공합니다.

이전 상태가 어떤 모듈도 __version__ 속성을 정의해서는 안 된다는 뜻으로 잘못 해석되고 있었기 때문에 [12] 이 거부는 2024-10-21에 철회로 재분류되었으며, 그러한 해석은 분명히 사실이 아닙니다.

모듈은 원한다면 여전히 자유롭게 __version__을 정의할 수 있습니다. 하지만 그렇게 하지 않기로 선택하더라도 설치된 배포 패키지의 버전 정보를 조회하는 데에는 지장이 없으므로, 모듈 __version__ 속성의 사용에 관한 커뮤니티 관례를 문서화하는 데에는 정보성 PEP가 적절한 수단이 아닙니다(이러한 관례는 Python 패키징 사용자 가이드의 일부로 다루는 것이 더 좋습니다).

사용자 이야기

Alice는 다른 Python 개발자들과 공유하고 싶은 alice라는 새 모듈을 작성하고 있습니다. alice는 단순한 모듈이며 alice.py라는 하나의 파일에 들어 있습니다. Alice는 사용자들이 자신이 어떤 버전을 사용하고 있는지 알 수 있도록 버전 번호를 지정하려고 합니다. 모듈 전체가 하나의 파일에 들어 있으므로, Alice는 그 파일에 버전 번호를 추가하려고 합니다.

Bob은 bob이라는 모듈을 작성하여 많은 사용자와 공유해 왔습니다. bob.py에는 사용자의 편의를 위해 버전 번호가 들어 있습니다. Bob은 치즈숍(Cheeseshop) [2]에 대해 알게 되었고, The Bob Bundle을 치즈숍에 업로드할 수 있도록 고전적인 distutils를 사용해 간단한 패키징을 추가합니다. bob.py는 이미 사용자가 프로그래밍 방식으로 접근할 수 있는 버전 번호를 지정하고 있으므로, Bob은 이제 사용자들이 치즈숍에서 모듈을 받더라도 같은 API가 계속 동작하기를 원합니다.

Carol은 여러 네임스페이스 패키지를 유지 관리하며, 각 패키지는 독립적으로 개발되고 배포됩니다. 사용자들이 Carol의 패키지의 올바른 버전에 대한 의존성을 제대로 지정할 수 있도록, Carol은 네임스페이스 패키지의 setup.py 파일에 버전 번호를 지정합니다. Carol은 패키지마다 버전 번호를 하나만 갱신하고 싶기 때문에, 모듈에 버전 번호를 지정하고 sdist 아카이브를 빌드할 때 setup.py가 모듈 버전 번호를 추출하도록 합니다.

David는 표준 라이브러리에 있는 패키지를 유지 관리하며, 다른 Python 버전을 위한 독립 실행형 버전도 만듭니다. 표준 라이브러리 사본은 모듈 안에 버전 번호를 정의하며, 이와 같은 버전 번호가 독립 실행형 배포판에도 사용됩니다.

근거

표준 라이브러리에 있는 것이든 서드파티에서 제공하는 것이든, Python 모듈은 오래전부터 버전 번호를 포함해 왔습니다. 버전 번호를 기술하는 확립된 사실상의 표준이 있으며, 수년에 걸쳐 여러 임시방편적인 방법도 자연스럽게 생겨났습니다. 흔히 모듈을 임포트하고 속성을 살펴보는 방식으로 모듈에서 버전 번호를 프로그래밍 방식으로 가져올 수 있습니다. 고전적인 Python distutils의 setup() 함수 [3]는 릴리스의 버전 번호를 지정할 수 있는 version 인자를 기술합니다. PEP 8은 키워드 확장을 사용하여 “Subversion, CVS, 또는 RCS” 버전 문자열을 기록하기 위한 __version__이라는 모듈 속성의 사용을 설명합니다. PEP 작성자 본인의 이메일 보관함에서, 독립적인 모듈 개발자들이 __version__ 모듈 속성을 사용한 가장 이른 사례는 1995년으로 거슬러 올라갑니다.

버전 정보의 또 다른 예로는 sqlite_version_info, version, version_info 속성을 가진 sqlite3 [5] 모듈이 있습니다. 어떤 속성이 모듈의 버전 번호를 담고 있고, 어떤 속성이 기반이 되는 SQLite3 라이브러리의 버전 번호를 담고 있는지 즉시 명확하지 않을 수 있습니다.

이 정보성 PEP는 확립된 관행을 성문화하고, 모듈 버전 번호를 기술하는 표준 방식을 권장하며, 버전 번호를 포함해야 하는 경우와 포함하지 말아야 하는 경우에 대한 몇 가지 사용 사례를 함께 제시합니다. 모듈 작성자가 이를 채택할지는 전적으로 자율에 맡깁니다. 표준 라이브러리의 패키징 도구는 여기에 정의된 표준을 선택적으로 지원할 것이며, Python 생태계의 다른 도구들도 이를 따를 수 있습니다.

명세

  1. 일반적으로 표준 라이브러리의 모듈은 버전 번호를 가져서는 안 됩니다(SHOULD NOT). 이러한 모듈은 자신이 포함된 Python 릴리스의 버전 번호를 암묵적으로 따릅니다.
  2. 다른 Python 버전을 위해 독립형으로도 릴리스되는 표준 라이브러리 모듈은 사안별로 판단하여, 표준 라이브러리에 포함될 때 모듈 버전 번호를 포함할 수 있으며(MAY), 별도로 패키징될 때는 버전 번호를 포함해야 합니다(SHOULD).
  3. 모듈(또는 패키지)이 버전 번호를 포함하는 경우, 그 버전은 __version__ 속성으로 제공되어야 합니다(SHOULD).
  4. 네임스페이스 패키지 안에 있는 모듈의 경우, 해당 모듈은 __version__ 속성을 포함해야 합니다(SHOULD). 네임스페이스 패키지 자체는 자신의 __version__ 속성을 포함해서는 안 됩니다(SHOULD NOT).
  5. __version__ 속성의 값은 문자열이어야 합니다(SHOULD).
  6. 모듈 버전 번호는 PEP 386에 명시된 정규화된 버전 형식을 따라야 합니다(SHOULD).
  7. 모듈 버전 번호는 버전 관리 시스템이 제공하는 리비전 번호나 의미가 다른 그 밖의 버전 번호(예: 기반 라이브러리의 버전 번호)를 포함해서는 안 됩니다(SHOULD NOT).
  8. 기존 distutils setup.py 파일의 version 속성이나 PEP 345 Version 메타데이터 필드는 __version__ 필드로부터 도출되거나, 반대로 __version__ 필드가 이들로부터 도출되어야 합니다(SHOULD).

예시

서드파티 패키지에서 버전 번호 가져오기:

>>> import bzrlib
>>> bzrlib.__version__
'2.3.0'

독립형 모듈로도 배포되는 표준 라이브러리 패키지에서 버전 번호 가져오기:

>>> import email
>>> email.__version__
'5.1.0'

네임스페이스 패키지의 버전 번호:

>>> import flufl.i18n
>>> import flufl.enum
>>> import flufl.lock

>>> print flufl.i18n.__version__
1.0.4
>>> print flufl.enum.__version__
3.1
>>> print flufl.lock.__version__
2.1

>>> import flufl
>>> flufl.__version__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute '__version__'
>>>

도출하기

모듈 버전 번호는 최소 두 곳에, 때로는 그보다 더 많은 곳에 나타날 수 있습니다. 예를 들어 이 PEP에 따르면, 버전 번호는 모듈의 __version__ 속성을 통해 프로그래밍 방식으로 얻을 수 있습니다. 기존 distutils setup.py 파일에서는 setup() 함수가 version 인자를 받고, distutils2 setup.cfg 파일에는 version 키가 있습니다. 버전 번호는 PEP 345 메타데이터에도 들어가야 하며, 가급적 sdist 아카이브를 빌드할 때 들어가는 것이 좋습니다. 모듈 작성자가 버전 번호를 한 번만 지정하고, 나머지 모든 용도는 이 단일 정의로부터 도출되도록 하는 것이 바람직합니다.

이는 여러 가지 방법으로 할 수 있으며, 그중 몇 가지를 아래에 간략히 소개합니다. 이 방법들은 오로지 예시를 위해 포함한 것이며, 결정적이거나 완전하거나 모든 경우를 포괄하려는 의도는 없습니다. 다른 접근 방식도 가능하며, 아래에 포함된 방법 중 일부는 특정 상황에서 사용할 수 없게 만드는 제약이 있을 수 있습니다.

Elle이 자신의 모듈 파일 elle.py에 이 속성을 추가한다고 가정합시다:

__version__ = '3.1.1'

기존 distutils

기존 distutils에서 setup.py의 setup() 함수에 버전 문자열을 추가하는 가장 간단한 방법은 다음과 같이 하는 것입니다:

from elle import __version__
setup(name='elle', version=__version__)

그러나 PEP 작성자의 경험에 따르면, 모듈이 2to3 프로그램을 통한 Python 3 자동 변환을 사용하는 경우처럼 이 방법이 실패하는 경우가 있습니다(elle 모듈이 변환되기 전에 setup.py가 Python 3로 실행되기 때문입니다).

그런 경우에는 __version__을 임포트하는 대신 파일에서 파싱하는 짧은 코드를 작성해도 그다지 더 어렵지 않습니다. 너무 자세히 설명하지는 않겠지만, distutils2 같은 모듈이 파일에서 버전 문자열을 파싱하는 방법을 제공할 가능성이 높습니다. 예를 들면 다음과 같습니다.:

from distutils2 import get_version
setup(name='elle', version=get_version('elle.py'))

Distutils2

distutils2 스타일의 setup.cfg는 선언적이므로, 임포트를 통해서든 파싱을 통해서든 __version__ 속성을 추출하는 코드를 전혀 실행할 수 없습니다.

distutils-sig [9]와 협의하여 두 가지 방안을 제안합니다. 두 방안 모두 버전 번호를 파일에 담고, 그 파일을 setup.cfg에 선언하는 방식입니다. 파일의 전체 내용이 버전 번호인 경우에는 version-file 키를 사용합니다:

[metadata]
version-file: version.txt

버전 번호가 Python 코드 파일처럼 더 큰 파일 안에 들어 있어서 버전을 추출하려면 파일을 파싱해야 하는 경우에는 version-from-file 키를 사용합니다:

[metadata]
version-from-file: elle.py

콜론 뒤에 지정된 파일에 대해 위에서 설명한 것과 비슷한 파싱 방법을 수행합니다. 이를 수행하는 정확한 방법은 적절한 distutils2 개발 포럼에서 논의할 것입니다.

다른 방안으로는 버전 번호를 setup.cfg에만 정의하고, pkgutil 모듈 [8]을 사용하여 프로그램에서 버전 번호를 사용할 수 있게 하는 방법이 있습니다. 예를 들어 elle.py에서는 다음과 같습니다.:

from distutils2._backport import pkgutil
__version__ = pkgutil.get_distribution('elle').metadata['version']

PEP 376 메타데이터

PEP 376은 정적 메타데이터에 대한 표준을 정의하지만, 이 메타데이터가 생성되는 과정은 설명하지 않습니다. 도출된 버전 정보는 설치 시점이 아니라 빌드 시점에 PEP 376 .dist-info 메타데이터에 기록되는 것이 매우 바람직합니다. 이렇게 하면 코드가 설치되지 않은 상태에서도 메타데이터를 인트로스펙션에 사용할 수 있습니다.

참고 문헌