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

Python 개선 제안 한국어 번역

PEP 413 – Python 표준 라이브러리의 더 빠른 발전

Author:
Alyssa Coghlan <ncoghlan at gmail.com>
Status:
Withdrawn
Type:
Process
Created:
24-Feb-2012
Post-History:
24-Feb-2012, 25-Feb-2012

Table of Contents

번역·라이선스 안내

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

PEP 철회

PEP 453이 수락되어 대부분의 새로운 Python 사용자가 기본적으로 pip을 사용할 수 있게 되었으므로, 새 모듈이 충분히 성숙하기 전에 표준 라이브러리에 추가해야 한다는 압박이 줄어들 것으로 기대합니다.

또한 지난 몇 년 동안 표준 라이브러리 패키지와 동등한 패키지를 Python 패키지 색인에서도 제공하고, 그 패키지가 이전 버전의 Python까지 지원하는 모델이 점점 더 많이 사용되었습니다.

이 두 가지 변화와 Python 3.4 릴리스 주기 전반에 걸친 참여 수준을 고려할 때, PEP 작성자는 표준 라이브러리 개발 프로세스를 이처럼 근본적으로 바꾸는 것이 더 이상 적절하지 않다고 판단합니다.

초록

이 PEP는 표준 라이브러리에 별도의 버전 관리 체계(기존 언어 버전 관리 체계와 구별되지만 그와 연결된 체계)를 도입할 것을 제안합니다. 이 체계를 통해 핵심 언어 정의의 현재 변경 속도는 유지하면서(또는 오히려 늦추면서) Python 표준 라이브러리를 더 빠르게 릴리스할 수 있습니다.

PEP 407과 마찬가지로, 이 PEP는 더 넓은 커뮤니티가 적응할 시간을 주는 신중한 변화와, 현재 릴리스 주기로는 감당할 수 없을 만큼 빠르게 발전하는 외부 영향에 보조를 맞추는 것 사이의 현재 균형을 조정하는 것을 목표로 합니다(이 문제는 웹 기술과 관련된 표준 라이브러리 요소에서 특히 두드러집니다).

그러나 이 PEP는 PEP 407보다 목표가 더 보수적입니다. 빨라진 개발 속도를 내장 인터페이스와 표준 라이브러리 인터페이스에만 한정하고, 언어 문법과 버전 번호 체계, CPython 바이너리 API와 바이트코드 형식 같은 다른 요소의 변경 속도에는 영향을 주지 않으려 합니다.

근거

PEP 407의 개요를 인용하면 다음과 같습니다:

오픈 소스 프로젝트의 릴리스 주기를 정하는 것은 서로 모순되는 제약 조건들을 조율해야 하는 섬세한 작업입니다. 그 제약 조건으로는 개발 인력, 릴리스 관리 자원봉사자의 확보, 사용자와 서드파티 패키저의 유지 보수 용이성, 새로운 기능(및 동작 변경)의 신속한 제공, 새로운 기능이나 동작 변경을 끌어들이지 않는 버그 수정의 제공이 있습니다.

현재 릴리스 주기는 보수적인 쪽으로 치우쳐 있습니다. 이 주기는 반응성보다 안정성을 중시하는 사람들에게는 적합합니다. 이 PEP는 장기 지원 버전이라는 개념을 도입하여, Python의 트레이드마크가 된 안정성을 유지하면서도 기능을 더 유연하게 릴리스하려는 시도입니다.

저는 표준 라이브러리의 현재 릴리스 주기가 일부 핵심 프로그래밍 분야(구체적으로 웹 프로토콜과 데이터베이스, 템플릿, 직렬화 형식을 포함한 관련 기술)의 변화 속도에 효과적으로 대응하기에는 너무 느리다는 PEP 407 작성자들의 의견에 동의합니다.

그러나 6개월마다 바이너리 호환성이 깨질 수 있는 CPython 전체 릴리스를 내놓자는 PEP 407의 제안 방식이 더 넓은 Python 생태계에 지나치게 큰 부담을 준다고 생각하기 때문에, 저는 이 경쟁 PEP를 작성했습니다.

현재 CPython 릴리스 주기에서는 주요 바이너리 확장 모듈의 배포자들이 CPython 브랜치가 “보안 수정 전용” 모드에 들어간 뒤에도 해당 Python 릴리스를 지원하는 경우가 많습니다(예를 들어 Twisted는 현재 2.5, 2.6, 2.7용 바이너리를 배포하고, NumPy와 SciPy는 이 세 버전과 함께 3.1과 3.2를 지원하며, PyGame은 여기에 2.4 바이너리 릴리스를 더하고, wxPython은 2.6과 2.7용으로 32비트와 64비트 바이너리를 모두 제공하는 식입니다).

CPython이 릴리스 속도를 세 배(또는 그 이상)로 높인다면, 그 라이브러리들의 개발자(이들 중 상당수는 CPython보다도 자원이 더 부족합니다)는 달갑지 않은 선택에 직면하게 됩니다. 스스로 더 빠른 릴리스 주기를 채택하거나(PyGame의 경우 동시에 최대 18개의 바이너리 릴리스가 필요합니다!), 이전 Python 버전 지원을 더 빨리 중단하거나, 아니면 사용자들에게 CPython LTS 릴리스만 사용하라고 안내해야 합니다(이렇게 되면 애초에 CPython 릴리스 주기를 앞당긴 의미가 완전히 사라집니다).

마찬가지로, Python을 위한 여러 지원 도구(예: 문법 강조 도구)는 언어 수준의 변경을 따라잡는 데 상당한 시간이 걸릴 수 있습니다.

문화적 차원에서도 Python 커뮤니티는 Python 버전 번호가 갖는 특정한 의미에 익숙해져 있습니다. 버전 번호는 폐지 기간, 지원 기간 등 온갖 것과 연결되어 있습니다. PEP 407은 그러한 방침이 실제로 왜 필요한지에 대한 설득력 있는 근거를 제시하지 않은 채(다른 모든 사람을 희생시켜 CPython 코어 개발자의 삶을 조금 더 편하게 만드는 것 정도를 제외하면) 이 집단적 지식을 모두 내던지자고 제안합니다.

그러나 변경 속도를 높이려는 주된 근거(즉 웹 프로토콜과 관련 기술을 더 시의적절하게 지원하는 것)로 돌아가 보면, 이를 위해서는 표준 라이브러리 변경만 필요하다는 점을 알 수 있습니다. 이는 새로운 릴리스 주기의 영향을 받는 CPython의 부분을 명시적으로 한정하고 나머지 부분은 현재의 더 완만한 속도로 발전하도록 둔다면, 더 넓은 커뮤니티에 미치는 부정적인 영향의 상당 부분(어쩌면 대부분)을 피할 수 있다는 뜻입니다.

제안

이 PEP는 새로운 종류의 CPython 릴리스인 “표준 라이브러리 릴리스”의 도입을 제안합니다. PEP 407과 마찬가지로, 이로써 CPython에는 세 종류의 릴리스가 생깁니다:

  • 언어 릴리스: “x.y.0”
  • 유지보수 릴리스: “x.y.z” (z > 0인 경우)
  • 표준 라이브러리 릴리스: “x.y (xy.z)” (z > 0)

이 방식에서는 한정자 없는 버전 참조(예: “3.3”)가 항상 그에 대응하는 가장 최근의 언어 릴리스나 유지보수 릴리스를 가리킵니다. 이 표기는 한정어 없이 표준 라이브러리 릴리스를 가리키는 데 결코 사용되지 않습니다(적어도 python-dev에서는 그렇습니다. 물론 우리는 모범을 보일 수 있을 뿐, 나머지 Python 생태계가 이를 따르도록 강제할 수는 없습니다).

언어 릴리스는 지금처럼 Python 언어 정의의 새 버전으로서, CPython 인터프리터와 Python 표준 라이브러리의 새 버전과 함께 계속 제공됩니다. 따라서 언어 릴리스에는 다음 변경 사항 중 일부 또는 전부가 포함될 수 있습니다:

  • 새로운 언어 문법
  • 새로운 표준 라이브러리 변경 사항(아래 참조)
  • 새로운 폐지 경고
  • 이전에 폐지된 기능의 제거
  • 생성되는 바이트코드의 변경
  • AST의 변경
  • 컴파일 도구 체인에 대한 그 밖의 중요한 변경
  • 핵심 인터프리터 평가 루프의 변경
  • C ABI의 바이너리 비호환 변경(단, PEP 384 안정 ABI는 여전히 유지되어야 합니다)
  • 버그 수정

유지보수 릴리스도 지금과 마찬가지로 계속 제공되며, 해당 언어 릴리스의 버그 수정으로 엄격히 제한됩니다. 새로운 기능이나 급진적인 내부 변경은 허용되지 않습니다.

새로운 표준 라이브러리 릴리스는 각 유지보수 릴리스와 병행하여 제공되며, 표준 라이브러리 버전을 나타내는 새로운 버전 식별자가 붙습니다. 표준 라이브러리 릴리스에는 다음 변경 사항이 포함될 수 있습니다:

  • 순수 Python 모듈의 새로운 기능
  • C 확장 모듈의 새로운 기능(PEP 399 호환성 요구 사항을 따름)
  • 언어 내장 기능의 새로운 기능(C ABI가 영향을 받지 않는 경우에 한함)
  • 해당 유지보수 릴리스의 버그 수정

표준 라이브러리 버전 식별자는 Python 언어 릴리스의 주 버전 번호와 부 버전 번호를 하나의 두 자리 숫자로 합친 다음, 순차적인 표준 라이브러리 버전 식별자를 덧붙여 구성합니다.

릴리스 주기

유지보수 릴리스가 만들어지면 실제로는 두 개의 새로운 Python 버전이 python.org에 게시됩니다(2013년 2월로 예정된 첫 번째 3.3 유지보수 릴리스를 예로 들면 다음과 같습니다).:

3.3.1       # Maintenance release
3.3 (33.1)  # Standard library release

다시 6개월 뒤에는 다음 3.3 유지보수 릴리스가 또다시 새로운 표준 라이브러리 릴리스와 함께 제공됩니다.:

3.3.2       # Maintenance release
3.3 (33.2)  # Standard library release

이번에도 표준 라이브러리 릴리스는 이전 언어 릴리스와 바이너리 호환되며, Python 수준에서 추가 기능을 제공할 뿐입니다.

마지막으로, 3.3 릴리스로부터 18개월 뒤에는 마지막 3.3 유지보수 릴리스 및 표준 라이브러리 릴리스와 거의 같은 시기에 새로운 언어 릴리스가 제공됩니다.:

3.3.3       # Maintenance release
3.3 (33.3)  # Standard library release
3.4.0       # Language release

이후 3.4 릴리스 주기도 3.3과 비슷한 패턴을 따릅니다.:

3.4.1       # Maintenance release
3.4 (34.1)  # Standard library release

3.4.2       # Maintenance release
3.4 (34.2)  # Standard library release

3.4.3       # Maintenance release
3.4 (34.3)  # Standard library release
3.5.0       # Language release

프로그램을 통한 버전 식별

새로운 버전 정보를 프로그램에서 확인할 수 있도록, 이 PEP는 기반 인터프리터 버전과 별도로 새로운 표준 라이브러리 버전을 기록하는 새로운 sys.stdlib_info 속성을 추가할 것을 제안합니다. 최초의 Python 3.3 릴리스를 예로 들면 다음과 같습니다.:

sys.stdlib_info(python=33, version=0, releaselevel='final', serial=0)

이 정보는 sys.version 문자열에도 포함됩니다.:

Python 3.3.0 (33.0, default, Feb 17 2012, 23:03:41)
[GCC 4.6.1]

보안 수정 및 그 밖의 “주기 외” 릴리스

유지보수 릴리스에서 주기 외 릴리스(예를 들어 보안 문제를 수정하거나 새 릴리스의 치명적인 버그를 해결하기 위한 릴리스)를 처리하는 절차는 현재와 같습니다. 즉, 마이너 버전 번호를 올리고, 필요한 버그 수정과 이전 릴리스 이후 커밋된 다른 모든 버그 수정을 반영한 새 릴리스를 만듭니다.

표준 라이브러리 릴리스의 절차도 본질적으로 같습니다. 다만 표준 라이브러리 릴리스에는 버그 수정뿐 아니라 새 기능도 포함될 수 있으므로, 해당 “What’s New?” 문서를 릴리스에 맞춰 다소 정리해야 할 수 있습니다.

사용자 시나리오

위에서 제안한 버전 관리 방식은 이 방식이 채택될 경우 마주칠 가능성이 높은 여러 사용자 시나리오에 바탕을 두고 있습니다. 각 경우에 대해 현 상태(즉, 느린 릴리스 주기), 이 PEP의 버전 관리 방식, 그리고 PEP 407에서 제안한 자유분방한 마이너 버전 번호 방식 모두에 대한 시나리오를 설명합니다.

결론부터 말씀드리면, 별도의 버전 번호를 사용하는 이유는 거의 모든 시나리오에서 중요한 번호가 표준 라이브러리 버전이 아니라 언어 버전이기 때문입니다. 대부분의 사용자는 표준 라이브러리 버전 번호가 존재한다는 사실조차 신경 쓸 필요가 없습니다. 이 번호가 중요한 것으로 확인된 두 가지 경우에도, 두 종류의 번호를 하나의 순서에 섞어 넣고 그 통합된 순서의 일부 번호에 특별하다는 표시를 붙이는 것보다 별도의 번호로 제공하는 편이 실제로 더 명확하고 명시적입니다.

2013년 3월에 python.org에서 Python을 내려받는 초보 사용자

현 상태: 3.3과 2.7 중에서 선택해야 합니다

이 PEP: 3.3 (33.1), 3.3, 2.7 중에서 선택해야 합니다.

PEP 407: 3.4, 3.3 (LTS), 2.7 중에서 선택해야 합니다.

판정: 장기 지원(Long Term Support) 릴리스의 의미를 설명하는 일은 제안된 표준 라이브러리 릴리스 버전 번호의 의미를 설명하는 일과 복잡한 정도가 비슷합니다. 이 경우는 무승부로 봅니다.

서드파티 문서가 최신인지 판단하려는 초보 사용자

현 상태: 마이너 버전 차이는 18~24개월의 언어 발전을 나타냅니다

이 PEP: 언어 코어는 현 상태와 같으며, 표준 라이브러리 버전 번호는 6개월의 표준 라이브러리 발전을 나타냅니다.

PEP 407: 마이너 버전 차이는 3.3까지는 18~24개월의 언어 발전을 나타내고, 그 이후로는 6개월의 언어 발전을 나타냅니다.

판정: 언어 변경과 폐지는 표준 라이브러리에 새 기능을 추가하는 것보다 서드파티 문서의 정확성에 훨씬 더 큰 영향을 미칠 수 있으므로, 저는 이를 이 PEP 방식의 승리로 판단합니다.

확장 모듈 바이너리 릴리스를 찾는 초보 사용자

현 상태: 실행 중인 Python 버전에 해당하는 바이너리를 찾으십시오.

이 PEP: 현 상태와 같습니다.

PEP 407 (전체 릴리스): 현 상태와 같지만, 해당 바이너리 버전이 없을 가능성이 더 높습니다(또는 있더라도 훨씬 더 긴 대안 목록 가운데에서 찾아야 합니다).

PEP 407 (ABI 갱신을 LTS 릴리스로 한정하는 경우): 모든 바이너리 릴리스 페이지에서 Python 3.3, 3.4, 3.5 모두 3.3 바이너리가 필요하다고 사용자에게 알려야 합니다.

판정: 이 경우는 이 PEP 체계의 명백한 승리로 봅니다. 이 경우 표준 라이브러리 버전은 사실상 관계가 없으므로(바이너리 확장 호환성만 중요합니다), 현재 상황에서 달라지는 것이 전혀 없습니다.

바이너리 릴리스를 만들지 결정하는 확장 모듈 작성자

현 상태: PEP 384 안정 ABI를 사용하지 않는 한, 마이너 버전 번호가 바뀔 때마다 새 바이너리 릴리스가 필요합니다.

이 PEP: 현 상태와 같습니다.

PEP 407 (전체 릴리스): 현 상태와 같지만, 이런 일이 훨씬 더 자주 생깁니다.

PEP 407 (ABI 갱신을 LTS 릴리스로 한정하는 경우): 결정하기 전에 먼저 새 릴리스가 LTS 릴리스인지 중간 릴리스인지 확인해야 합니다. LTS 릴리스라면 새 빌드가 필요합니다.

판정: 저는 이번에도 이 PEP의 방식이 명백히 우세하다고 봅니다. 이 문제의 최종 사용자 측면과 마찬가지로, 이 경우에도 표준 라이브러리 버전은 사실상 무관합니다. 그 정보를 별도의 번호로 분리하면 불필요한 혼란을 피할 수 있습니다.

Python 개발자가 폐지 경고(Deprecation Warning) 제거의 우선순위를 정하는 경우

현 상태: 폐지 경고를 발생시키는 코드는 마이너 버전 번호가 더 높은 Python 버전에서 실행된다는 보장이 없습니다.

이 PEP: 현 상태와 같습니다

PEP 407: 불명확합니다. 해당 PEP가 현재 이 점을 명시하지 않기 때문입니다. 폐지 주기가 LTS 릴리스와 연동된다고 가정하면, LTS가 아닌 릴리스로 업그레이드하는 것은 안전하지만 다음 LTS 릴리스로 업그레이드하려면 폐지된 구문을 사용하지 않아야 할 수도 있습니다.

판정: 이 시나리오에서도 표준 라이브러리 버전은 무관하므로, 이번에도 이 PEP의 방식이 명백히 우세합니다.

새로운 기능을 반영하는 대체 인터프리터 구현자

현 상태: 새 Python 버전은 드물게 나오지만, 표준 라이브러리 업데이트와 코어 언어 정의 및 인터프리터 변경이 뒤섞여 있습니다.

이 PEP: 통합하기 더 쉬운 표준 라이브러리 갱신이 이전 버전의 언어 정의와 명확하고 명시적으로 호환되는 형태로 더 자주 제공됩니다. 이는 대체 구현이 일단 Python 3.3을 따라잡고 나면, 표준 라이브러리 기능(특히 순수 Python 변경)이 나올 때마다 이를 훨씬 쉽게 통합할 수 있으며, 코어 컴파일 및 실행 구성 요소의 업데이트가 필요한 유일한 작업으로 마이너 버전 번호 업데이트만 남는다는 것을 의미합니다.

PEP 407 (전체 릴리스): 현재 상태와 같지만, 훨씬 더 자주 발생하게 됩니다.

PEP 407 (언어 갱신을 LTS 릴리스로 한정하는 경우): 불명확합니다. 해당 PEP가 현재 구체적인 개발 전략을 명시하지 않기 때문입니다. (이 PEP에서 제안하는 것처럼) 3.3 호환성 브랜치를 채택한다고 가정하면 결과는 거의 같겠지만, 버전 번호가 전달하는 신호는 약간 덜 명확해질 것입니다(특정 릴리스가 LTS 릴리스인지 아닌지 확인해야 하기 때문입니다).

판정: 앞의 몇몇 시나리오만큼 명확하지는 않지만, 저는 이 경우에도 이 PEP의 방식이 우세하다고 봅니다. 명시적인 것이 암시적인 것보다 낫습니다. 이 PEP의 방식은 평범한 릴리스 번호에 별도의 “LTS” 태그를 붙이는 대신 서로 다른 두 종류의 갱신을 명확하게 구분합니다. 특정 버전에 특별하다는 태그를 붙이는 것은 버전 관리 시스템 및 관련 자동화 도구와 소통하는 데는 훌륭하지만, 다른 사람에게 정보를 전달하는 방법으로는 형편없습니다.

최소 버전 의존성을 정하는 Python 개발자

현재 상태: 문서에서 “version added”나 “version changed” 표시를 찾아 sys.version_info와 비교합니다

이 PEP: 문서에서 “version added”나 “version changed” 표시를 찾습니다. “3.3”처럼 Python 버전만 적혀 있다면 sys.version_info와 비교하십시오. “3.3 (33.1)”처럼 표준 라이브러리 버전이 함께 적혀 있다면 sys.stdlib_info와 비교합니다.

PEP 407: 현재 상태와 같습니다

판정: 실제로 이 PEP의 방식을 쓰면 서드파티 라이브러리가 표준 라이브러리 기능을 얼마나 빨리 도입하는지를 더 명시적으로 드러낼 수 있습니다. 보수적인 프로젝트는 아마 의존성을 언어 버전에 고정하고 표준 라이브러리 릴리스에서 추가된 기능을 피할 것입니다. 빠르게 움직이는 프로젝트는 그 대신 특정 표준 라이브러리 버전에 대한 의존성을 선언할 수 있습니다. 하지만 PEP 407에는 현재 상태를 유지한다는 장점이 있으므로, 저는 이 경우를 (근소한 차이이기는 하지만) PEP 407의 우세로 판정합니다.

트래커 이슈를 재현하려는 Python 개발자

현 상태: 이미 제공되지 않았다면, 보고자에게 어떤 버전의 Python을 사용하고 있는지 물어보십시오. 보통 대화형 프롬프트에 표시되는 처음 두 줄이나 sys.version의 값을 알려 달라고 요청합니다.

이 PEP: sys.version이 표준 라이브러리 버전도 포함하도록 갱신되므로 현재 상태와 같습니다. 다만 추가적인 경우에 필요할 수 있습니다(사용자가 자신의 Python 버전을 밝힐 만큼은 알고 있었지만, 그것만으로는 결함을 재현하기에 충분하지 않았던 경우).

PEP 407: 현재 상태와 같습니다.

판정: PEP 407의 또 다른 근소한 승리입니다. 새로운 표준 라이브러리 버전은 사용자가 Python 라이브러리(또는 우리 자체 트래커에서 Python 자체)의 문제를 보고할 때 개발자에게 전달해야 할 수도 있는 추가 정보입니다. 하지만 이를 sys.version에 포함하므로 많은 결함 보고에 이미 이 정보가 들어가게 되며, 필요하면 요청하기도 쉽습니다.

보안 수정을 처리하는 CPython 릴리스 관리자

현재 상태: 보안 수정과 소스 관리에 있는 다른 모든 버그 수정을 포함하는 새 유지보수 릴리스를 만듭니다. 또한 보안 수정만을 위해 열려 있는 모든 브랜치에 대해 소스 릴리스를 만듭니다.

이 PEP: 유지보수 브랜치에 대해서는 현재 상태와 같습니다. 또한 새 표준 라이브러리 릴리스를 만듭니다(보안 수정과 함께 새 기능을 포함할 수도 있습니다). 보안 브랜치에 대해서는 이전 유지보수 브랜치와 표준 라이브러리 업데이트 브랜치 모두에 대해 소스 릴리스를 만듭니다.

PEP 407: 유지보수 브랜치와 보안 브랜치에 대해서는 현재 상태와 같지만, LTS가 아닌 릴리스의 보안 수정을 어떻게 처리할지는 현재 미해결 문제입니다.

판정: PEP 407이 이 시나리오를 실제로 다루도록 갱신되기 전까지는 이 PEP의 명백한 승리입니다.

영향

개발 주기에 미치는 영향

PEP 407과 마찬가지로, 이 PEP는 새 기능의 제공을 더 작은 단위로 나눕니다. 언어 릴리스에서 수많은 변경 사항이 한꺼번에 들어오는 대신, 각 언어 릴리스는 6개월 분량의 표준 라이브러리 변경 사항과 새 문법에 관련된 변경 사항으로 제한됩니다.

워크플로에 미치는 영향

이 PEP는 일반 워크플로에서 사용할 추가 브랜치 하나를 만들 것을 제안합니다. 3.3 릴리스 이후에는 다음 브랜치들이 사용됩니다:

2.7         # Maintenance branch, no change
3.3         # Maintenance branch, as for 3.2
3.3-compat  # New branch, backwards compatible changes
default     # Language changes, standard library updates that depend on them

새 기능을 작업할 때, 개발자는 그것이 표준 라이브러리 릴리스에 허용 가능한 변경인지 여부를 결정해야 합니다. 허용 가능하다면 3.3-compat에 체크인한 다음 default에 병합해야 합니다. 그렇지 않다면 default에 직접 체크인해야 합니다.

3.3-compat 브랜치에서 이루어진 모든 변경 사항의 “version added” 및 “version changed” 표시에는 언어 버전과 표준 라이브러리 버전을 모두 표기해야 합니다. 예를 들면 “3.3 (33.1)”과 같습니다.

default 브랜치에서 직접 이루어진 변경 사항은 평소처럼 “3.4”로만 표기합니다.

3.3-compat 브랜치는 3.3 유지보수 브랜치와 같은 시점에 일반 개발이 종료됩니다. 3.3-compat 브랜치는 3.3 유지보수 브랜치와 같은 기간 동안 보안 수정을 위해 열린 상태로 유지됩니다.

버그 수정 주기에 미치는 영향

버그 수정 워크플로에 미치는 영향은 새 기능 워크플로에 미치는 영향과 본질적으로 같습니다. 변경 사항이 default 브랜치에 도달하기 전에 거쳐야 할 브랜치가 하나 더 생깁니다.

유지보수 릴리스에서 심각한 버그가 발견되면, 문제를 해결하기 위해 새 유지보수 릴리스와 새 표준 라이브러리 릴리스를 만듭니다. 언어 버전과 표준 라이브러리 버전 모두 버전 번호의 마지막 부분이 증가합니다.

표준 라이브러리 릴리스에서 심각한 버그가 발견되었으나 관련 유지보수 릴리스에는 영향을 주지 않는 경우, 새 표준 라이브러리 릴리스만 만들고 표준 라이브러리의 버전 번호만 올립니다.

이러한 상황에서는 표준 라이브러리 릴리스에 버그 수정만 들어가는 것이 아니라 추가 기능이 포함될 수도 있다는 점에 유의하십시오. 새 기능이 섞이지 않은 버그 수정만 받기를 원하는 사람이라면 새 표준 라이브러리 릴리스를 사용하지 않고 이미 유지보수 릴리스에만 엄격하게 의존하고 있을 것이라고 가정합니다.

커뮤니티에 미치는 영향

PEP 407은 커뮤니티에 미치는 영향에 대해 다음과 같이 말합니다:

안정성을 중시하는 사람들은 그냥 LTS 릴리스에 맞추면 되며, 제안된 수치대로라면 LTS 릴리스는 (기간과 안정성 모두에서) 비슷한 지원 주기를 제공할 것입니다.

저는 이 주장이 완전히 틀렸다고 생각합니다. 현실은 그렇게 단순하지 않습니다. 오히려 서드파티 모듈과 프레임워크 개발자들은 새 릴리스 주기의 속도에 맞춰 바이너리 업데이트를 제공해야 한다는 압박을 받게 되고, 교사와 책 저자들은 Python의 “오래된” 버전만 다룬다는 불만(“3.3만 쓰시네요, 최신은 3.5인데요!”)을 듣게 되는 등의 일이 벌어질 것입니다.

마이너 버전 번호가 과거보다 3배 빠르게 올라가기 시작하면, (그러한 의견이 정당한지와 관계없이) 언어의 안정성에 대한 인식도 떨어질 것이라고 생각합니다.

빨라진 변경 속도를 표준 라이브러리로 한정하고 별도의 버전 번호로 명확하게 구분하면, 우리가 갑자기 커뮤니티의 나머지 구성원들에게 그들의 개발 속도를 세 배로 높이라고 요구하는 것이 아니라는 점을 알려 그들을 크게 안심시킬 수 있을 것이라고 생각합니다. 우리는 그저 다음 언어 릴리스를 위한 표준 라이브러리 업데이트를, 이전에 릴리스된 Python 버전과 하위 호환되는 변경 사항까지 포함해 다음 언어 정의 업데이트 때까지 모두 미루지 않고 6개월 단위로 나누어 내놓으려는 것뿐입니다.

PEP 407에 나열된 커뮤니티 이점은 적어도 표준 라이브러리에 관한 한 이 PEP에도 똑같이 적용됩니다:

반응성과 새 기능에 대한 접근을 중시하는 사람들은 (알파 버전이나 Mercurial 스냅숏을 설치하는 위험을 감수하지 않고도) 새 릴리스 주기에서 현재보다 훨씬 더 많은 가치를 얻을 것입니다.

새 기능이나 개선 사항에 기여하려는 사람들은 자신의 기여가 일반 사용자에게 더 빨리 제공된다는 것을 알기에 더 큰 동기를 얻을 것입니다.

더 빠른 릴리스 주기 덕분에 더 많은 사람이 언어 정의 변경을 제안하기보다 표준 라이브러리에 기여하는 데 집중하게 된다면, 저는 그것을 나쁜 일로 보지 않습니다.

뉴스 업데이트 처리

새로운 기능

“새로운 기능(What’s New)” 문서는 표준 라이브러리 릴리스용 문서와 언어 릴리스용 문서로 분리됩니다. 따라서 3.3 릴리스 주기 동안에는 다음과 같은 문서를 보게 됩니다:

  • Python 3.3의 새로운 기능
  • Python 표준 라이브러리 33.1의 새로운 기능
  • Python 표준 라이브러리 33.2의 새로운 기능
  • Python 표준 라이브러리 33.3의 새로운 기능

그리고 마지막으로 다음 언어 릴리스를 보게 됩니다:

  • Python 3.4의 새로운 기능

표준 라이브러리 릴리스를 신경 쓰지 않는 사용자를 위해, 3.4의 “새로운 기능” 문서는 3.3 시리즈의 각 표준 라이브러리 릴리스에 대한 “새로운 기능” 문서로 연결되는 링크를 제공합니다.

NEWS

NEWS 파일의 병합 충돌은 이미 골칫거리입니다. 이 PEP는 일반 워크플로에 추가 브랜치를 도입할 것을 제안하므로, 이 문제를 해결하는 일은 더욱 중요해집니다. Mercurial 페이즈가 어느 정도 도움이 될 수는 있겠지만, 문제를 완전히 없애는 것이 좋을 것입니다.

Barry Warsaw가 제안한 한 가지 방법은 Twisted [2]에서 사용하는 것과 비슷하게, 변경 사항마다 별도 파일을 두어 충돌이 생기지 않는 방식을 채택하는 것입니다.

현재 수동으로 갱신하는 NEWS 파일을 3.3.0 릴리스에 사용한다는 점을 고려하면, 이러한 접근 방식의 레이아웃은 한 가지 예로 다음과 같을 수 있습니다.:

Misc/
  NEWS  # Now autogenerated from news_entries
  news_entries/
    3.3/
      NEWS # Original 3.3 NEWS file
      maint.1/ # Maintenance branch changes
        core/
          <news entries>
        builtins/
          <news entries>
        extensions/
          <news entries>
        library/
          <news entries>
        documentation/
          <news entries>
        tests/
          <news entries>
      compat.1/ # Compatibility branch changes
        builtins/
          <news entries>
        extensions/
          <news entries>
        library/
          <news entries>
        documentation/
          <news entries>
        tests/
          <news entries>
      # Add maint.2, compat.2 etc as releases are made
    3.4/
      core/
        <news entries>
      builtins/
        <news entries>
      extensions/
        <news entries>
      library/
        <news entries>
      documentation/
        <news entries>
      tests/
        <news entries>
      # Add maint.1, compat.1 etc as releases are made

버전 정보를 디렉터리 계층 구조에 넣는 것이 꼭 필요하지는 않지만(NEWS 파일 제너레이터가 버전 이력에서 알아낼 수 있으므로), 사람이 서로 다른 버전을 순서대로 관리하기는 더 쉬워집니다.

버전 결합도 감소의 다른 이점

언어 릴리스 주기 늦추기

현재 릴리스 주기는 핵심 언어 정의와 C 확장 ABI를 안정적으로 유지하려는 요구와 새 기능(특히 표준 라이브러리 업데이트)을 사용자에게 더 빨리 제공하려는 요구 사이의 절충안입니다.

표준 라이브러리 릴리스 주기를 핵심 언어 정의의 릴리스 주기와 (어느 정도) 분리하면, 언어 정의의 변경 속도를 실제로 늦출 기회가 생깁니다. Python 3.2의 언어 모라토리엄은 큰 문제나 불만 없이 그 주기를 사실상 3년 이상으로 늦췄습니다(3.1: 2009년 6월, 3.3: 2012년 8월).

위에서 설명한 NEWS 파일 관리 방식은 사실 표준 라이브러리 릴리스를 더 자주 하는 동시에 언어 릴리스를 늦출 수 있는 유연성을 주도록 설계되었습니다.

간단한 예로, 3.3과 3.4 사이에 꼬박 2년을 둔다면 3.3 릴리스 주기는 다음과 같은 모습이 됩니다.:

3.2.4       # Maintenance release
3.3.0       # Language release

3.3.1       # Maintenance release
3.3 (33.1)  # Standard library release

3.3.2       # Maintenance release
3.3 (33.2)  # Standard library release

3.3.3       # Maintenance release
3.3 (33.3)  # Standard library release

3.3.4       # Maintenance release
3.3 (33.4)  # Standard library release
3.4.0       # Language release

제안된 브랜치 구조와 NEWS 항목 레이아웃의 장점은 3.4 릴리스 예정일 직전까지 이 결정을 내리지 않아도 된다는 점입니다. 그 시점에 3.4 릴리스를 연기하기로 결정하고, 3.3.3 유지보수 릴리스와 3.3 (33.3) 표준 라이브러리 릴리스 이후에도 3.3 및 3.3-compat 브랜치를 열어 두어 주기에 표준 라이브러리 릴리스를 하나 더 추가할 수 있습니다. 그 이후에는 6개월마다 표준 라이브러리 릴리스를 한 번 더 할지, 전체 언어 릴리스를 할지 선택할 수 있습니다.

표준 라이브러리 개발 속도 더 높이기

앞 절에서 언급했듯이, 이 PEP에서 제안하는 방식의 이점 중 하나는 언어 릴리스 주기를 표준 라이브러리 릴리스 주기와 대부분 분리한다는 점입니다. 표준 라이브러리를 3개월마다, 심지어 한 달에 한 번씩 갱신하더라도 언어 버전 번호 체계나 사람들이 느끼는 핵심 언어의 안정성에는 아무런 파급 효과가 없습니다.

Windows와 Mac OS X용 바이너리 설치 프로그램을 만드는 데 여러 수동 단계(수동 테스트 포함)가 필요하고, 안정 빌드봇이 양호하다고 표시한 버전만 받는 별도의 “<branch>-release” 트리가 없는 한 그러한 개발 속도는 현실적이지 않지만, 새로 제안된 버전 관리 방식을 검토할 때 염두에 둘 만한 유용한 기준입니다. 나중에 표준 라이브러리 릴리스를 6개월마다보다 더 빠르게 하고 싶어지면 어떻게 하겠습니까?

이러한 현실적인 문제가 언젠가 해결된다면, 이 PEP의 별도 표준 라이브러리 버전 관리 방식으로 대응할 수 있습니다. PEP 407에서 제안한 태그 붙은 버전 번호 방식으로는 그럴 수 없습니다(적어도 사용자에게 큰 혼란과 불확실성을 주지 않고는 불가능합니다).

기타 질문

왜 메이저 버전 번호를 사용하지 않습니까?

사실 가장 단순하고 논리적인 해결책은 major.minor.micro 버전 번호를 각각 언어 버전, 표준 라이브러리 버전, 유지보수 릴리스 버전에 대응시키는 것입니다.

그러면 Python 3.3.0 대신 Python 4.0.0을 릴리스하게 되며, 릴리스 주기는 다음과 같은 모습이 됩니다.:

4.0.0  # Language release

4.0.1  # Maintenance release
4.1.0  # Standard library release

4.0.2  # Maintenance release
4.2.0  # Standard library release

4.0.3  # Maintenance release
4.3.0  # Standard library release
5.0.0  # Language release

그러나 Python 2 -> Python 3 전환에서 계속되는 고통(그리고 원하는 릴리스 시리즈를 직접 가리키기 위한 python3 및 python2 심볼릭 링크 같은 관련 우회책) 때문에, 이 단순한 방안은 역사적인 이유로 실행 가능하지 않습니다.

이 단순한 방식이 동작하도록 만들 수 있는 한 가지 방법은 현재의 메이저 버전 번호와 마이너 버전 번호를 두 자리 메이저 버전 번호 하나로 직접 합치는 것입니다.:

33.0.0  # Language release

33.0.1  # Maintenance release
33.1.0  # Standard library release

33.0.2  # Maintenance release
33.2.0  # Standard library release

33.0.3  # Maintenance release
33.3.0  # Standard library release
34.0.0  # Language release

왜 네 부분으로 된 버전 번호를 사용하지 않습니까?

또 다른 단순한 버전 관리 방식은 기존 버전 관리 방식에 “표준 라이브러리” 버전만 추가하는 것입니다.:

3.3.0.0  # Language release

3.3.0.1  # Maintenance release
3.3.1.0  # Standard library release

3.3.0.2  # Maintenance release
3.3.2.0  # Standard library release

3.3.0.3  # Maintenance release
3.3.3.0  # Standard library release
3.4.0.0  # Language release

하지만 이 방식은 sys.version_info 구조체의 하위 호환성 제약 때문에 실현할 수 없습니다.

왜 날짜 기반 버전 관리 방식을 사용하지 않습니까?

이 PEP의 이전 버전에서는 표준 라이브러리에 날짜 기반 버전 관리 방식을 제안했습니다. 하지만 이러한 방식에서는 표준 라이브러리 릴리스의 보안 문제나 기타 치명적인 버그를 고치기 위한 주기 외 릴리스를 처리하기가 매우 어려웠습니다. 다음 단계를 거쳐야 했기 때문입니다.

  1. 릴리스 버전 번호를 이번 달 날짜로 변경합니다.
  2. What’s New, NEWS 및 문서가 새 릴리스 번호를 가리키도록 갱신합니다.
  3. 새 릴리스를 만드십시오.

이제 제안된 순차적 체계에서는 이러한 릴리스를 만들기 전에 What’s New 문서를 기껏해야 약간 정리하는 작업만 필요할 것입니다.

PEP 384로는 왜 충분하지 않습니까?

PEP 384는 CPython에 “안정 ABI(Stable ABI)”라는 개념을 도입했습니다. 이는 전체 C ABI 중 안정적으로 유지되는 것이 보장되는 제한된 부분 집합입니다. 안정 ABI를 대상으로 빌드된 확장은 동일한 바이너리로 이후의 모든 Python 버전을 지원할 수 있어야 합니다.

이는 새 프로젝트가 자신의 C 확장 모듈을 특정 CPython 버전에 지나치게 밀접하게 결합하지 않도록 하는 데 도움이 될 것입니다. 그러나 기존 모듈의 경우 안정 ABI로 이전하려면 상당히 많은 작업이 필요할 수 있습니다(특히 많은 클래스를 정의하는 확장 모듈이 그렇습니다). 개발 자원이 제한되어 있으므로, 이러한 변경에 들이는 시간은 모두 최종 사용자에게 더 직접적인 이점을 제공하는 기능 작업에 쓸 수도 있었던 시간입니다.

별도의 버전 관리에는 (위에서 설명한 것처럼) 서드파티 C 확장과의 바이너리 호환성 문제와 직접 관련되지 않은 다른 이점도 있습니다.

왜 표준 라이브러리 릴리스에서 C ABI에 대한 바이너리 호환 추가를 허용하지 않습니까?

CPython C ABI에 대한 추가는 표준 라이브러리 릴리스에서 허용해도 합리적이라는 주장도 가능합니다. 이렇게 하면 C 확장 작성자도 다른 패키지나 모듈 작성자와 마찬가지로 특정 언어 버전이나 표준 라이브러리 버전 중 어느 쪽에든 의존할 수 있는 자유를 얻게 될 것입니다.

현재 이 PEP는 인터프리터 버전을 언어 버전과 연관 짓고 있으며, 따라서 주요 인터프리터 변경(C ABI 추가 포함)을 언어 릴리스로 제한합니다.

내부적으로 일관된 또 다른 접근 방식은 인터프리터 버전을 표준 라이브러리 버전과 연결하고, 하위 호환성에 영향을 줄 수 있는 변경만 언어 릴리스로 제한하는 것입니다.

그러한 체계에서는 표준 라이브러리 릴리스에서 다음과 같은 변경이 허용됩니다:

  • 표준 라이브러리 업데이트
    • 순수 Python 모듈의 새 기능
    • C 확장 모듈의 새 기능(PEP 399 호환성 요구 사항을 따름)
    • 언어 내장 기능의 새 기능
  • 인터프리터 구현 업데이트
    • C ABI에 대한 바이너리 호환 추가
    • AST에 영향을 주거나 바이트코드 매직 넘버를 변경하지 않는 컴파일 도구 체인의 변경
    • 핵심 인터프리터 평가 루프의 변경
  • 대응하는 유지보수 릴리스의 버그 수정

그리고 언어 릴리스에서는 다음과 같은 변경이 허용됩니다:

  • 새로운 언어 문법
  • 표준 라이브러리 릴리스에서 허용되는 모든 업데이트
  • 새로운 폐지 경고
  • 이전에 폐지된 기능의 제거
  • AST의 변경
  • 매직 넘버 변경이 필요한, 생성되는 바이트코드의 변경
  • C ABI에 대한 바이너리 비호환 변경(단, PEP 384 안정 ABI는 여전히 유지되어야 합니다)

그런 접근 방식도 아마 작동하게 만들 수는 있겠지만, 이를 뒷받침할 설득력 있는 근거는 없어 보이며, 현재 이 PEP에서 설명하는 접근 방식이 더 단순하고 설명하기도 쉽습니다.

표준 라이브러리를 완전히 분리하지 않는 이유는 무엇입니까?

이따금 논의되는 개념 중 하나는 표준 라이브러리를 CPython 참조 구현으로부터 진정으로 독립시키자는 아이디어입니다.

제 개인적인 의견으로는, 실제로 그러한 변경을 하려면 많은 작업이 필요한 반면 얻는 이득은 거의 없을 것입니다. 표준 라이브러리가 없는 CPython은 쓸모가 없습니다(테스트 스위트는 고사하고 빌드 체인조차 실행되지 않습니다). 또한 독립적인 순수 Python 표준 라이브러리를 만들 수도 없습니다. 너무 많은 “표준 라이브러리 모듈”이 실제로는 각 인터프리터의 내부 세부 사항과 긴밀하게 연결되어 있기 때문입니다(예: 내장, weakref, gc, sys, inspect, ast).

이전 언어 릴리스와의 호환성을 유지하는 별도의 CPython 개발 브랜치를 만들고, 그 브랜치에서 별도의 표준 라이브러리 버전 번호로 식별되는 릴리스를 만들면, 별도의 표준 라이브러리 저장소가 주는 이점 대부분을 훨씬 적은 수고로 얻을 수 있을 것입니다.

감사의 글

이 논의를 시작해 준 PEP 407 저자들께 감사드리며, 이 PEP에서 제안한 내용에 대한 초기 논의를 함께해 준 해당 저자들과 Larry Hastings에게도 감사드립니다.

참고 문헌