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

Python 개선 제안 한국어 번역

PEP 605 – CPython을 위한 롤링 기능 릴리스 스트림

Author:
Steve Dower <steve.dower at python.org>, Alyssa Coghlan <ncoghlan at gmail.com>
Discussions-To:
Discourse thread
Status:
Rejected
Type:
Informational
Created:
20-Sep-2019
Python-Version:
3.9
Post-History:
01-Oct-2019, 06-Oct-2019, 20-Oct-2019

Table of Contents

번역·라이선스 안내

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

거부 공지

이 PEP는 PEP 602가 채택되면서 거부되었습니다. 알파와 베타 릴리스가 번갈아 나올 수 있다는 점은 지나치게 혼란스럽고, 릴리스 사이의 2년 주기는 지나치게 길다고 판단되었습니다.

초록

오랫동안 CPython의 명목상 기능 릴리스 주기는 “18~24개월마다”였으며, 최근 몇 년 동안은 꽤 일관되게 그 범위 중 “18개월” 쪽에 머물러 왔습니다. PEP 607은 이러한 주기 선택으로 인해 발생하는 문제들에 대한 공통 배경과 함께, 주기 변경을 제안할 때 고려해야 하는 몇 가지 위험도 설명합니다.

이 PEP의 제안은 CPython 사용자층이 서로 구별되지만 일부 겹치는 다음 두 그룹 중 하나를 스스로 선택할 수 있도록 하는 것을 목표로 합니다.

  • 24개월마다 발행되는 안정적인 기능 릴리스(및 이와 연관된 유지보수 릴리스 스트림)의 사용자, 그리고
  • 기존의 CPython 사전 릴리스 프로세스를 대체하는 새로운 롤링 릴리스 스트림의 얼리 어답터

이 제안의 일환으로, 베타 릴리스에 대한 사용 지침은 현재의 무조건적인 “프로덕션 용도로 사용하지 마십시오” 대신 “충분히 견고한 호환성 테스트 및 운영 모니터링 역량을 갖춘 환경에서만 프로덕션 용도로 적합합니다”로 바뀝니다.

마찬가지로, 알파 릴리스에 대한 지침도 단순히 “프로덕션 용도로 사용하지 마십시오”라고 하는 대신 “라이브러리 호환성 테스트와 ABI 호환 바이너리 아티팩트 생성을 위한 것입니다”라고 명시하도록 수정됩니다.

PEP 작성자들은 아래 제안 절에서 설명하는 대로 CPython의 사전 릴리스 관리 프로세스를 수정함으로써 이러한 결과를 달성할 수 있다고 믿습니다.

이 PEP는 또한 X.Y.0 릴리스의 빈도를 조정하여, 2년마다 8월에 각각의 새 릴리스 시리즈를 시작하도록(Python 3.8.0 릴리스로부터 약 2년 후인 2021년부터) 제안합니다.

향후 릴리스 일정 예시

이 제안에 따르면 Python 3.9.0a1은 2019년 10월의 Python 3.8.0 기준 기능 릴리스로부터 두 달 후인 2019년 12월에 릴리스됩니다.

전체 CPython ABI에 호환성을 깨는 변경이 더 이상 없다고 가정하면, 그로부터 2개월 후인 2020년 2월에 3.9.0b2 릴리스가 이어지고, 2021년 4월의 3.9.0b9까지 계속됩니다.

전체 CPython ABI에 호환성을 깨는 변경이 도입될 때마다, 그 변경을 포함하는 첫 번째 사전 릴리스는 알파 릴리스로 표시됩니다.

3.9.0rc1은 2021년 6월에, 3.9.0rc2는 2021년 7월에 발행되고, 이어서 정식 릴리스가 3.9.0으로 2021년 8월에 발행됩니다.

이 주기는 2021년 10월에 3.10.0a1의 발행(3.9.x 유지보수 브랜치 생성으로부터 4개월 후)과 함께 다시 시작됩니다.

유지보수 릴리스의 정확한 일정은 릴리스 팀이 결정하겠지만, 3.9.x의 유지보수 릴리스도 (3.10.0 베타 릴리스와 엇갈려) 격월로 이루어진다고 가정하면, 전체 릴리스 일정은 다음과 같습니다.

  • 2019-12: 3.9.0a1
  • 2020-02: 3.9.0b2
  • … 격월로 베타(또는 알파) 릴리스
  • 2021-04: 3.9.0b9
  • 2021-06: 3.9.0rc1 (기능 동결, ABI 동결, pyc 형식 동결)
  • 2021-07: 3.9.0rc2
  • 2021-08: 3.9.0
  • 2021-09: 3.9.1, 3.8.x (마지막 3.8.x 바이너리 유지보수 릴리스)
  • 2021-10: 3.10.0a1
  • 2021-11: 3.9.2
  • 2021-12: 3.10.0b2
  • … 베타(또는 알파) 릴리스와 유지보수 릴리스가 한 달씩 번갈아 계속됩니다.
  • 2023-04: 3.10.0b10
  • 2023-05: 3.9.11
  • 2023-06: 3.10.0rc1 (기능 동결, ABI 동결, pyc 형식 동결)
  • 2023-07: 3.10.0rc2, 3.9.12
  • 2023-08: 3.10.0
  • 2023-09: 3.10.1, 3.9.13 (마지막 3.9.x 바이너리 유지보수 릴리스)
  • 2023-10: 3.11.0a1
  • 2023-12: 3.11.0b2
  • … 등

3.9.0a5와 3.9.0a7 릴리스에서 전체 CPython ABI에 호환성을 깨는 변경을 도입한 사전 릴리스가 두 번 더 있었다고 가정하면, 전체 일정은 다음과 같습니다:

../_images/pep-0605-example-release-calendar.png

Figure 1. Impact of the pre-release process changes on the calendar.

이 모델에서는 활성 유지보수 브랜치가 항상 두세 개 존재하므로, 그 점에서는 현 상태가 유지됩니다. 가장 큰 차이점은 게시자에게 안정 유지보수 브랜치용 사전 빌드 바이너리뿐 아니라 동결 전 롤링 릴리스용 사전 빌드 바이너리도 제공하도록 권장하기 시작한다는 것입니다.

../_images/pep-0605-overlapping-support-matrix.png

Figure 2. Testing matrix in the 18-month cadence vs. the 24-month

전체 CPython ABI를 대상으로 하면서 동결 전 롤링 릴리스용 사전 빌드 바이너리를 제공하기로 한 패키지 게시자는 최소한 3.9.0a1 릴리스 이후에 새 휠 아카이브를 빌드해야 합니다. 이후의 알파 릴리스(예: 예시 일정의 3.9.0a5 또는 3.9.0a7 릴리스) 뒤에 갱신된 바이너리를 게시해야 하는지는 그 이후 릴리스의 ABI 호환성 단절에 실제로 영향을 받았는지에 따라 달라집니다.

현 상태와 마찬가지로, 최종 릴리스용 사전 빌드 바이너리를 제공하려는 모든 패키지 게시자는 ABI 동결일 이후에 새 휠 아카이브를 빌드해야 합니다. 현 상태와 달리 이 날짜는 첫 번째 릴리스 후보의 게시로 명확하게 표시되며, 게시자가 최종 릴리스를 준비할 수 있도록 두어 달의 여유를 줄 만큼 일찍 찾아옵니다.

향후 릴리스 공지 예시

이 PEP가 수락되면, 갱신된 사전 릴리스 관리 절차를 최종 사용자에게 알리는 주요 경로는 Python 3.9 What’s New 문서와 릴리스 공지 자체가 됩니다.

이 절에서는 그러한 목적으로 사용할 수 있는 글의 초안을 제공합니다.

제안하는 “What’s New in Python 3.9” 항목

다음 하위 절을 Python 3.9 What’s New 문서에 추가하고, Python 3.9의 각 알파 및 베타 공지에서 이 하위 절을 링크합니다.

PEP 605: 사전 릴리스 관리 절차 변경

PEP 605에 자세히 설명된 대로, 사전 릴리스 관리 절차가 갱신되어 충분히 견고한 통합 테스트 및 운영 모니터링 역량을 갖춘 환경에서 프로덕션 용도로 사용하기에 적합하다고 간주되는 베타 릴리스를 롤링 방식으로 연이어 내놓습니다.

이 새로운 롤링 모델에서는 알파 릴리스와 베타 릴리스가 하나로 합쳐진 “동결 전” 기간 안에 섞여 나옵니다. 알파 릴리스는 확장 모듈이나 임베딩 애플리케이션의 재컴파일이 필요할 수 있는 전체 CPython ABI의 호환성 단절을 나타내고, 베타 릴리스는 바로 앞 사전 릴리스와 완전한 바이너리 호환성이 있음을 나타냅니다.

이전 릴리스와 달리 3.9.0 알파 및 베타 릴리스용 사전 빌드 바이너리를 게시하는 것을 적극 권장합니다. 이제 전체 CPython ABI 동결 전에 확장 모듈을 빌드하고 로드할 때 새로운 사전 릴리스 ABI 플래그(“p”)가 설정되므로, 동결 전에 빌드된 확장 모듈은 모두 동결 후 인터프리터 빌드에서 무시되기 때문입니다.

전체 CPython ABI는 3.9.0rc1에서 동결되고 ABI 플래그에서 사전 릴리스 플래그가 제거되며, 3.9.0rc1은 3.9.0 최종 릴리스 2개월 전에 나올 예정입니다(정확한 목표 날짜는 PEP 596의 릴리스 일정을 참고하십시오).

애플리케이션 개발자는 롤링 릴리스 스트림으로 옮겨 가면 다음 안정 릴리스 전에 표준 라이브러리와 참조 인터프리터 개선의 설계 및 개발에 적극적으로 참여할 기회를 얻습니다. 또한 인터프리터 성능 개선이 안정 릴리스에 반영되기 최대 1년 이상 전부터 그 혜택을 누릴 기회도 얻습니다.

사전 빌드 휠 아카이브를 게시하는 라이브러리 개발자의 경우, 프로젝트가 이미 순수 Python 휠(py3-none-any로 태그됨)이나 안정 C ABI 대상 빌드(cp38-abi3-<platform> 또는 이전 CPython 3.x 릴리스의 동등한 태그로 태그됨)를 게시하고 있다면, 3.8 안정 릴리스 시리즈와 더불어 3.9.x 롤링 릴리스 스트림을 지원하기로 하는 데 특별한 조치가 필요하지 않습니다. 이 휠 아카이브는 이후의 3.9 안정 릴리스 시리즈에서도 그대로 사용할 수 있습니다.

전체 CPython ABI를 대상으로 빌드한 사전 빌드 휠 아카이브를 게시하는 라이브러리 개발자의 경우, 3.9 안정 릴리스 시리즈용 바이너리는 전체 CPython ABI 동결 이후에(즉, 3.9.0rc1 이상을 사용하여) 빌드해야 합니다.

이러한 라이브러리의 개발자도 3.9.0a1 릴리스(또는 그 이후의 베타 릴리스)를 대상으로 빌드하고 그 결과를 평소처럼 게시하여 롤링 릴리스 스트림을 지원하기로 할 수 있습니다.

이상적인 경우, 이 방식으로 빌드한 바이너리는 동결 전 마지막 릴리스까지 계속 동작합니다. 그러나 동결 전 기간 동안 전체 CPython C ABI의 변경이 프로젝트에 영향을 준다면, 관련 인터페이스를 변경한 알파 릴리스를 대상으로 영향을 받은 바이너리를 다시 빌드하는 유지보수 업데이트를 게시해야 합니다. 이러한 경우에는 프로젝트 메타데이터에 해당하는 Python-Requires 항목을 추가해야 합니다. 예를 들어 프로젝트가 3.9.0a5에서 도입된 ABI 변경의 영향을 받는다면, 추가할 Python-Requires 항목은 다음과 같습니다:

Python-Requires: >= "3.9.0b6"; python_version == "3.9" and full_python_version != "3.9.0a5"

(이 추가 메타데이터는 이전 변형의 ABI를 제공하는 3.9 시리즈의 이전 사전 릴리스에 업데이트된 버전이 설치되지 않도록 보장합니다)

애플리케이션 개발자와 마찬가지로, 롤링 릴리스 스트림을 지원하기로 한 라이브러리 개발자는 새로운 API 설계와 갱신된 API 설계가 안정 릴리스에서 여러 해 동안 고정되기 전에 (또는 안정 릴리스 시리즈에 잠정 API로 포함되기 전에) 피드백을 제공할 기회를 얻습니다.

3.9.0a1 릴리스의 공지문 예시

이것은 Python 3.9의 첫 번째 프리뷰 릴리스입니다. 알파 릴리스인 이 버전은 라이브러리 및 애플리케이션 호환성 테스트와 ABI 호환 바이너리 아티팩트 생성을 위한 것입니다. 프로덕션 환경에서 사용하는 것은 권장하지 않습니다.

사전 릴리스 관리 프로세스의 변경 사항

CPython은 새로운 사전 릴리스 관리 프로세스로 전환했습니다. 이 프로세스는 충분히 견고한 통합 테스트 및 운영 모니터링 역량을 갖춘 환경에서 프로덕션 용도로 적합하다고 여겨지는 베타 릴리스를 롤링 시리즈로 내놓도록 설계되었습니다. 자세한 내용은 Python 3.9 What’s New 문서(관련 절로 하이퍼링크됨)를 참조하십시오.

3.8과 비교한 3.9 시리즈의 주요 새 기능

Python 3.9의 많은 새 기능이 아직 계획 및 작성 중입니다. 이미 구현된 주요 새 기능과 변경 사항은 다음과 같습니다:

  • …
  • (동료 코어 개발자 또는 롤링 릴리스 스트림 사용자 여러분, 중요하다고 생각하는 기능이 이 목록에 빠져 있다면 <릴리스 관리자>에게 알려 주십시오.)

Python 3.9의 다음 사전 릴리스는 3.8.0b2가 될 예정이며, 현재 2020-02-02로 일정이 잡혀 있습니다.

3.9.0b2 릴리스의 공지문 예시

이것은 Python 3.9의 두 번째 프리뷰 릴리스입니다. 베타 릴리스인 이 버전은 바로 앞의 3.9.0a1 릴리스와 완전히 바이너리 호환됩니다. 충분히 견고한 통합 테스트 및 운영 모니터링 역량을 갖춘 환경에서만 프로덕션 용도로 사용할 것을 권장합니다.

(나머지는 3.9.0a1 공지와 같으며, 구현된 변경 사항을 반영하고 다음 예정 릴리스를 3.9.0b3으로 갱신합니다)

3.9.0a5(스트림 중간의 알파 릴리스)의 공지문 예시

이것은 Python 3.9의 다섯 번째 프리뷰 릴리스입니다. 알파 릴리스인 이 버전은 이전 3.9.0b4 릴리스와 바이너리 수준에서 완전히 호환되지 않습니다. 이 릴리스는 라이브러리 및 애플리케이션 호환성 테스트와 ABI 호환 바이너리 아티팩트 생성을 위한 것입니다. 프로덕션 환경에서 사용하는 것은 권장하지 않습니다.

3.9.0b4와 3.9.0a5 사이에 전체 CPython ABI에서 발생한 호환성을 깨는 변경 사항

  • PyObject 구조체에 새 필드 ob_example 추가
  • PyTypeObject 구조체에서 잠정 필드 tp_example 제거

롤링 릴리스 스트림을 지원하며 바이너리 호환성을 복원하기 위해 다시 빌드해야 하는 프로젝트는 업데이트된 릴리스에 다음 메타데이터를 추가해야 합니다:

Python-Requires: >= "3.9.0b6"; python_version == "3.9" and full_python_version != "3.9.0a5"

(나머지 내용은 3.9.0a1 공지와 같으며, 구현된 변경 사항을 반영하고 다음 예정 릴리스를 3.9.0b6으로 갱신합니다)

3.9.0rc1 공지문 예시

Python 3.9의 첫 번째 릴리스 후보입니다. 릴리스 후보로서 이번 릴리스는 이제 기능이 완성되었고, 전체 CPython ABI가 동결되었으며, ABI 호환성 플래그에서 사전 릴리스 마커가 제거되었습니다. 프로덕션 환경에서는 통합 테스트와 운영 모니터링 역량을 충분히 견고하게 갖춘 경우에만 사용할 것을 권장합니다.

3.9.0 최종 릴리스 준비

이제 전체 CPython ABI가 동결되었으므로, 해당 ABI를 대상으로 하는 라이브러리 개발자는 안정 3.9.x 시리즈용 바이너리를 빌드하여 게시하시기 바랍니다.

롤링 릴리스 스트림으로 테스트하지 않았던 애플리케이션 개발자는 릴리스 후보로 애플리케이션을 테스트하고, 포팅 가이드(관련 What’s New 절로 하이퍼링크)에 아직 언급되지 않은 호환성 회귀가 있으면 보고하시기 바랍니다.

두 번째 릴리스 후보는 2021-07-02에, 이어서 3.9.0 최종 릴리스는 2021-08-02에 예정되어 있습니다.

3.8과 비교한 3.9 시리즈의 주요 새 기능

이번 릴리스의 주요 새 기능과 변경 사항 중 일부는 다음과 같습니다:

  • …
  • (동료 코어 개발자 또는 롤링 릴리스 스트림 사용자 여러분, 중요하다고 생각하는 기능이 이 목록에 빠져 있다면 <릴리스 관리자>에게 알려 주십시오.)

동기

현재 CPython의 사전 릴리스 및 릴리스 관리 프로세스는 자동화된 지속적 통합과 운영 모니터링 시스템이 아직 비교적 미성숙하던 시대에 만들어졌습니다. 그 이후 많은 조직이 다른 코드 변경에서 감수하는 것보다 위험을 크게 늘리지 않고도 새로운 CPython 기능 릴리스를 도입할 수 있는 배포 모델을 채택했습니다. 가벼운 작업 특화 애플리케이션 컨테이너와 같은 새로운 배포 모델은 CI 파이프라인에서 애플리케이션과 언어 런타임을 결합한 다음, 나중에 전체 컨테이너 이미지가 갱신된 이미지로 교체될 때까지 둘을 함께 유지하는 일도 더 쉽게 만들어 줍니다.

이러한 더 넓은 환경의 변화에 비추어, PEP 602는 CPython 기능 릴리스 주기를 18-24개월마다에서 12개월마다로 앞당겨 Python 표준 라이브러리와 CPython 참조 인터프리터의 기능 전달 지연을 줄일 것을 제안했습니다.

안타깝게도 많은 조직에서 새 Python 릴리스를 도입하는 비용은 릴리스의 변경 사항 수가 줄어든다고 해서 자동으로 줄어들지 않습니다. 주된 비용은 발견된 문제를 해결하는 데서 발생하는 것이 아니라 문제를 탐색하는 데서 발생하기 때문입니다. 이 탐색에는 소프트웨어 시스템의 수동 테스트, 작성된 자료에 대한 사람의 검토, 그리고 필요한 시간이 Python 버전 간 변경 사항의 수가 아니라 기존 시스템의 규모에 비례하는 기타 활동이 포함될 수 있습니다.

서드파티 라이브러리 개발자에게 비용은 주로 널리 사용되는 서로 다른 Python 버전의 수와 관련됩니다. 이는 현재 어떤 릴리스가 여전히 python-dev에서 활발히 유지 관리되는지와 어떤 릴리스가 특정 재배포자가 제공하는 최신 버전인지의 조합에 영향을 받는 경향이 있습니다(Debian, Ubuntu LTS, RHEL/CentOS의 시스템 Python 버전이 특히 인기 있는 개발 대상입니다). 더 많은 Python 버전에 대해 테스트하는 기본적인 CI 비용 외에도, 널리 사용되는 변형이 많아질수록 결함 보고가 프로젝트의 실제 오류인지 아니면 보고한 사용자 환경의 문제인지 판단하기가 더 어려워질 수 있습니다.

PEP 602는 영향을 받는 조직과 프로젝트가 모든 릴리스를 도입하려 하지 말고 CPython 릴리스를 두 번 또는 세 번에 한 번씩만 도입하는 방식으로 전환하면 된다고 제안하지만, 이 방식은 해결해야 할 새로운 문제들을 낳습니다. 실무적인 문제(예: 사용자가 일상적으로 릴리스를 건너뛸 것으로 예상한다면 폐지 예고 기간이 둘 이상의 릴리스에 걸쳐야 합니다)와 문화적인 문제(예: 활발히 사용되는 버전의 수가 많아지면, 오픈 소스 라이브러리 유지 관리자가 자신은 사용하지 않는 Python 버전에서만 발생하는 버그 보고를 받을 가능성이 훨씬 높아집니다)가 모두 여기에 해당합니다.

PEP 598은 이 PEP 작성자 중 한 명이 기능 전달 지연을 줄이기 위한 대안적 방식을 제안하려 한 첫 시도였습니다. 이 방식은 의미 기반 버전 관리(semantic versioning) 스타일의 정책을 채택하여, 릴리스 시리즈가 기능 완료 상태에 도달할 때까지 해당 시리즈 안에서 하위 호환성을 유지하는 기능을 점진적으로 제공할 수 있도록 했습니다. 그 변형안도 현재의 릴리스 관리 모델에 충분히 만족하는 최종 사용자에게 눈에 보이는 변화를 강요한다는 바람직하지 않은 결과를 여전히 안고 있었습니다.

이 PEP는 PEP 598과 PEP 602가 공통된 결함을 지니고 있다고 봅니다. 두 제안 모두 단일 릴리스 모델이라는 제약 안에서 서로 상당히 다른 두 대상 집단의 요구를 충족시키려 하며, 그 결과 설계 요구 사항이 서로 충돌하고 충돌하는 요구 사항 사이에서 어색한 절충이 필요해집니다. 이 PEP의 제안은 두 개의 별개의 프로덕션 수준 릴리스 스트림을 만들 것을 제안함으로써 그 결함을 피하고자 합니다. 기존 릴리스 스트림은 대체로 그대로 두고, 새 릴리스 스트림은 기능 전달 지연 감소로 가장 큰 이익을 얻을 대상 집단에 맞춥니다.

이 제안의 목표

이 PEP의 제안은 다음과 같은 핵심 가정에서 출발합니다:

  • Python 사용자의 대다수는 새로운 언어 및 런타임 수준 기능을 적극적으로 요구하지 않으며, 이전에 사용하던 버전이 더 이상 지원되지 않을 때, Python 제공자가 기본으로 더 새로운 버전을 제공하도록 전환할 때, 또는 관심 있는 변경 사항이 충분히 쌓여 업그레이드할 설득력 있는 이유가 생겼을 때에만 업그레이드합니다.
  • 새 릴리스를 사용하는 많은 사용자에게 새 릴리스 도입 시 발생하는 작업의 상당 부분은 언어 수준의 호환성 문제가 아니라 구성 요소 설치 수준의 호환성 문제(즉, 파일 이름과 설치 경로 변경)에서 비롯됩니다.
  • Python 사용자 기반 중 일부는 적어도 일부 사용 사례에서 프로덕션 환경에 바로 쓸 수 있는 사전 릴리스(Windows Insider나 Debian testing 빌드와 유사한)를 실행할 의향이 있다는 것

이 PEP 제안의 핵심은 CPython 사전 릴리스 프로세스를 변경하여 점진적인 기능 릴리스를 정기적인 주기로 롤링 스트림 형태로 만들어 내고, 그 빌드 대부분이 적절히 관리되는 프로덕션 시스템에서 사용하기에 적합할 만큼 충분한 수준의 안정성을 제공하도록 보장하는 것입니다.

이 제안은 이러한 접근 방식을 채택하여 거의 모든 Python 사용자와 기여자에게 더 나은 결과를 제공하는 것을 목표로 합니다:

  • 새로운 점진적 기능 릴리스 스트림의 사용자는 사전 릴리스 단계를 대상으로 삼아 PEP 602에서 제안한 연간 주기보다도 기능 제공 지연 시간을 더 줄일 수 있습니다;
  • 새로운 기능을 개발하는 코어 개발자에게는 사전 릴리스의 빈도와 채택률이 높아져 사전 릴리스 피드백 주기가 개선될 것입니다;
  • 기존 릴리스 스트림의 사용자에게는 사전 릴리스 기간 동안 채택률이 높아지고 피드백 주기가 개선된 결과로, 첫 X.Y.0 릴리스 시점에 기능이 더 성숙하고 생태계의 준비 수준도 더 높아질 것입니다;
  • Python 라이브러리 유지 관리자에게는 연속적인 사전 릴리스 스트림이 현재의 사전 릴리스 관리 절차보다 더 많은 기회를 제공하여, 설계 문제가 정식 안정 릴리스에 포함되기 전에 이를 발견하고 해결할 수 있기를 기대합니다; 그리고
  • 대체 Python 구현의 개발자에게는 연속적인 사전 릴리스 스트림이 확장 모듈 작성자가 전체 CPython ABI에서 Python 안정 ABI로 이전할 추가 동기가 될 수 있으며, 이는 전체 CPython C API를 에뮬레이트하지 않는 구현과 호환되는 생태계의 범위를 넓히는 데에도 도움이 됩니다.

다만, 이 제안의 모든 결과가 더 넓은 Python 생태계의 모든 구성원에게 이로운 것은 아니라는 점을 인정합니다:

  • Python 라이브러리 유지 관리자에게는 이 PEP와 PEP 602 모두 더 빠른 릴리스 주기를 지원하라는 사용자 압력으로 이어질 가능성이 높습니다. 이 PEP는 어떤 사전 릴리스가 전체 CPython C ABI를 깨뜨릴 수 있는 변경을 포함하는지 명확히 표시하여 이를 완화하려 하고, PEP 602는 정식 릴리스 사이의 최소 간격을 12개월로 유지하여 이를 완화하려 하지만, 이 단점을 완전히 없애는 것은 불가능합니다;
  • 서드파티 확장 모듈 유지 관리자에게는 이 PEP와 PEP 602 모두 새 버전이 나오자마자 그 버전에서 동작하는 휠 아카이브를 제공하기 위해 안정 ABI 지원을 시작하라는 사용자 압력으로 이어질 가능성이 높습니다. 이것이 전체적으로 부정적인지 여부는 그 요청이 그들에게 어떤 방식으로 전달되는지에 따라 달라질 것입니다(연속적인 동결 전 릴리스 지원에 관심 있는 개발자가 해당 프로젝트에 정중하게 기여하는 형태로 요청이 들어온다면 긍정적일 수도 있습니다);
  • 미리 빌드된 휠 아카이브의 제공 여부에 의존하는 기존 릴리스 스트림의 일부 사용자에게는 12개월마다 새 릴리스를 채택하는 것이 받아들일 만한 속도 증가일 수 있지만, 과거 18~24개월 주기 중 24개월 쪽으로 일관되게 옮겨 가는 것은 최근 릴리스에 사용된 18개월 주기에 비해 바람직하지 않은 속도 감소가 될 것입니다. 이 제안이 이러한 사용자에게 전체적으로 부정적일지는, 다가오는 안정 릴리스의 API와 ABI가 동결될 때까지 기다리지 않고 동결 전 기간 내내 이를 지원할 가치가 있다고 라이브러리 유지 관리자를 설득할 수 있는지에 달려 있습니다.

제안

이 PEP에서 제안하는 변경 사항 대부분은 사전 릴리스 버전의 처리에만 영향을 줍니다. 정식 릴리스 버전에 영향을 주는 유일한 변경은 그 주기를 바꾸자는 제안입니다.

안정 릴리스의 2년 주기

참조 인터프리터와 표준 라이브러리의 최신 버전을 사용하려는 사용자는 연속적인 동결 전 릴리스를 이용할 수 있으므로, 이 PEP는 X.Y.0 릴리스 빈도를 조정하여 2년마다 8월에 새 안정 릴리스를 발행할 것을 제안합니다(Python 3.8.0 릴리스 후 약 2년이 지난 2021년부터 시작합니다).

이 변경은 사전 동결 릴리스 기간의 처리 방식에 대해 제안된 변경과는 별개라고 볼 수도 있습니다. 그러나 둘 사이의 연결 고리는 다음과 같습니다. 그러한 사전 릴리스 관리 변경이 없다면 2년 주기 정식 릴리스의 단점이 장점보다 클 가능성이 높지만, 12개월 릴리스 주기에서는 그 반대입니다(즉, 이 PEP에서 제안하는 사전 릴리스 관리 변경이 적용된 상태에서는 12개월 주기 정식 릴리스의 단점이 장점보다 큽니다).

알파 단계와 베타 단계를 “동결 전” 단계로 통합

이 PEP는 사전 릴리스의 알파 단계와 베타 단계가 서로 구별되고 순차적인 현 상태를 유지하는 대신, 이를 릴리스 일련번호가 단조 증가하는 단일 “동결 전” 단계로 통합할 것을 제안합니다.

“알파”와 “베타”라는 이름은 서로 다른 단계를 나타내는 대신, 해당 릴리스가 전체 CPython C ABI를 깨뜨리는 변경을 포함하는지 여부를 나타내게 됩니다:

  • “알파” 릴리스는 “ABI를 깨뜨리는” 릴리스로, 직전 사전 릴리스의 전체 CPython ABI에 맞춰 빌드된 확장 모듈이 반드시 올바르게 로드되지는 않습니다
  • “베타” 릴리스는 “바이너리 호환” 릴리스로, 직전 사전 릴리스의 전체 CPython ABI에 맞춰 빌드된 확장 모듈이 다음 추가 기준을 준수하는 한 올바르게 로드될 것으로 기대됩니다:
    • 모듈은 이 베타 릴리스에서 제거되었거나 ABI 비호환 방식으로 변경된 임시(provisional) 또는 비공개 C API(이전 안정 릴리스 시리즈의 것이든 개발 중인 사전 릴리스 시리즈의 것이든)를 사용해서는 안 됩니다
    • 모듈은 이전 안정 릴리스 시리즈에서 폐지 예정(deprecated)으로 지정되었고 이 베타 릴리스에서 제거된 C API를 사용해서는 안 됩니다

동결 전 단계의 기간과 주기

동결 전 릴리스는 새 X.Y.0 릴리스를 준비하는 몇 달 동안 매월 릴리스되는 대신, 2개월마다 일관되게 발행됩니다.

유일한 예외는 다가오는 X.Y.0 릴리스를 위한 2개월간의 릴리스 후보 기간입니다(자세한 내용은 아래 릴리스 후보 절을 참조하십시오). 즉, 원래 예정되어 있던 릴리스 두 번(하나는 첫 번째 릴리스 후보 날짜에 해당하고, 다른 하나는 최종 릴리스 날짜에 해당)을 건너뛰게 됩니다.

동결 전 단계는 일반적으로 직전 안정 X.Y.0 릴리스 후 2개월이 지나 시작될 것으로 예상됩니다.

새 릴리스 시리즈의 첫 번째 동결 전 릴리스는 항상 X.Y.0a1이 됩니다(같은 ABI 버전 표식을 가진 이전 릴리스가 없어서 바이너리 호환성을 비교할 대상이 없기 때문입니다).

동결 전 릴리스는 나중에 나올 안정 릴리스와 바이너리 호환성 문제가 생기지 않도록 C ABI 호환성 표식에 플래그를 하나 더 갖게 됩니다.

베타 릴리스의 릴리스 정책

이 PEP는 베타 릴리스 정책을 다음과 같이 정할 것을 제안합니다:

  • 현재의 베타 릴리스와 마찬가지로, 베타 릴리스를 준비하고 게시하기 전에 안정 BuildBot 군이 모두 녹색 상태여야 합니다
  • 현재의 베타 릴리스와 마찬가지로, 릴리스 관리자는 베타 릴리스를 준비하고 게시하기 전에 열려 있는 릴리스 차단 이슈를 검토해야 합니다
  • 현재의 베타 릴리스와 마찬가지로, abi3 안정 C ABI에 추가된 모든 항목은 그 안정 ABI 버전이 완전히 폐기되기 전까지 그 ABI의 영구적인 일부가 됩니다(참고: 현재 안정 ABI 버전을 올릴 계획은 없습니다)
  • 현재의 베타 릴리스와 달리, 이 PEP에 따른 베타 릴리스는 다음 X.Y.0 릴리스의 기능이 완성된 것으로 간주되지 않습니다
  • 현재의 베타 릴리스와 달리, 마지막 CPython 기능 릴리스 이후에 추가된 모든 API(안정 C ABI에 추가된 것은 제외)는 잠정적인 것으로 간주됩니다
  • 현재의 베타 릴리스와 달리, 이 PEP에 따른 베타 릴리스는 master 개발 브랜치에서 준비하고 게시합니다
  • 현재의 알파나 베타 릴리스와 달리, 이 PEP에 따른 베타 릴리스는 같은 시리즈에서 바로 앞선 사전 릴리스와 완전히 ABI 호환되어야 합니다(잠정적 API의 변경이나 이전 릴리스 시리즈에서 폐지 예정으로 지정된 API의 제거는 제외합니다)

알파 릴리스의 릴리스 정책

이 PEP는 알파 릴리스 정책을 다음과 같이 정할 것을 제안합니다:

  • 현재의 알파 릴리스와 마찬가지로, 알파 릴리스를 준비하고 게시하기 전에 안정 BuildBot 군이 모두 녹색 상태여야 합니다
  • 현재의 알파 릴리스와 마찬가지로, 릴리스 관리자는 베타 릴리스를 준비하고 게시하기 전에 열려 있는 릴리스 차단 이슈를 검토해야 합니다
  • 현재의 알파 릴리스와 달리, 릴리스 관리자는 알파 릴리스에서도 현재의 베타 릴리스와 비슷한 수준의 안정성을 목표로 해야 합니다

이 PEP에 따르면, 베타 릴리스 기준을 충족하는 릴리스를 게시할 수 없고 릴리스 전에 시간을 좀 더 두어도 문제가 해결되지 않을 때마다 알파 릴리스를 게시합니다.

호환성 태그를 정의하는 최초의 X.Y.0a1 릴리스 이후에 알파 릴리스를 추가로 게시하게 되는 가장 유력한 이유는 전체 CPython API가 ABI 호환성을 깨뜨리는 방식으로 변경되는 경우(예를 들어 공개 구조체 정의에 필드가 추가되거나 제거된 경우)일 것으로 예상되지만, 개별 릴리스에 대한 결정은 릴리스 관리자에게 달려 있습니다.

릴리스 후보 정책, 단계 기간 및 주기

알파와 베타 릴리스 단계에 대해 제안된 변경에 따라, 릴리스 후보 단계도 다음과 같이 조정됩니다:

  • 기능 동결, ABI 동결, pyc 파일 형식 동결, 유지 보수 브랜치 생성은 모두 X.Y.0rc1을 만드는 시점에 이루어집니다(현재 이들은 X.Y.0b1, 마지막 베타 릴리스, X.Y.0rc1에 나뉘어 이루어집니다)
  • X.Y.0 릴리스 후보 기간은 3주에서 2개월로 늘어납니다
  • 보통은 한 달 간격으로 릴리스 후보를 두 번 발행하지만, 릴리스 관리자의 재량에 따라 후보를 더 게시할 수 있습니다
  • 최종 X.Y.0 릴리스는 마지막 릴리스 후보가 나온 뒤 1주에서 4주 사이에 이루어집니다(두 번째 후보 이후에 릴리스 후보가 더 필요했는지에 따라 달라집니다)
  • 최종 X.Y.0 릴리스가 8월 목표일을 넘겨 늦어지더라도 다음 릴리스 시리즈는 영향을 받지 않으며, 여전히 8월(이 경우 2년이 조금 안 되는 시점)로 예정됩니다.

이렇게 조정된 정책은 릴리스 후보에 대한 최종 사용자 피드백을 받을 시간을 더 확보해 줄 뿐만 아니라, Python 프로젝트 유지 관리자가 새로운 안정 릴리스 시리즈용으로 미리 빌드된 wheel 아카이브를 빌드하고 게시할 시간도 추가로 제공하여 X.Y.0 릴리스의 초기 사용자 경험을 크게 개선합니다.

CPython 안정 C ABI 관리 방식의 변경

CPython 안정 ABI [5]는 특정 CPython 릴리스를 대상으로 빌드된 바이너리 확장 모듈이 같은 안정 ABI 버전(현재 이 버전은 abi3입니다)을 지원하는 이후의 CPython 릴리스에서도 계속 동작할 것을 약속합니다.

제안된 롤링 동결 이전 릴리스 모델에서는 이 약속이 베타 릴리스에도 적용되도록 확장됩니다. 즉, 다가오는 Python 버전의 abi3 안정 ABI에 의도적으로 추가된 항목이 일단 베타 릴리스에 포함되어 배포되면, abi3 안정 ABI가 지원되는 동안에는 이후 릴리스에서 제거되지 않습니다.

안정 ABI에 추가되는 항목에 대해 커뮤니티 피드백을 받는 데는 두 가지 주요 방법을 쓸 수 있습니다:

  • 권장하는 방법은 새 API를 먼저 전체 CPython API에 추가하고, 게시된 베타 릴리스 중 적어도 하나에 포함되어 관련 사용자 피드백을 받은 뒤에만 안정 ABI로 승격하는 것입니다
  • 어떤 이유로 그 방법을 쓸 수 없는 API라면(예를 들어 어떤 API 추가는 전체 CPython API를 쓸 수 있을 때는 아무 쓸모가 없을 수 있습니다), 개발자는 릴리스 관리자에게 다음 릴리스를 알파 릴리스로 지정해 달라고 요청하고(전체 CPython API에 ABI 호환성을 깨는 변경이 없더라도) 그런 방식으로 피드백을 더 얻으려고 시도할 수 있습니다

가독성과 사용성을 조금 개선하기 위해, 이 PEP는 각 주요 안정 ABI 버전에 대한 별칭 도입도 제안합니다.:

#define Py_LIMITED_API_3_3 0x03030000
#define Py_LIMITED_API_3_4 0x03040000
#define Py_LIMITED_API_3_5 0x03050000
#define Py_LIMITED_API_3_6 0x03060000
#define Py_LIMITED_API_3_7 0x03070000
#define Py_LIMITED_API_3_8 0x03080000
#define Py_LIMITED_API_3_9 0x03090000
// etc...

이 별칭은 확장 모듈 코드에서 대상 ABI 버전을 설정하는 데 사용되며,:

#define Py_LIMITED_API Py_LIMITED_API_3_8

CPython 인터프리터 구현에서 어떤 심볼을 제공해야 하는지 확인하는 데에도 사용됩니다.:

#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= Py_LIMITED_API_3_9
// A Python 3.9+ addition to the stable ABI would appear here
#endif

롤링 동결 전 릴리스와 안정 C ABI 문서에는 나중의 동결 전 릴리스에서 안정 ABI를 대상으로 빌드한 확장 모듈이 그보다 이전의 동결 전 릴리스에서 올바르게 로드되지 않을 수 있다는 점을 명시합니다.

알파 릴리스와 안정 C ABI 문서에는 알파 릴리스 두 개가 연달아 게시되는 경우(이런 상황은 드문 것이 이상적입니다), 알파 릴리스에서 안정 ABI를 대상으로 빌드한 확장 모듈조차 다음 릴리스에서 올바르게 로드되지 않을 수 있다는 점을 명시합니다.

전체 CPython ABI 관리 방식의 변경

이 PEP는 전체 CPython ABI 관리 방식에 대해 두 가지 변경을 제안합니다.

ABI를 깨뜨리는 변경을 표시하기 위한 명시적인 커밋 및 NEWS 파일 규칙

이 PEP의 제안에 따르면 릴리스 관리자는 동결 전 릴리스에 ABI를 깨뜨리는 변경이 포함되었는지에 따라 해당 릴리스를 알파 릴리스 또는 베타 릴리스로 적절히 표시할 수 있어야 합니다.

이 과정을 돕기 위해, 코어 개발자는 전체 CPython C ABI를 깨뜨리는 변경을 도입하는 모든 변경 사항의 NEWS 파일 조각 맨 앞에 “(CPython ABI break)” 표시를 넣도록 요청받습니다.

“CPython” 마커는 이 어노테이션이 안정 ABI가 아니라 전체 CPython ABI와 관련된다는 점을 분명히 하기 위해 포함됩니다.

커밋 메시지에는 더 짧은 표시인 “(ABI break)”를 커밋 요약 줄의 맨 앞에 넣습니다.

병합 전 봇을 업데이트하여, ABI break 표시가 두 위치 중 한 곳에 나타나면 반드시 두 곳 모두에 나타나도록 보장할 것입니다.

최초 커밋 메시지와 NEWS 항목에서 실수로 표시를 빠뜨린 경우, NEWS 항목에 표시를 추가하는 후속 커밋의 커밋 메시지에 해당 표시를 포함해야 합니다.

이러한 표시는 릴리스 관리자에게 유용할 뿐 아니라, 영향을 받는 릴리스로 테스트하다가 발생한 예기치 않은 세그폴트를 조사하는 개발자에게도 유용할 것입니다.

동결 전 ABI를 대상으로 한 빌드의 명시적 표시

전체 CPython ABI는 오랫동안 바이너리 호환성은 ABI가 동결되었다고 선언된 이후 하나의 릴리스 시리즈 안에서만 적용되고, 서로 다른 릴리스 시리즈 사이에는 소스 호환성만 적용된다는 정책에 따라 운영되어 왔습니다.

이 정책에 따르면, 해당 릴리스 시리즈의 ABI가 동결되기 전의 CPython 사전 릴리스를 대상으로 빌드한 확장 모듈은 최종 릴리스에서 실제로는 올바르게 로드되지 않을 수 있습니다.

이는 확장 모듈이 이후의 알파 또는 베타 릴리스에서 변경되거나 제거된 임시 인터페이스나 이전에 폐지된 인터페이스에 의존하고 있을 수 있기 때문이거나, 확장 모듈이 사용하는 공개 구조체에 새 필드가 추가되어 크기가 바뀌었기 때문일 수 있습니다.

지금까지는 알파 및 베타 릴리스의 채택률이 충분히 낮았기 때문에 실제로 이것이 큰 문제가 되지 않았습니다. 그러나 이 PEP는 베타 릴리스를 운영 환경에서 널리 사용하도록 적극 장려할 것을 제안하므로, 해당 릴리스의 사용자가 릴리스 후보와 최종 릴리스를 실행하는 사용자에게 세그폴트를 일으키는 바이너리 확장 모듈을 실수로 게시하지 않도록 보장하는 것이 바람직합니다.

이를 위해 이 PEP는 Windows가 아닌 시스템에서 확장 모듈의 SOABI 표시를 수정하여 CPython 사전 릴리스에 새로운 “p” 플래그를 포함하고, 해당 X.Y.0 버전의 ABI가 릴리스 후보 단계에 진입하면서 동결된 이후에야 다시 그 플래그를 생략하도록 할 것을 제안합니다.

이 변경으로 3.9.0의 알파 및 베타 릴리스는 cpython-39p라는 SOABI 태그를 받고, 모든 릴리스 후보와 최종 빌드(3.9.0과 이후의 3.9.x 릴리스 모두)는 한정자가 없는 cpython-39라는 SOABI 태그를 받습니다.

디버그 빌드는 여전히 태그 끝에 “d”를 추가하므로, 사전 릴리스의 디버그 빌드는 cpython-39pd가 됩니다.

Windows 시스템에서는 사전 릴리스 빌드에서 태그가 붙은 pyd 파일의 접미사에 버전 번호 바로 뒤에 사전 릴리스 표시로 “p”를 포함하여, “cp39p-win_amd64”와 같은 표시가 됩니다.

이 변경에 대해 제안된 참조 구현은 [4]에서 볼 수 있습니다(참고: 작성 시점에 해당 구현은 아직 Windows에서 테스트되지 않았습니다).

전체 C ABI 변경의 영향을 받는 프로젝트의 Python-Requires 업데이트

프로젝트가 롤링 동결 전 릴리스 시리즈에 대해 미리 빌드한 바이너리 휠을 제공하기로 처음 선택할 때는 특별히 할 일이 없습니다. 해당 릴리스 시리즈의 전체 CPython ABI가 동결된 이후 미리 빌드한 바이너리 휠을 제공할 때와 마찬가지로, 롤링 릴리스 시리즈를 빌드 및 테스트 매트릭스에 추가하고 해당 릴리스 시리즈와 호환된다고 표시된 바이너리 아카이브를 게시하면 됩니다.

그러나 프로젝트가 롤링 릴리스 스트림에서 CPython ABI 호환성 깨짐의 영향을 받는다면, 새 바이너리 빌드와 환경 제약이 걸린 새 Python-Requires 표시를 모두 포함하는 버전 업데이트를 배포해야 합니다.

예를 들어, 롤링 릴리스 스트림을 지원하는 프로젝트가 3.9.0a5 릴리스에서 CPython ABI 호환성 깨짐의 영향을 받았다면, 업데이트된 바이너리 빌드를 게시한 버전에 다음 메타데이터 항목을 추가합니다.:

Python-Requires: >= "3.9.0b6"; python_version == "3.9" and full_python_version != "3.9.0a5"

이렇게 하면 게시된 패키지의 일부로 호환성 제약이 추가되므로, 3.9.0b6 이전의 Python 3.9.0 베타 버전은 업데이트된 패키지를 설치 후보로 고려하지 않으며, 이 패키지를 고려하는 알파 릴리스는 3.9.0a5 자체뿐입니다.

주의 사항 및 제한 사항

실제 릴리스 날짜는 릴리스 팀의 가용 여부와 다른 행사(예: PyCon US 또는 연례 코어 개발자 스프린트)의 일정에 따라 릴리스 관리자의 재량으로 최대 한 달까지 앞당기거나 늦출 수 있습니다. 그러나 이 제안의 목표 중 하나가 일관된 릴리스 주기를 제공하는 것이므로, 이러한 조정은 드물게 이루어지는 것이 바람직합니다.

하나의 릴리스 시리즈 안에서 유지보수 릴리스의 정확한 빈도는 여전히 릴리스 관리자와 바이너리 릴리스 팀이 결정합니다. 이 PEP는 사전 릴리스와 X.Y.0 릴리스에 대해 예상되는 주기만을 제안합니다.

다만 예시 일정을 위해 이 PEP는 유지보수 릴리스가 격월로 이루어진다고 가정합니다. 이렇게 하면 유지보수 릴리스와 롤링 사전 동결 릴리스가 한 달씩 번갈아 나올 수 있습니다.

릴리스 관리자와 운영 위원회(Steering Council)는 이 PEP에 담긴 제안의 여러 세부 사항을 수정할 권한도 계속 가집니다. 가능한 수정 사항은 다음과 같으며, 이에 국한되지 않습니다:

  • 유지보수 브랜치를 생성하는 시점 변경. 새 알파 릴리스가 필요한 주요 변경이 사전 릴리스 과정의 비교적 늦은 시점에 반영된 경우, 릴리스 관리자는 그 주요 변경 이전 시점에서 브랜치를 분기하기로 선택할 수 있습니다. 예를 들어 다음 예정 릴리스가 마지막 베타 릴리스나 첫 번째 릴리스 후보가 될 예정이었다면, 이렇게 하는 것이 합리적일 수 있습니다.
  • 알파 릴리스를 선언하는 기준을 확장하여 What’s New 문서에 “Porting” 항목이 필요한 모든 변경을 포함할 수도 있습니다
  • 알파 릴리스를 필요할 때마다 선언하는 대신, 릴리스 관리자가 일부 날짜를 미리 알파 릴리스로 지정하고 코어 개발자들에게 위험도가 높은 변경을 그 일정에 맞추도록 요청할 수 있습니다.

이 PEP에 담긴 구체적인 제안은 검토자들이 고려할 수 있는 명확한 예시를 제공하려는 것입니다. 이 절차를 실제로 운영하며 얻은 경험을 바탕으로 세부 사항을 조정할 수 있는 여지를 제한하려는 것이 아닙니다.

설계 논의

단순히 X.Y.0 릴리스를 더 자주 하는 대신 롤링 사전 동결 릴리스를 택한 이유는 무엇입니까?

Python 사용자 중 상당수에게는 새 CPython 기능 릴리스의 가용성이 새 릴리스 도입을 가로막는 요인이 아닙니다(이러한 현상은 PyPI 다운로드 메타데이터 같은 지표에서 확인할 수 있습니다).

따라서 전체 기능 릴리스를 더 빠르게 내는 방식의 제안은 모두 두 부류의 사용자 요구 사이에서 균형을 잡아야 합니다. 한쪽은 각 릴리스가 나오는 대로 도입할 사용자이고, 다른 한쪽은 지금까지는 거의 모든 릴리스로 그 수명 주기 중 어느 시점에든 이전할 수 있었지만, 앞으로는 두 번째, 세 번째 또는 네 번째 릴리스마다 하나씩만 도입하게 될 사용자입니다.

이 제안은 CPython 코어 팀이 새 릴리스를 만들어 내는 속도만큼 빠르게 새 릴리스를 받아들일 수 있는 운영 환경의 이해관계에 더 구체적으로 맞춘, 프로덕션 환경에 바로 쓸 수 있는 새로운 릴리스 스트림을 정의함으로써 다른 각도에서 문제에 접근하는 것을 목표로 합니다.

“알파”와 “베타”라는 명명 체계를 유지할 필요가 있습니까?

제안된 롤링 릴리스에 “a”와 “b”라는 머리글자를 사용하는 것은 CPython 버전 번호가 공개되는 방식의 몇 가지 현실적인 측면 때문에 생기는 설계상의 제약입니다.

구체적으로 말하면, 알파 릴리스, 베타 릴리스, 릴리스 후보는 어떤 곳에서는 각각 문자열 “a”, “b”, “c”로 표시되고, 다른 곳에서는 16진수 0xA, 0xB, 0xC로 표시됩니다. 우리는 이를 유지하면서도, 모든 Python-Requires 제약 조건이 알파 릴리스가 아닌 베타 릴리스를 기준으로 표현되도록 하려고 합니다(알파 릴리스가 두 번 연속으로 나오면 알파 릴리스는 abi3 안정성 요구 사항을 지키지 않을 수 있기 때문입니다).

하지만 “a”가 “알파”를, “b”가 “베타”를 의미한다고 말해야 할 필연적인 이유는 없습니다.

따라서 “베타”라는 이름표 때문에만 도입을 꺼리는 사람들 사이에서 도입을 늘리려 한다면, “알파”와 “베타”라는 이름보다 “*A*BI breaking”과 “*B*inary compatible”이라는 이름을 강조하는 것이 합리적일 수 있으며, 그러면 다음과 같이 됩니다:

  • 3.9.0a1: ABI 호환성을 깨는 사전 동결 릴리스
  • 3.9.0b2: 바이너리 호환 사전 동결 릴리스
  • 3.9.0rc1: 릴리스 후보
  • 3.9.0: 최종 릴리스

이번 버전의 PEP는 거기까지 나아가지 않습니다. 롤링 사전 동결 릴리스의 초기 도입을 “베타”라는 이름표를 개의치 않는 사람들로 한정하는 편이 좋을 가능성이 크기 때문입니다. 더 넓은 Python 생태계 수준에서 생기는 예상치 못한 결과를 맞닥뜨리는 것은 이 릴리스의 초기 도입자들이며, 우리는 그들이 그런 문제를 해결하는 데 기꺼이 적극적으로 참여해 주어야 합니다.

그 결과 얻은 경험이 충분히 긍정적이어서 이 방식을 계속할 가치가 있다고 판단한다면, “베타”라는 이름에서 벗어나는 것은 앞으로 염두에 둘 선택지가 될 것입니다.

안정 릴리스 시리즈와 불안정 릴리스 시리즈를 번갈아 내는 대신 롤링 사전 동결 릴리스를 택한 이유는 무엇입니까?

베타 기간을 롤링 릴리스에 사용하는 대신, 기존 방식의 안정 릴리스(3.8.x, 3.10.x 등)와 새로운 롤링 릴리스 주기를 따르는 릴리스 시리즈(3.9.x, 3.11.x 등)를 번갈아 내는 방법도 있습니다.

이 방안에는 PEP 598 및 PEP 602와 같은 핵심 문제가 있습니다. 현 상태에 만족하는 최종 사용자에게 뚜렷한 보상이 되는 이점을 주지 않으면서 변화만 강요한다는 점입니다.

이는 PEP 598에 대해 제기된 주요 우려 사항 중 하나에도 영향을 받습니다. 적어도 일부 코어 개발자와 최종 사용자는 릴리스 버전에 있는 숫자 중 어느 것의 값에도 특정한 의미가 부여되지 않기를 강하게 선호합니다. 이 커뮤니티 구성원들은 그 대신 모든 의미상의 중요성이 릴리스 번호 안에서 변경되는 위치와 연관되기를 선호합니다.

반면에 롤링 동결 전 릴리스 제안은 제안된 정책 변경이 모두 특정 릴리스가 알파 릴리스인지, 베타 릴리스인지, 릴리스 후보인지, 최종 릴리스인지를 중심으로 이루어지도록 함으로써 그 우려를 해소하는 것을 목표로 합니다.

롤링 릴리스 스트림에 달력 버전 관리(Calendar Versioning)를 사용하지 않는 이유는 무엇입니까?

Steve Dower가 처음 작성한 이 제안서 [1]는 롤링 릴리스 스트림에 달력 버전 관리를 사용할 것을 제안했습니다(그렇게 했다면 Python 3.8.0 이후의 첫 번째 롤링 사전 릴리스는 3.9.0b1이 아니라 Python 2019.12가 되었을 것입니다).

Paul Moore는 그 제안에 두 가지 주요한 실무적 문제가 있다고 지적했습니다 [2]:

  • 달력 기반 버전의 사용자는 자신이 사용하는 버전이 기존 방식으로 번호가 매겨진 버전과 비교해 어디에 위치하는지 명확히 알 수 없습니다
  • 패키징 도구의 Python-Requires 메타데이터 처리를 망가뜨리며, 이를 안정적으로 고칠 명확한 방법이 없습니다(모든 달력 버전이 어떤 표준 버전보다도 새로운 버전으로 보이기 때문입니다)

이 PEP는 롤링 릴리스에 기존의 베타 버전 번호를 사용함으로써 이 두 가지 문제를 모두 해결하는 것을 목표로 합니다.

예를 들어 다음 질문을 생각해 보십시오: “Python 2021.12에는 Python 3.9.0에서 릴리스된 모든 새 기능이 포함되어 있습니까?”. 롤링 릴리스에 달력 버전 관리를 사용하면, 3.9.0rc1이 언제 롤링 릴리스 시리즈에서 분기되었는지 릴리스 일정표를 확인하지 않고는 이 질문에 답할 수 없습니다.

반면에 롤링 동결 전 릴리스에 대한 동일한 질문에는 쉽게 답할 수 있습니다: “Python 3.10.0b2에는 Python 3.9.0에서 릴리스된 모든 새 기능이 포함되어 있습니까?”. 질문을 구성하는 것만으로도 답은 분명히 “예, 제거된 잠정적 기능이 아니라면 그렇습니다”입니다.

베타 번호 매기기 방식은 sys.version_info, PY_VERSION_HEX, site-packages 디렉터리 이름 지정, 설치된 Python 바이너리 및 확장 모듈 이름 지정이 어떻게 동작할 것인지와 같이 달력 버전 관리 개념이 불러일으키는 다른 질문들도 피할 수 있습니다.

롤링 동결 전 릴리스의 사용자는 API 변경을 어떻게 감지합니까?

새 기능을 추가할 때 코어 개발자는 sys.version_info나 런타임 코드 객체 인트로스펙션에 의존하지 않는 메커니즘을 통해 기능 감지와 대안적 방식으로의 우아한 대체를 지원하도록 강력히 권장됩니다.

대부분의 경우 영향을 받는 모듈에 대한 간단한 hasattr 검사로 이 목적을 달성할 수 있지만, 그렇지 않은 경우에는 기능 추가 작업의 일부로 대체 방식을 검토하게 됩니다. 이 영역의 선행 사례로는 pickle.HIGHEST_PROTOCOL 속성, hashlib.algorithms_available 집합, 그리고 os 모듈이 플랫폼에 따른 기능 감지를 위해 이미 제공하고 있는 다양한 os.supports_* 집합이 있습니다.

롤링 동결 전 릴리스에 처음 포함될 때 __future__ 임포트를 통해 명시적으로 활성화해야 하는 기능을 추가하는 것도 가능합니다. 이는 해당 기능 플래그가 X.Y.0 릴리스 후보에 처음 등장하기 전에 나중에 기본으로 활성화되더라도 마찬가지입니다.

이러한 방식의 근거는, 이처럼 명시적으로 감지하고 활성화하면 롤링 동결 전 릴리스 스트림의 사용자가 잠정적 기능이 제거되거나 변경되었을 때 이를 쉽게 알아차리거나(예를 들어 기능 플래그가 더 이상 존재하지 않으면 from __future__ 임포트는 컴파일 시점에 실패합니다), 이전 기능으로 안전하게 폴백할 수 있다는 것입니다.

인터프리터의 풍부한 속성 조회 메커니즘 덕분에, sys.version_info 값을 대상으로 하는 검사에는 실질적으로 추가할 방법이 없는 경고를 잠정적이거나 폐지된 임포트와 속성에 대해서는 추가하도록 선택할 수도 있습니다.

X.Y.0rc1 이후 재빌드를 강제하기 위해 새로운 동결 전 ABI 플래그를 추가하는 이유는 무엇입니까?

현재 핵심 개발 팀은 ABI 동결일 이전에 X.Y 시리즈용으로 미리 빌드된 공개 바이너리를 만드는 것을 적극적으로 권장하지 않습니다.

그렇게 하는 이유는, 안정 버전인 X.Y.0 릴리스에서 고통스러운 디버깅 끝에 결국 “아, 우리의 의존성인 ‘superfast-binary-operation’이 X.Y.0a3의 CPython ABI 변경에 영향을 받았는데, 그 프로젝트는 그 이후로 새 빌드를 게시하지 않았습니다”라는 원인에 도달하게 되는 위험을 피하기 위함입니다.

제안된 동결 이전 ABI 플래그가 적용되면, 릴리스 도입 프로세스의 이 측면은 현 상태에서 본질적으로 변하지 않고 계속됩니다. 새로운 CPython X.Y 릴리스 시리즈가 ABI 동결에 도달함 -> 패키지 유지 관리자가 해당 릴리스 시리즈용 새 바이너리 확장 모듈을 게시함 -> 최종 사용자는 호환되지 않는 ABI에 맞춰 빌드된 것 때문이 아니라 실제 버그 때문에만 세그폴트를 겪게 됨.

따라서 새로운 동결 전 ABI 플래그의 주된 목표는 롤링 동결 전 릴리스 자체의 사용자 경험을 개선하는 것입니다. 이를 위해 현재 ABI 동결 이전의 바이너리 아티팩트 게시를 적극적으로 권장하지 않게 만드는 문제들을 감수하지 않고도 해당 릴리스용으로 미리 빌드된 바이너리 아카이브를 게시할 수 있도록 합니다.

이상적인 경우 패키지 유지 관리자는 X.Y.0a1에서 동결 이전 바이너리 빌드를 한 번, 그리고 X.Y.0rc1 이후에 동결 이후 빌드를 한 번만 게시하면 됩니다. 그 사이에 재빌드를 필요로 하는 유일한 상황은 중간의 알파 릴리스에서 발생한 CPython ABI 변경에 프로젝트가 실제로 영향을 받은 경우뿐이어야 합니다.

구체적인 예로, 결과적으로 ABI 변경을 포함하는 릴리스가 X.Y.0a1, X.Y.0a5, X.Y.0a7의 세 개가 되는 시나리오를 생각해 보십시오. 그러면 X.Y.0a7 ABI가 이후의 모든 베타 릴리스를 거쳐 X.Y.0rc1까지 이어지는 ABI가 됩니다. (이것이 그림 1에 나타난 시나리오입니다)

롤링 릴리스 스트림에 알파 릴리스가 나올 때마다 모두가 모든 것을 재빌드하도록 강제하면, 게시자들은 거의 확실히 롤링 릴리스를 지원하는 것이 얻는 것보다 수고가 더 크다고 판단하게 될 것입니다. 따라서 X.Y.0a1에 맞춰 빌드된 모듈이 X.Y.0a7에서도 로드될 수 있도록 허용하고자 합니다. 그러한 모듈은 아마 호환될 것이기 때문입니다(CPython이 공개하는 모든 C API를 사용하는 프로젝트는 매우 드물며, 대부분의 ABI 변경은 특정한 API 하나에만 영향을 미칩니다).

하지만 X.Y.0rc1을 발행하고 나면, X.Y.0a1과 X.Y.0a4를 대상으로 빌드된 바이너리가 최종 사용자 환경에서 완전히 사라지도록 보장하고자 합니다. X.Y.0a7과 그 이후의 베타 릴리스를 대상으로 한 빌드는 유지할 수 있으면 좋겠지만(당시에는 알지 못했더라도, 결과적으로 그 빌드들은 실제로 동결 이후 ABI를 대상으로 빌드된 것이었으므로), 그것들을 잃는다고 해서 현 상태보다 더 나빠지는 것은 아닙니다.

즉, 동결 이전 플래그는 이 문제를 해결하기 위한 “제대로 동작할 수 있는 가장 단순한 방법”입니다. 이는 단지 새로운 ABI 플래그일 뿐이며, ABI 플래그를 처리하는 도구는 (인터프리터에도, 패키지 발행 및 설치 도구에도) 이미 갖추어져 있습니다.

사전 릴리스와 비교해 ABI 플래그가 바뀌었으므로, 프로젝트는 새 릴리스를 발행할 필요조차 없습니다. 지금과 마찬가지로 기존 릴리스에 새 휠 아카이브를 업로드하면 됩니다.

마지막 알파 릴리스나 그 이후의 베타 릴리스를 대상으로 빌드된 모든 것을 소급하여 수용할 수 있는 더 영리한 방식도 아마 가능하겠지만, 이 PEP를 채택하는 데 그것이 필수적이라고 보지는 않습니다. 처음에는 단순한 사전 릴리스 ABI 플래그로 시작하더라도, 나중에 더 정교한 방식을 고안하는 것은 여전히 가능하기 때문입니다.

X.Y.0a1 이후에 추가 알파 릴리스를 허용하는 이유는 무엇입니까?

이상적으로는 전체 CPython ABI에 대한 모든 호환성을 깨는 변경이 파일 시스템 레이아웃 변경과 함께 X.Y.0a1에 반영되고, 그 이후로는 해당 릴리스 시리즈의 ABI가 안정적으로 유지될 것입니다.

그러나 최근의 경험으로 볼 때 우리가 실제로 그런 약속을 하고 지켜낼 수 있을 것 같지는 않으므로, 이 PEP는 ABI 변경이 동결 이전 기간 내내 점진적으로 이루어지고, 완전한 동결은 X.Y.0rc1을 준비하면서 X.Y.z 유지 보수 브랜치를 만들 때에야 이루어진다고 가정합니다.

CPython 코어 개발에 미치는 영향

CPython 코어 개발에서 가장 큰 변화는 master 브랜치를 더 일관되게 릴리스 가능한 상태로 유지해야 한다는 점입니다.

이를 위한 주된 요구 사항은 안정 BuildBot 플릿을 녹색 상태로 유지하는 것이겠지만, 롤링 동결 이전 릴리스 사용자를 위해 문서의 개발 버전을 최신 상태로 유지하는 것도 권장됩니다. 여기에는 변경 사항이 구현될 때마다 What’s New 항목 초안을 작성하는 일도 포함됩니다. 다만 초기 버전은 비교적 간략할 수 있으며, 이후 베타 릴리스 사용자의 피드백을 바탕으로 보강될 것입니다.

CPython C API를 다루는 코어 개발자에게는 NEWS 파일 조각에 ABI 호환성을 깨는 변경을 일관되게 표시해야 한다는 새로운 요구 사항도 생깁니다.

안정 ABI라는 특정 주제에 관해서는, 대부분의 API 설계가 먼저 전체 CPython API의 잠정적인 일부로 도입되고(동결 이전 릴리스 사이의 변경 허용), 개발자들이 해당 인터페이스가 정말로 안정적이라고 확신한 뒤에야 안정 ABI로 승격되는 과정을 거칠 수 있을 것입니다.

잠정적인 CPython API에서 설계를 반복 개선하는 대신 잠정적인 안정 ABI 추가 사항을 포함한 알파 릴리스를 발행하는 것이 타당할 수 있는 경우는, 어떤 API가 안정 ABI 밖에서는 아무런 쓸모가 없는 드문 경우뿐입니다.

Python 라이브러리 개발에 대한 영향

이 PEP가 목표를 달성한다면, 라이브러리 작성자에게 롤링 동결 이전 릴리스 스트림을 지원하는 일이 안정 릴리스를 지원하는 것보다 크게 더 고통스럽지는 않을 것입니다.

순수 Python 패키지를 게시하는 사람에게는 “py3” 태그가 붙은 wheel 아카이브를 게시하고, 가능하다면 롤링 동결 이전 릴리스 스트림을 테스트 매트릭스에 추가하는 것으로 충분합니다.

바이너리 확장 모듈을 게시하는 사람에게 권장되는 방법은 (가능하다면) 안정 C ABI를 대상으로 하여, 미리 빌드된 wheel 아카이브 하나로 롤링 동결 이전 릴리스 스트림을 포함한 여러 Python 버전을 지원할 수 있는, 순수 Python 패키지와 비슷한 경험을 누리는 것입니다.

이 선택지가 모든 라이브러리에서 실현 가능하지는 않을 것이며, 그런 라이브러리 작성자에게 바라는 결과는 최초의 X.Y.0a1 릴리스를 대상으로 빌드한 휠 아카이브 하나를 추가로 빌드하고 발행함으로써 롤링 릴리스를 지원할 수 있게 되는 것입니다. 그 뒤에 X.Y.0rc1 이후를 대상으로 하는 빌드는 최종 안정 릴리스만 지원하는 경우에도 필요했을 빌드와 동일합니다.

이 두 빌드 외의 추가 휠 빌드는 해당 라이브러리가 두 시점 사이에 나오는 다른 알파 릴리스의 ABI 호환성 깨짐에 직접 영향을 받는 경우에만 필요할 것입니다.

롤링 동결 이전 릴리스 스트림이 제공되면 더 많은 CI 제공자가 “CPython 베타 릴리스” 테스트 옵션을 제공하기가 더 쉬워질 수도 있습니다. 현재 이 기능은 CPython master 브랜치로부터 자체 빌드를 만들고, 테스트하고, 발행하는 데 필요한 시간과 노력을 들일 의지와 능력이 있는 CI 제공자에게서만 이용할 수 있습니다(예: [6]).

제안된 Scientific Python 생태계 지원 기간에 미치는 영향

SciPy 2019에서의 논의를 바탕으로, Scientific Python 생태계 전반에서 오래된 파이썬 버전에 대한 지원 중단에 관한 공통 관례를 제안하기 위해 NEP(NumPy Enhancement Proposal) 29의 초안이 작성되었습니다 [3].

해당 정책의 정확한 내용은 아직 논의 중이지만, 초안 제안(2019년 10월 20일 기준)은 프로젝트가 최근 42개월 이내에 게시된 모든 Python 기능 릴리스를 지원하되, 최소한 최신 Python 기능 릴리스 2개는 지원하도록 권장합니다.

18개월 기능 릴리스 주기에서는, 이는 항상 최소한 가장 최근의 기능 릴리스 두 개를 지원하고, X.(Y+2).0이 릴리스된 지 약 6개월 후에 모든 X.Y.Z 릴리스에 대한 지원을 중단하는 것이 됩니다. 즉, 대략 2년에 한 번씩 가장 최근의 기능 릴리스 세 개가 지원되는 6개월의 기간이 생깁니다.

12개월 릴리스 주기에서는, 항상 최소한 가장 최근의 기능 릴리스 세 개를 지원하고, X.(Y+3).0이 릴리스된 지 약 6개월 후에 모든 X.Y.Z 릴리스에 대한 지원을 중단하는 것이 됩니다. 즉, 매년 절반 동안은 가장 최근의 기능 릴리스 네 개가 지원되며, 나머지 절반은 그해의 기능 릴리스를 준비하는 데 쓰이기를 기대합니다.

24개월 릴리스 주기에서는 두 번째 절이 첫 번째 절보다 우선하며, 가장 최근의 CPython 기능 릴리스 두 개를 일관되게 지원하기 위해 권장 Python 버전 지원 기간이 최초 X.Y.0 릴리스로부터 48개월로 늘어납니다. 롤링 릴리스 스트림도 지원하는 프로젝트라면 지원 대상 기능 릴리스의 수가 세 개로 늘어납니다.

코어 개발 스프린트와 릴리스 주기의 정렬

이 PEP의 제안에 따르면, 코어 개발 스프린트의 초점은 2년 주기 중 현재 어느 시점에 있는지에 따라 약간씩 달라질 것으로 예상됩니다.

릴리스 연도에는 PyCon US의 개최 시기가 새로운 기여자들이 첫 번째 릴리스 후보가 나오기 전에 버그 수정과 작은 기능 작업을 하기에 적합합니다. 한편 Language Summit과 코어 개발자 논의는 다음 릴리스 시리즈의 계획에 집중할 수 있습니다.

릴리스 연도의 프리알파 코어 개발 스프린트는 이전 릴리스에 대해 받은 피드백을 반영할 기회를 제공합니다. 이러한 피드백은 다음 유지보수 릴리스의 일부로 반영하거나(버그 수정 및 잠정 API에 대한 피드백의 경우), 다음 릴리스 시리즈의 첫 번째 알파 릴리스의 일부로 반영할 수 있습니다(안정 API에 대해 받은 피드백의 경우).

이러한 초기 알파 릴리스는 전체 CPython ABI의 호환성을 깨는 변경을 넣기에 가장 바람직한 대상이기도 합니다(이 PEP에서 설명한 대로 릴리스 주기 후반의 변경도 여전히 허용되지만, 이를 X.Y.0a1 릴리스에 넣으면 미리 빌드된 바이너리 패키지 배포자에게 추가 작업이 생기지 않습니다).

다음 릴리스 주기의 운영 위원회(Steering Council) 선거도 프리알파 개발 스프린트와 비슷한 시기에 열릴 가능성이 높습니다.

릴리스가 없는 해에는 두 행사 모두 다가오는 유지보수 릴리스와 프리프리즈 릴리스에만 초점을 맞추게 됩니다. 이처럼 비교적 덜 바쁜 해에는 릴리스 후보 준비 과정에 영향을 주지 않으면서 다양한 프로세스 변경과 인프라 업그레이드에 착수할 기회가 생길 것으로 기대합니다.

주요 Linux 배포판과 릴리스 주기의 정렬

일부 롤링 릴리스 Linux 배포판(예: Arch, Gentoo)은 이 PEP에서 제안하는 새로운 롤링 프리프리즈 릴리스를 사용할 수 있는 입장일 수 있습니다. 그러나 대부분의 배포판은 기존의 확립된 릴리스를 계속 사용할 것으로 예상됩니다.

이 PEP에서 제안하는 최종 릴리스의 구체적인 날짜는 매년 10월에 릴리스되는 Ubuntu 및 Fedora Linux 배포판의 기능 동결 일정에 맞추어 선택되었습니다.

이는 Fedora와 Ubuntu 모두에서 릴리스 후보 단계가 배포판 릴리스의 개발 기간과 겹친다는 뜻입니다. 이 기간은 배포판이 새 버전을 테스트하고 잠재적인 회귀 및 호환성 문제에 대한 피드백을 제공하기에 이상적인 시기입니다.

Ubuntu의 경우 이는 4월 LTS 릴리스가 새로운 시스템 Python 버전을 사용하는 단기 릴리스 주기를 한 번 온전히 거친 이점을 누린다는 뜻이기도 합니다. 동시에 다음 Ubuntu LTS 릴리스까지 대부분의 기간 동안 해당 CPython 릴리스는 여전히 업스트림 버그 수정을 받을 수 있습니다.

이 PEP의 구체적인 제안과 릴리스 주기가 계속 잘 맞지 않을 가능성이 높은 Linux 배포판은 Debian 하나입니다. Debian은 2005년 이후 홀수 해 상반기에 릴리스되어 왔기 때문입니다(Ubuntu LTS 릴리스와 약 12개월 차이).

PEP 602의 연간 릴리스 제안에 따르면 Debian과 Ubuntu LTS 모두 약 6개월 된 시스템 Python 버전을 꾸준히 얻게 됩니다. 하지만 두 배포판은 서로 다른 Python 버전을 꾸준히 선택하게 됩니다.

2년 주기에 CPython 릴리스가 하반기에 이루어지면 두 배포판이 같은 버전을 선택할 가능성이 높습니다. 하지만 둘 중 하나는 자신의 Linux 배포판이 출시될 시점에 최신 베타 릴리스보다 18개월 이상 뒤처진 CPython 릴리스를 선택하게 됩니다.

그러한 상황이 실제로 발생하고 바람직하지 않다고 판단되는 경우(그러나 Debian이 릴리스 시기를 조정하기로 할 만큼 바람직하지 않은 것은 아닌 경우), 바로 그때 PEP 598의 “점진적 기능 릴리스” 제안이 가져오는 추가적인 복잡성이 그만한 가치를 발휘할 수 있습니다.

(CPython 릴리스를 Debian 및 Ubuntu LTS 릴리스와 같은 반기로 옮기면 이 문제를 완화하는 데 도움이 될 수 있습니다. 하지만 새로운 문제도 생깁니다. CPython 릴리스 일정이 지연되면 Linux 배포판의 릴리스 일정이 직접 영향을 받을 수 있고, 그렇지 않으면 배포판이 18개월 이상 된 Python 버전을 탑재하게 될 수 있습니다)

단순한 배포 환경에 대한 영향

이 PEP에서 “단순한” 배포 환경은 두 가지 조건을 갖춘 사용 사례를 모두 가리킵니다. 첫째, 모든 대상 환경을 동시에(또는 최소한 새로운 상위 수준 애플리케이션 버전을 출시하기 전에) 새 Python 릴리스로 업데이트하기가 간단해야 합니다. 둘째, 수행하는 사전 릴리스 테스트가 단일 Python 마이크로 버전만 대상으로 하면 되어야 합니다.

가장 단순한 사례는 테스트 환경과 대상 환경이 정확히 같은 개인용 스크립팅입니다.

이와 비슷하게 단순한 환경으로는 두 가지가 있습니다. 하나는 CI 파이프라인과 배포 시에 동일한 Python 컨테이너를 사용하는 컨테이너화된 웹 서비스입니다. 다른 하나는 대상 시스템에 미리 설치된 Python에 의존하지 않고 자체 Python 런타임을 번들로 포함하는 모든 애플리케이션입니다.

이러한 사용 사례에서는 이 PEP의 영향을 최소화하는 간단한 방법이 있습니다. 안정 릴리스를 계속 사용하고 롤링 프리프리즈 릴리스는 무시하면 됩니다.

이러한 환경에서 롤링 프리프리즈 릴리스를 실제로 채택할 때의 주요 과제는 확장 모듈에서 세그폴트가 발생할 가능성에 대처하는 일입니다. 다음 프리프리즈 릴리스가 베타 릴리스가 아니라 알파 릴리스라면 CPython ABI가 호환되지 않는 방식으로 변경되었을 수 있다는 뜻이기 때문입니다.

사용 중인 모든 확장 모듈이 안정 ABI를 대상으로 한다면 아무런 문제가 없습니다. 모든 것이 안정 릴리스에서와 마찬가지로 원활하게 작동합니다.

또는 “모든 확장 모듈을 다시 빌드하고 다시 캐시하기”를 알파 릴리스로 업데이트할 때 수행하는 표준 작업으로 삼을 수도 있습니다.

마지막으로, 실제로 무언가가 깨질 때까지는 신경 쓰지 않는 방법도 있습니다. 문제가 생기면 새로운 알파 또는 베타 릴리스에서 발견된 다른 라이브러리 호환성 문제와 똑같이 처리하면 되며, 이 역시 합리적인 방법입니다.

롤링 프리프리즈 릴리스를 사용할 때 추가로 복잡해지는 주요 지점은 확장 모듈 ABI 호환성 말고도 하나 더 있습니다. 바로 pickle이나 SQLite처럼 독립적으로 버전이 관리되는 기능의 “롤백” 호환성입니다. 이러한 기능은 베타 스트림에서 새로운 기능이나 잠정 기능을 사용하면 안정 릴리스에서 읽을 수 없는 파일이 생성될 수 있습니다. 이러한 종류의 기능을 사용하면서 이전 안정 CPython 릴리스로 확실하게 롤백할 수 있어야 하는 애플리케이션은 지금과 마찬가지로 사전 릴리스 버전을 채택하지 않는 것이 좋습니다.

복잡한 배포 환경에 대한 영향

이 PEP에서 말하는 “복잡한” 배포 환경이란 위에서 설명한 “단순한 배포” 기준을 충족하지 않는 사용 사례를 가리킵니다. 이러한 환경에는 서로 다른 여러 Python 버전, 개인화된 Python 빌드의 사용, 또는 배포 전에 새 버전의 사용을 승인해야 하는 “게이트키퍼”가 관련될 수 있습니다.

예를 들어 표준 운영 환경의 일부로 사용자 컴퓨터에 Python을 설치하는 조직이 이 범주에 속하며, 표준 빌드 환경을 제공하는 조직도 마찬가지입니다. 일관되게 빌드하고 검증한 패키지 모음을 제공하는 conda-forge나 WinPython 같은 배포판도 비슷한 방식으로 영향을 받습니다.

이러한 조직은 높은 안정성(예: Debian, RHEL/CentOS, Ubuntu LTS와 같은 안정적인 Linux 배포판의 시스템 Python을 선호하는 Python 환경으로 만족스럽게 사용하는 모든 조직)이나 빠른 처리(예: 최신 CPython 사전 릴리스에 정기적으로 기여하는 조직) 중 하나를 선호하는 경향이 있습니다.

경우에 따라서는 한 조직 안에서 두 가지 사용 모델이 서로 다른 목적으로 함께 존재할 수도 있습니다. 예를 들면 다음과 같습니다:

  • 미션 크리티컬 시스템에는 안정적인 Python 환경을 사용하되, 데이터 과학자에게는 임시 데이터 분석을 위해 사용 가능한 최신 버전을 쓰도록 허용하는 것
  • 프로덕션 펌웨어의 일부로 안정적인 Python 버전을 배포하지만, 자동화된 통합 테스트의 개발과 실행에는 사용 가능한 최신 버전을 사용하는 하드웨어 제조업체

어떤 릴리스 모델에서든 Python의 새 릴리스가 나올 때마다 이러한 조직에는 작업이 발생합니다. 이 작업에는 Python 자체에 대한 법률, 보안 또는 기술 검토, 영향이 큰 변경 사항의 평가와 검증, 패치 재적용, 서드파티 의존성의 재컴파일과 테스트가 포함될 수 있으며, 그런 다음에야 배포가 이루어집니다.

업데이트를 빠르게 받아들일 수 있는 조직은 더 자주 나오는 베타 릴리스를 활용할 수 있어야 합니다. 업데이트마다 여전히 지금과 비슷한 조사 작업이 필요하겠지만, 각 릴리스가 현재 모델에서보다 이전 릴리스와 더 비슷해지므로 릴리스당 필요한 작업량은 줄어들 것입니다. 제안된 2개월마다 릴리스하는 모델의 장점 하나는 조직이 모든 베타 릴리스를 도입하는 것부터 분기마다 하나, 6개월마다 하나, 또는 1년마다 하나를 도입하는 것까지 자체 도입 주기를 선택할 수 있다는 점입니다. 그보다 주기가 길다면 대신 안정 릴리스를 계속 사용하는 편이 더 합리적일 것입니다.

더 엄격한 평가를 거치거나 안정성을 선호하는 조직의 경우, 안정 릴리스의 릴리스 주기가 길어지면 업데이트에 드는 연간 노력이 줄어들고, 릴리스 후보 기간이 길어지면 X.Y.0 릴리스 전에 내부 테스트를 할 시간이 늘어나며, 베타 기간 동안 다른 사람들이 더 많이 사용하게 되면 초기 릴리스에 대한 신뢰가 높아질 것입니다. 한편 조직은 호환성을 깨뜨리는 변경을 걱정하지 않고 더 오랜 기간 동안 유지보수 릴리스를 통해 안심하고 업그레이드할 수 있습니다.

감사의 글

PEP 602를 작성하고 CPython 릴리스 주기의 개선 가능성에 대한 이 논의를 이끌어 낸 Łukasz Langa에게, 그리고 이 PEP의 초기 초안에 건설적인 피드백을 준 Kyle Stanley와 h-vetinari에게 감사드립니다.

참고 문헌