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

Python 개선 제안 한국어 번역

PEP 694 – Python 패키지 색인을 위한 Upload 2.0 API

Author:
Barry Warsaw <barry at python.org>, Donald Stufft <donald at stufft.io>, Ee Durbin <ee at python.org>
PEP-Delegate:
Dustin Ingram <di at python.org>
Discussions-To:
Discourse thread
Status:
Draft
Type:
Standards Track
Topic:
Packaging
Created:
11-Jun-2022
Post-History:
27-Jun-2022, 06-Jan-2025 14-Apr-2025 06-Aug-2025 27-Sep-2025 07-Dec-2025 26-Jun-2026 29-Jul-2026

Table of Contents

번역·라이선스 안내

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

초록

이 PEP는 PyPI와 같은 Python 패키지 색인에 파일을 업로드하기 위한 확장 가능한 API를 제안합니다. 표준화와 함께 업로드 API는 다음과 같은 유용한 추가 기능을 지원합니다:

  • 패키지 릴리스의 모든 아티팩트(휠, sdist)를 동시에 원자적으로 게시하는 데 사용할 수 있는 게시 세션;
  • 공개적으로 게시하기 전에 업로드를 테스트하는 데 사용할 수 있는 릴리스의 “스테이징”. 이 경우 test.pypi.org가 필요하지 않습니다;
  • 세션이 게시될 때까지 덮어쓰고 교체할 수 있는 아티팩트;
  • 아티팩트 업로드 상태에 대한 상세한 상태 정보;
  • 아티팩트 업로드 없이 새 프로젝트를 생성하는 기능;
  • 전체 PEP를 요구하지 않고 향후 지원되는 업로드 메커니즘을 확장할 수 있는 프로토콜. 이러한 메커니즘은 모든 색인에 대해 표준화하고 권장할 수도 있고, 색인별로 지정할 수도 있습니다.

이 PEP는 레거시 API의 지원 중단 일정을 제안하지 않습니다.

근거

현재 PyPI와 같은 Python 패키지 색인에 파일을 업로드하기 위한 표준화된 API는 없습니다. 대신 모든 사용자는 기존의 “legacy” API를 역공학해야 했습니다.

레거시 API는 기능적으로 작동하지만, 원래 PyPI 코드베이스의 구현 세부 사항을 노출합니다. 이러한 세부 사항은 새로운 코드베이스와 대체 구현에 충실히 복제되었습니다.

또한 레거시 API에는 다음과 같은 여러 가지 주요 문제가 있습니다:

  • 완전히 동기식이므로 업로드 자체를 수행하는 동안뿐만 아니라 색인이 업로드된 파일을 처리하여 성공 또는 실패를 판단하는 동안에도 요청을 계속 열어 두어야 합니다.
  • 업로드를 병렬화하거나 재개할 수 있는 메커니즘을 지원하지 않습니다. PyPI의 가장 큰 기본 파일 크기가 약 1GiB이므로, 업로드 전체가 성공적으로 완료되어야 한다면 요청이 진행 중일 때 이러한 업로드에서 네트워크 중단이 발생할 경우 대역폭이 낭비됩니다.
  • 작업의 원자적 단위는 단일 파일입니다. 릴리스에 논리적으로 sdist와 여러 바이너리 휠이 포함되는 경우 이는 문제가 됩니다. 사용자가 운이 나쁘게도 자신의 플랫폼용 휠이 완전히 업로드되기 전에 패키지를 필요로 하면 소비자마다 서로 다른 버전의 패키지를 받게 되는 경쟁 조건이 발생하기 때문입니다. 릴리스가 sdist를 먼저 업로드하면 일부 소비자에게 sdist만 표시되어 로컬에서 소스 빌드를 수행하게 되는 형태로도 나타날 수 있습니다.
  • 상태 보고는 매우 제한적입니다. 여러 오류, 경고, 지원 중단 등의 보고를 지원하지 않습니다. 상태는 HTTP 상태 코드와 사유 구문으로 제한되며, 이 중 사유 구문은 HTTP/2 이후 폐기되었습니다(RFC 7540).
  • 릴리스의 메타데이터는 파일과 함께 제출됩니다. 그러나 이 메타데이터는 악명 높을 정도로 신뢰할 수 없으므로 대부분의 설치 프로그램은 대신 파일 전체를 다운로드하여 그 안에서 메타데이터를 읽습니다.
  • 업로드에 대역폭을 사용하기 전에 색인이 어떤 종류의 기본 검사를 수행하도록 허용하는 메커니즘이 없습니다. 잘못된 권한이나 할당량 소진과 같은 많은 오류 조건은 파일을 업로드하기 전에 확인할 수 있습니다.
  • 색인에 게시하기 전에 릴리스를 “스테이징”할 수 있는 기능이 없습니다.
  • 새 프로젝트를 생성하려면 최소 하나의 파일을 업로드해야 하므로 프로젝트 이름을 선점하기 위한 “스텁” 업로드가 발생하고 공간이 낭비됩니다.

이 PEP에서 제안하는 새로운 업로드 API는 이러한 모든 문제를 직접 해결하거나 확장 가능한 접근 방식을 통해 해결할 방법을 제공합니다. 이를 통해 서버는 재개 가능한 업로드와 병렬 업로드 같은 기능을 구현할 수 있습니다. 이 PEP에서 제안하는 업로드 API는 더 우수하고 표준화된 오류 보고, 더욱 견고한 릴리스 테스트 환경, 그리고 모든 릴리스 아티팩트의 원자적이고 동시적인 게시를 제공합니다.

레거시 API

다음은 레거시 API의 개요입니다. 자세한 설명은 PyPI 사용자 가이드 문서를 참조하십시오.

엔드포인트

기존 업로드 API는 기본 URL에 있습니다. PyPI의 경우 해당 URL은 현재 https://upload.pypi.org/legacy/입니다. 업로드를 수행하는 클라이언트는 값이 file_upload:action URL 매개변수를 추가하여 호출하려는 API를 지정합니다. [1]

레거시 API에는 이론적으로 API의 새 버전을 정의할 수 있도록 하는 protocol_version 매개변수도 있습니다. 실제로 이러한 일은 한 번도 발생하지 않았으며, 값은 항상 1입니다.

따라서 PyPI에서 실제로 사용되는 업로드 API는 다음과 같습니다: https://upload.pypi.org/legacy/?:action=file_upload&protocol_version=1.

인코딩

제출할 데이터는 콘텐츠 유형이 multipart/form-dataPOST 요청으로 제출됩니다. 이는 레거시 API의 역사적 특성을 반영합니다. 이 API는 원래 API가 아니라 초기 PyPI 구현의 웹 폼으로 설계되었으며, 클라이언트 코드는 해당 폼을 프로그래밍 방식으로 제출하도록 작성되었습니다.

콘텐츠

대략적으로 말하면, 패키지에 포함된 메타데이터는 콘텐츠 처리 방식이 form-data이고 메타데이터 키가 필드 이름인 파트로 제출됩니다. 이러한 여러 메타데이터 조각의 이름은 문서화되어 있지 않으며, 패키지 아티팩트의 METADATA 파일에 사용된 이름과 일치하는 경우도 있지만 항상 일치하는 것은 아닙니다. 대소문자가 일치하는 경우는 드물며, form-data에서 METADATA로의 변환도 일관되지 않습니다.

업로드 아티팩트 파일 자체는 이름이 contentapplication/octet-stream 파트로 전송되며, PGP 서명이 첨부된 경우에는 이름이 gpg_signatureapplication/octet-stream 파트로 포함됩니다.

인증

업로드 인증 또한 표준화되어 있지 않습니다.

PyPI는 API 토큰을 비밀번호로 사용하고 사용자 이름은 __token__으로 하는 HTTP 기본 인증을 사용합니다. 신뢰할 수 있는 게시자는 OpenID Connect를 통해 인증하고, 동일한 방식으로 사용되는 단기 API 토큰을 받습니다.

Upload 2.0 API 사양

이 PEP는 대략적으로 다음 단계로 구성되는 다중 요청 워크플로를 제안합니다.

  1. 릴리스 단계를 생성하면서 게시 세션을 시작합니다.
  2. 게시 세션의 일부로 해당 단계에 대한 파일 업로드 세션(들)을 시작합니다.
  3. 클라이언트와 서버 간에 사용할 특정 파일 업로드 메커니즘을 협상합니다.
  4. 협상된 메커니즘을 사용하여 파일 업로드 세션(들)에 대한 파일 업로드 메커니즘을 실행합니다.
  5. 파일 업로드 세션(들)을 완료하고, 완료됨 또는 취소됨으로 표시합니다.
  6. 게시 세션을 완료하고, 해당 단계를 게시하거나 폐기합니다.
  7. 선택적으로 게시 세션의 상태를 확인합니다.

버전 관리

이 PEP는 PEP 691에서 사용되는 것과 동일한 MAJOR.MINOR버전 관리 시스템을 사용하지만, 그 외에는 독립적으로 버전이 관리됩니다. 레거시 API는 이 PEP에서 1.0버전으로 간주하지만, 이 PEP는 어떤 방식으로도 레거시 API를 수정하지 않습니다.

따라서 이 PEP에서 제안하는 API의 버전 번호는 2.0입니다.

Upload API의 주요 버전 번호와 부 버전 번호는 PEP 절차를 통해서만 반드시 변경되어야 합니다. 색인 운영자와 구현자는 승인된 PEP 없이 새로운 API 버전을 광고하거나 구현해서는 MUST NOT안 됩니다. 이를 통해 모든 구현에서 일관성을 보장하고 생태계의 파편화를 방지합니다.

콘텐츠 유형

관련 PEP 691과 마찬가지로, 이 PEP는 이 업로드 API의 모든 요청과 응답이 콘텐츠의 종류, 해당 콘텐츠가 나타내는 API 버전 및 사용된 직렬화 형식을 설명하는 표준 콘텐츠 유형을 갖도록 제안합니다.

이 표준 요청 콘텐츠 유형은 파일 업로드 메커니즘을 실행하기 위한 요청을 제외하고 모든 요청에 적용되며, 해당 메커니즘의 문서에서 이를 명시합니다.

그 밖의 모든 요청에 대한 Content-Type헤더의 구조는 다음과 같습니다:

application/vnd.pypi.upload.$version+$format

부 API 버전의 차이는 절대로 중단을 일으켜서는 안 되므로 콘텐츠 유형에는 주 버전만 포함하며, 버전 번호 앞에는 v를 붙입니다.

클라이언트 요청의 .meta.api-versionJSON 키에 지정된 주 API 버전은 주 버전에 대한 Content-Type헤더와 MUST일치해야 합니다.

관련 PEP 691과 달리, 이 PEP는 기존 레거시 1.0 업로드 API를 어떤 방식으로도 변경하지 않으므로 서버는 이 PEP에서 설명하는 새 API를 기존 업로드 API와 다른 엔드포인트에서 호스팅해야 합니다.

이 PEP에서 정의된 요청 형식은 JSON이 유일하므로, 이 PEP에서 정의된 파일 업로드가 아닌 모든 요청은 다음 Content-Type헤더 값을 MUST포함해야 합니다:

  • application/vnd.pypi.upload.v2+json.

관련 PEP 691과 마찬가지로, 이 PEP는 클라이언트가 콘텐츠 유형의 format 부분을 포함하여 다양한 버전이나 직렬화 형식을 요청할 수 있도록 서버 주도 콘텐츠 협상을 사용하는 방식도 표준화합니다. 그러나 이 PEP는 기존 레거시 1.0업로드 API가 다른 엔드포인트에 존재한다고 예상하고, 현재 JSON 직렬화만 제공하므로 이 메커니즘은 특별히 유용하지 않습니다. 클라이언트가 요청할 수 있는 버전과 직렬화는 각각 하나뿐입니다. 그러나 클라이언트는 향후 추가 형식이나 버전이 추가되는 경우 콘텐츠 협상을 원활하게 처리할 수 있도록 SHOULD준비해야 합니다.

서버는 승인된 PEP에서 정의한 범위를 넘어서는 API 버전의 지원을 광고해서는 MUST NOT안 됩니다. 새로운 버전이나 형식은 새로운 PEP를 통해 표준화해야 합니다.

달리 명시하지 않는 한, 이 문서의 모든 HTTP 요청과 응답은 다음 HTTP 헤더를 포함하는 것으로 간주합니다:

Content-Type: application/vnd.pypi.upload.v2+json

루트 엔드포인트

여기에 설명된 모든 URL은 도메인의 URL 구조 어디에나 위치할 수 있는 “루트 엔드포인트”를 기준으로 합니다. 예를 들어 루트 엔드포인트는 https://upload.example.com/이거나 https://example.com/upload/일 수 있습니다.

루트 엔드포인트의 선택은 색인 운영자에게 맡깁니다.

인증 및 권한 부여

이 명세의 모든 엔드포인트는 RFC 7235에 정의된 표준 HTTP 인증 메커니즘을 MUST사용해야 합니다.

인증은 표준 HTTP 패턴을 따릅니다:

  • 인증이 필요한 경우 서버는 WWW-Authenticate응답 헤더를 사용합니다.
  • 클라이언트는 Authorization요청 헤더를 통해 자격 증명을 제공합니다.
  • 401 Unauthorized는 인증이 누락되었거나 유효하지 않음을 나타냅니다.
  • 403 Forbidden은 권한이 충분하지 않음을 나타냅니다.

구체적인 인증 방식(예: Bearer, Basic, Digest)은 패키지 색인 운영자가 결정합니다.

인증은 요청을 수행하는 주체를 확정합니다. 권한 부여는 해당 주체가 특정 세션에서 작업을 수행할 수 있는지를 결정합니다. 이 사양에 정의된 모든 세션 엔드포인트(즉, publishing session 또는 file upload session이 생성될 때 links 키 아래 반환되는 URL)는 프로젝트의 업로드 권한을 기준으로 권한이 부여되어야 MUST 합니다. 구체적으로 서버는 각 요청 시점에 인증된 주체가 세션에 지정된 프로젝트에 업로드할 현재 권한이 있는지 MUST 확인해야 하며, 권한이 없으면 403 ForbiddenMUST 응답해야 합니다.

이 검사는 각 요청에서 독립적으로 수행되므로 세션은 세션을 생성한 정확한 자격 증명에 not 연결되지 않습니다.

  • 세션이 열린 후 업로드 권한을 부여받은 주체는 해당 세션에 즉시 참여할 수 있습니다.
  • 세션이 열려 있는 동안 업로드 권한이 취소된 주체는 해당 주체가 세션을 생성한 경우에도 이후의 모든 요청에서 403 Forbidden으로 거부되어야 MUST 합니다.

이 거부는 요청별로 평가되며 “고정적”이지 않습니다. 주체의 권한이 나중에 복원되면 이후 요청은 다시 권한이 부여됩니다. 패키지 색인은 더 엄격한 정책을 적용할 MAY 수 있지만, 이 사양에서는 이를 요구하지 않습니다.

서버는 퍼블리싱 세션 또는 파일 업로드 세션을 생성, 수정, 완료, 연장, 취소 또는 게시하는 모든 요청에 대해 최소한 이 권한 부여 검사를 수행해야 MUST 합니다. 둘 이상의 요청을 통해 파일을 전송하는 업로드 메커니즘(예: 청크 방식 또는 멀티파트 방식)의 경우 서버는 그러한 각 요청에 권한을 부여해야 SHOULD 합니다.

추측하기 어려운 stage preview URL은 별도의 기능이며 의도적으로 이 권한 부여 검사의 적용을 받지 not습니다. 이 URL은 토큰을 보유한 모든 클라이언트에 읽기 전용 미리 보기 접근 권한을 부여하므로, 예를 들어 CI 작업이 프로젝트 업로드 자격 증명 없이 스테이징된 릴리스의 설치를 테스트할 수 있습니다.

오류

달리 명시되지 않는 한 서버의 모든 오류(4xx 및 5xx) 응답은 RFC 9457 (Problem Details for HTTP APIs) 형식을 사용해야 MUST 합니다. 특히 서버는 Section 3에 정의된 “Problem Details JSON Object”를 사용해야 MUST 하며, 응답에서 application/problem+json 미디어 유형을 사용해야 SHOULD 합니다.

일반적으로 클라이언트는 다음과 같은 페이로드를 포함해야 SHOULD 하는 HTTP response error status codes를 처리할 준비가 되어 있어야 합니다. 단, RFC 9457을 준수하는 한 세부 사항은 패키지 색인별로 다를 수 있습니다. 예를 들어 PyPI는 다음과 같은 오류 본문을 반환할 수 있습니다.

{
  "type": "https://docs.pypi.org/api/errors/error-types#invalid-filename",
  "status": 400,
  "title": "The artifact used an invalid wheel file name format",
  "details": "See https://packaging.python.org/en/latest/specifications/binary-distribution-format/",
  "meta": {
    "api-version": "2.0"
  },
  "errors": [
    {
      "source": "...",
      "message": "..."
    }
  ]
}

RFC 9457은 type, status, titledetails를 정의합니다. metaerrors 키는 Section 3.2에 정의된 “확장 멤버”입니다. 패키지 색인은 이러한 확장 멤버를 포함해야 SHOULD 합니다.

meta
요청/응답 메타데이터 구조는 퍼블리싱 세션 설명에서 정의된 것과 동일합니다.
errors
각각 특정 오류를 나타내는 오류 배열이며, 각 오류에는 오류의 원인을 나타내는 문자열인 source 키와 해당 오류에 대한 message 키가 포함됩니다.

messagesource 문자열에는 특정한 의미가 없으며, 근본적인 문제를 진단하는 데 도움이 되도록 사람이 해석하기 위한 것입니다.

일부 응답은 아래 본문에 설명된 것처럼 더 구체적인 HTTP 상태 코드를 반환할 수 있습니다.

퍼블리싱 세션

퍼블리싱 세션 생성

릴리스는 새 퍼블리싱 세션을 생성하는 것으로 시작합니다. 세션을 생성하려면 클라이언트가 루트 URL에 다음과 같은 POST 요청을 제출합니다.

{
  "meta": {
    "api-version": "2.0"
  },
  "name": "foo",
  "version": "1.0",
}

요청에는 다음 최상위 키가 포함됩니다:

meta (필수)
페이로드 자체에 대한 정보를 설명합니다. 현재 유일한 필수 하위 키는 api-version이며, 그 값은 문자열 "2.0"이어야 합니다. 선택적 하위 키로 색인별 동작을 정의할 수 있습니다.
name (필수)
이 세션이 새 버전을 릴리스하려는 프로젝트의 이름입니다. 이름은 표준 패키지 이름 형식반드시 준수해야 하며, 서버는 이름을 반드시 정규화해야 합니다.
version (필수)
이 세션이 파일을 추가하려는 프로젝트의 버전입니다. 버전 문자열은 패키징 버전 사양을 반드시 준수해야 합니다.

세션이 성공적으로 생성되면 서버는 201 Created 응답을 반환합니다. 응답에는 응답 본문links.session 키와 동일한 URL을 포함하는 Location 헤더도 반드시 포함되어야 합니다.

이전 릴리스가 없는 프로젝트에 대해 세션이 생성되면, 색인은 세션 생성 시 프로젝트 이름을 반드시 예약해야 합니다. 이는 스테이지가 유지되는 동안에만 유지되는 임시 예약입니다. 새 프로젝트를 처음 업로드할 때 서로 다른 두 클라이언트가 각각 스테이지를 생성하고, 그렇지 않으면 먼저 스테이지를 게시하는 클라이언트가 이름을 차지하게 되는 스테이지 게시 시점의 이름 선점 경쟁 조건을 방지하기 위해 존재합니다. 스테이지가 게시될 때까지 “정규”(즉, 스테이지되지 않은) 액세스 프로토콜을 사용하여 예약된 프로젝트에 접근할 수 있어서는 안 됩니다. 스테이지가 게시되면 예약은 이름의 영구 등록으로 전환됩니다. 이 첫 릴리스 스테이지가 취소되면 색인은 프로젝트가 업로드된 적이 없었던 것처럼 프로젝트 레코드를 삭제해야 하며, 예약을 해제해야 합니다.

게시 세션은 이를 생성한 특정 자격 증명에 묶이지 않습니다. 대신 세션에 대한 모든 요청은 인증에 설명된 대로 해당 요청 시점에 프로젝트에 업로드할 권한이 있는 인증된 주체가 반드시 수행해야 합니다. 그러한 권한이 없거나 더 이상 없는 주체의 요청은 403 Forbidden반드시 수신해야 합니다.

아직 존재하지 않는 프로젝트에 대한 첫 릴리스 세션에서는 평가할 기존 프로젝트 업로드 권한이 없습니다. 대신 색인은 자체 이름 등록 정책에 따라 요청을 승인하며, 세션 수명 동안 생성 주체(및 해당되는 경우 이를 대신하여 활동하는 조직)를 권한이 있는 주체로 취급해야 합니다.

선택적 색인별 메타데이터

색인은 선택적으로 색인별 동작을 위한 자체 메타데이터를 정의할 수 있습니다. 메타데이터 키는 MUST 밑줄로 시작해야 하며, 뒤따르는 값은 색인을 쉽고 고유하게 식별해야 합니다. 예를 들어 PyPI는 다음 색인별 메타데이터 섹션을 사용하여 발행자가 구성원인 조직 계정에 프로젝트를 생성할 수 있도록 허용할 수 있습니다.

{
  "meta": {
    "api-version": "2.0",
    "_pypi.org": {
        "organization": "my-org"
    }
  },
  "name": "foo",
  "version": "1.0",
}

이는 예일 뿐입니다. 이 PEP는 색인별 키나 메타데이터를 정의하거나 예약하지 않으며, 이는 색인이 지정하고 문서화할 사항입니다. 색인별 메타데이터의 의미(예: 잘못된 키나 값이 오류를 발생시키는지 또는 무시되는지)도 여기서는 정의되지 않습니다.

응답 본문

성공적인 응답에는 다음 내용이 포함됩니다.

{
  "meta": {
    "api-version": "2.0"
  },
  "links": {
    "stage": "...",
    "upload": "...",
    "session": "...",
    "publish": "...",
    "extend": "...",
  },
  "mechanisms": ["http-post-bytes"],
  "session-token": "<token-string>",
  "expires-at": "2030-08-01T12:00:00Z",
  "status": "open",
  "files": {},
  "notices": [
    "a notice to display to the user"
  ]
}

요청 JSON과 동일한 형식을 갖는 meta 키 외에도, 성공 응답에는 다음 키가 포함됩니다:

links
이 세션과 관련된 URL로 연결되는 키를 매핑하는 딕셔너리이며, 자세한 내용은 아래에 설명되어 있습니다.
mechanisms
서버에서 지원하는 파일 업로드 메커니즘의 목록이며, 서버가 선호하는 순서로 정렬되어 있습니다. 하나 이상의 값이 필요합니다.
session-token
색인이 스테이징된 릴리스 미리 보기를 지원하는 경우, 이 키에는 설치 프로그램에 제공하여 게시 전에 스테이징된 릴리스를 미리 볼 수 있는 고유한 “세션 토큰”이 포함됩니다. 이 토큰은 반드시 암호학적으로 추측할 수 없어야 합니다. 색인이 스테이지 미리 보기를 지원하지 않는 경우 이 키는 생략되어야 합니다.
expires-at
관련 RFC 3339 형식의 타임스탬프 문자열입니다. 이 문자열은 “Zulu”(즉, Z) 표식을 사용하여 UTC 타임스탬프를 반드시 나타내야 하며, 정수 초만 사용해야 합니다(즉, 소수 초를 사용해서는 안 됩니다). 이 타임스탬프는 서버가 이 세션과 업로드된 모든 파일 및 세션과 관련된 URL 링크를 포함한 모든 콘텐츠를 만료시키는 시점을 나타냅니다. 클라이언트 자체가 세션을 취소하거나 게시하지 않는 한, 세션은 최소한 이 시점까지 활성 상태로 유지되어야 합니다. 서버는 이 만료 시간을 연장할 수도 있지만, 더 이른 시간으로 변경해서는 안 됩니다. 클라이언트는 세션 상태를 조회하여 세션의 현재 만료 시간을 확인할 수 있으며, 연장을 요청할 수도 있습니다.
status
전체 세션 상태를 나타내며, open, processing, published, error, canceled 중 하나를 포함하는 문자열입니다.
files
이 세션에 업로드된 파일 이름을, 각 이 세션에서 참조되는 파일에 대한 세부 정보를 포함하는 매핑으로 매핑하는 매핑입니다.
notices
서버가 최종 사용자에게 전달하려는 사람이 읽을 수 있는 정보성 알림의 배열을 가리키는 선택적 키입니다. 이러한 알림은 세션의 특정 파일이 아니라 전체 세션에 관한 것입니다.
여러 세션 생성 요청

기존 세션이 open, processing 또는 error 상태인 비종료 상태(참조: 세션 상태)에서 동일한 이름-버전 쌍에 대해 세션을 생성하려는 두 번째 시도가 수신되면 새 세션은 생성되지 않습니다. 대신 서버는 409 Conflict반드시 반환하고, 세션 상태 URL을 가리키는 Location헤더를 반드시 포함해야 합니다. 다른 모든 세션 요청과 마찬가지로 이러한 요청은 프로젝트에 업로드할 권한이 있는 주체가 반드시 수행해야 합니다(참조: 인증). 권한이 없는 주체의 요청에는 대신 403 Forbidden반드시 반환되어야 하며, 진행 중인 세션의 존재가 공개되지 않도록 이는 409 Conflict에 우선합니다. 권한이 있는 주체는 409 ConflictLocation헤더를 받고 참조된 세션을 사용할 수 있습니다. 이것이 여러 권한 있는 게시자(예를 들어 서로 다른 Trusted Publishing 워크플로)가 동일한 세션에 기여할 수 있는 방식입니다.

그 외의 경우(예를 들어 이름-버전 쌍에 비종료 상태의 세션이 없는 경우)에는 새 세션이 생성됩니다. 이는 해당 쌍의 이전 세션이 종료 상태인 published 또는 canceled 상태에 도달했거나 해당 쌍에 대해 세션이 한 번도 생성된 적이 없기 때문일 수 있습니다. 이때 응답과 페이로드는 동일한 201 Created이지만, 게시 세션 상태 URL, session-tokenlinks.stage값은 반드시 서로 달라야 합니다.

게시 세션 파일

files 키에는 이 세션에서 업로드된 파일 이름에서 다음 키를 포함하는 하위 매핑으로의 매핑이 들어 있습니다.

status
pending, processing, completed, error를 유효한 값으로 갖는 문자열이며, 해당 파일의 업로드 세션의 상태를 반영합니다. 업로드 중 오류가 발생한 경우 클라이언트는 해당 파일이 사용 가능한 상태라고 가정해서는 안 되며, error가 반환되므로 파일을 취소하거나 삭제하고 처음부터 다시 시작하는 것이 가장 좋습니다.

canceled는 여기에 나타나지 않습니다. 파일을 취소하거나 삭제하면 해당 파일은 더 이상 세션의 일부가 아니므로 세션 상태 응답 본문files 매핑에서 해당 항목이 완전히 제거됩니다. 해당 파일의 자체 파일 업로드 세션 상태 URL은 계속해서 canceled를 보고합니다.

link
클라이언트가 이 특정 파일을 참조하는 데 사용해야 하는 절대 URL입니다. 이 URL은 참조된 파일을 가져오거나, 교체하거나, 삭제하는 데 사용됩니다. 관련 미리 보기 단계를 지원하는 경우, 이 URL은 암호학적으로 반드시 추측할 수 없어야 하며, 이 제약 조건을 확실히 충족하기 위해 동일한 게시 세션 토큰반드시 사용해야 합니다. URL의 정확한 형식은 색인에 맡기지만 반드시문서화해야 합니다.
notices
세션의 notices 키와 형식 및 의미가 유사한 선택적 키이지만, 이러한 알림은 참조된 파일에만 해당합니다.

게시 세션 상태

퍼블리싱 세션은 항상 다음 상태 중 정확히 하나이며, 이는 세션 상태 응답status 키로 보고됩니다.

퍼블리싱 세션의 상태 다이어그램입니다. 초기 상태에서 세션은 ``open``\ 으로 진입합니다. ``open`` 상태에서 퍼블리시 요청은 즉시 완료되어(``201``) 최종 상태인 ``published``\ 로 이동하거나, 지연 처리를 위해 수락되어(``202``) ``processing``\ 으로 이동하거나, 동기적으로 실패하여(``4xx``/``5xx``) ``open`` 상태를 유지합니다. 또한 ``open``\ 은 취소되어(``DELETE``) 최종 상태인 ``canceled``\ 로 이동할 수도 있습니다. ``processing``\ 은 성공 시 ``published``\ 로, 실패 시 ``error``\ 로 귀결됩니다. ``error`` 상태에서 클라이언트는 퍼블리싱을 재시도할 수 있으며 -- 이는 ``open``\ 에서 퍼블리싱하는 것과 동일하게 동작합니다 -- 또는 취소하여 ``canceled``\ 로 이동할 수 있습니다. ``open``\ 과 ``error`` 모두 파일 업로드 세션을 호스팅합니다. ``processing`` 중 취소는 ``409``\ 로 거부됩니다.

각 상태에 대한 텍스트 설명과 전체 전이 표는 다음과 같습니다.

open
세션은 변경 사항을 수락합니다. 파일을 업로드, 교체하고, 삭제할 수 있으며, 세션을 미리 보고 연장할 수 있고, 게시하거나 취소할 수 있습니다. 새로 생성된 세션은 이 상태에서 시작합니다.
processing
클라이언트가 게시를 요청했고 서버는 지연 처리를 위해 해당 요청을 수락하여 202 Accepted를 반환합니다(게시 세션 완료 참조). 서버가 세션을 검증하고 처리하는 동안 세션은 더 이상 변경 사항을 수락하지 않습니다. 이는 전환 상태입니다. 클라이언트는 세션 상태를 폴링하여 published 또는 error로 결정될 때까지 확인합니다.
published (terminal)
세션의 파일이 게시되어 공개적으로 사용할 수 있습니다. 더 이상의 변경은 불가능합니다.
error
가장 최근의 지연 게시 시도가 실패했습니다. 세션은 완전히 다시 편집할 수 있습니다. open과 정확히 동일한 작업을 허용하며, 마지막 게시 시도가 실패했다는 사실을 기록한다는 점에서만 오직 open과 다릅니다. 사람이 읽을 수 있는 이유는 세션의 notices반드시 보고해야 하며, 실패 원인이 특정 파일에 있는 경우에는 해당 파일의 notices에도 보고해야 합니다. 이 상태에서 클라이언트는 문제를 해결한 후 다시 게시하거나 세션을 취소할 수 있습니다.
canceled (terminal)
세션이 취소되었고 스테이징된 데이터가 폐기되었습니다. 더 이상의 변경은 불가능합니다.

openerror는 동일한 작업 집합을 허용하는 편집 가능한 상태이며, 클라이언트는 error 세션을 폐쇄되었거나 읽기 전용인 것으로 취급해서는 안 됩니다. 두 상태의 유일한 차이는 error가 이전의 지연 게시 요청이 실패했다는 사실을 추가로 기록한다는 점입니다.

publishedcanceled는 종단 상태이므로, 둘 중 하나에 도달하면 이름-버전 쌍이 해제되어 후속 세션을 생성할 수 있습니다. 예를 들어 이미 게시된 릴리스에 추가 플랫폼용 휠을 추가할 수 있습니다.

이러한 상태 간의 전이는 다음과 같습니다.

출발 이벤트 도착
(없음) 세션 생성됨 open
open 파일이 업로드, 교체 또는 삭제됨 open
open 퍼블리시 요청이 즉시 완료됨(201 Created) published
open 퍼블리시 요청이 지연 처리를 위해 수락됨(202 Accepted) processing
open 또는 error 파일 중 하나라도 completed가 아닌 상태에서 퍼블리시가 요청됨 409 Conflict로 거부됨(게시 세션 완료 참조)
open 또는 error 퍼블리시 요청이 동기적으로 실패함 변경 없음(오류가 호출자에게 반환됨)
open 또는 error 세션이 취소됨(DELETE) canceled
processing 지연 처리가 성공함 published
processing 지연 처리가 실패함 error
processing 취소 요청됨 409 Conflict로 거부됨 (게시 세션 취소 참조)
error 파일이 업로드, 교체 또는 삭제됨 error
error 게시가 재시도됨 processing 또는 published

동기 게시 실패(즉, 서버가 게시 요청 자체 내에서 판정하는 실패)는 호출자에게 오류 응답으로 반환되며, 세션은 현재의 편집 가능한 상태로 유지됩니다(openopen으로, errorerror로 유지됩니다). error 상태에 도달하는 경우는 지연 처리를 위해 수락된 게시가 이후에 실패하는 경우뿐입니다. 이 경우 실패를 호출자에게 직접 반환할 수 없으므로 클라이언트가 폴링을 통해 이를 발견합니다.

게시 세션 완료

세션을 완료하고 세션에 포함된 파일을 게시하려면 클라이언트는 세션 생성 응답 본문에 지정된 publish 링크POST 요청을 보냅니다.

요청은 다음과 같습니다:

{
  "meta": {
    "api-version": "2.0"
  }
}

세션을 게시하려면 세션의 모든 파일이 업로드를 완료해야 합니다. 세션의 파일 매핑에 있는 항목 중 하나라도 completed 이외의 상태라면 서버는 문제가 있는 파일과 해당 파일의 현재 상태를 식별하는 409 Conflict 오류 응답과 함께 게시 요청을 거부해야 하며, 세션을 현재 편집 가능한 상태로 유지해야 합니다. 클라이언트는 각 진행 중인 파일 업로드 세션이 해결될 때까지 기다린 다음, 다시 게시하거나 먼저 더 이상 게시할 의도가 없는 파일을 삭제하여 이 문제를 해결합니다.

이 사전 조건은 의도적으로 허용 목록으로 표현되었습니다 – completed 파일만 게시할 수 있으므로, 다른 상태의 파일은 조용히 포함되거나 조용히 삭제되지 않고 게시를 차단합니다. 특히 여기에는 제자리에서 복구할 수 없어 삭제해야 하는 error 상태의 파일(파일 업로드 세션 상태 참조)뿐만 아니라, 이 프로토콜의 향후 개정판에서 도입될 수 있는 추가 파일 상태도 포함됩니다.

서버가 게시 세션을 즉시 완료할 수 있으면 그렇게 처리하고 201 Created 응답을 반환하여 세션을 최종 상태published로 전환할 수 있습니다. 서버가 게시 세션을 즉시 완료할 수 없으면(예를 들어 단일 HTTP 요청에서 처리하기에 합리적인 시간보다 오래 걸릴 수 있는 유효성 검사를 수행해야 하는 경우) 202 Accepted 응답을 반환하고 세션을 processing 상태로 전환할 수 있습니다.

서버는 현재 세션 상태를 조회하는 데 사용할 수 있는 게시 세션 상태 URL을 가리키는 Location 헤더를 응답에 포함해야 합니다. 서버가 202 Accepted를 반환한 경우 해당 URL을 폴링하여 세션 상태의 변경을 확인할 수 있습니다. 지연된 처리는 성공하면 published로, 실패하면 error로 귀결됩니다. error로 귀결되면 세션은 편집 가능한 상태로 유지되며, 이유는 게시 세션 상태에 설명된 대로 세션의 notices에 보고됩니다.

동기적으로 실패하는 게시 시도(즉, 게시 요청 자체 내에서 실패하는 시도)는 오류 응답으로 클라이언트에 반환되며 세션은 현재 편집 가능한 상태로 유지됩니다. 세션을 error로 전환하지 않습니다.

원자적 게시와 충돌

세션 게시 작업은 릴리스의 파일명 네임스페이스에 대해 원자적으로 수행됩니다. 게시된 아티팩트는 변경할 수 없으므로, 색인은 이 API 또는 레거시 API를 통해 동시 업로드가 도착하더라도 동일한 릴리스에 동일한 이름을 가진 두 파일을 게시하지 않도록 보장해야 합니다.

관련 파일 업로드 세션이 생성될 때 수행되는 특정 시점의 충돌 검사는 최선형 검사입니다. 이 검사는 해당 요청 시점의 게시 상태를 반영하며, 세션이 열려 있는 동안 릴리스의 게시 상태가 변경될 수 있으므로 게시 시점에도 파일에 충돌이 없을 것이라고 보장하지는 않습니다. 예를 들어 동일한 이름의 파일이 레거시 API를 통해 게시되거나, 이미 게시된 동일한 nameversion에 대한 후속 세션을 통해 게시될 수 있습니다. 따라서 권위 있는 충돌 검사는 게시 시점에 원자적으로 수행됩니다.

파일명 예약. 클라이언트가 게시를 요청하면 서버는 대상 릴리스 내 세션의 모든 파일 이름을 원자적으로 예약하고 게시가 진행되는 동안 해당 예약을 유지해야 합니다. 세션의 모든 파일이 업로드를 완료해야 게시할 수 있으므로, publication requires every file in the session to have finished uploading이 예약은 세션이 게시할 완전히 업로드된 파일만 정확히 포함합니다.

  • 예약이 유지되는 동안 동일한 릴리스에 해당 파일명 중 하나를 가진 파일을 업로드하려는 다른 모든 시도는 이 API를 통하든 레거시 API를 통하든 파일이 이미 게시된 경우와 정확히 동일하게 409 Conflict로 거부되어야 합니다. 색인은 충돌하는 요청이 어떤 업로드 경로를 통해 도착하든 이를 적용해야 합니다. 이는 색인의 공유 게시 파일명 네임스페이스에 대한 요구 사항이며 레거시 API 자체를 변경하지는 않습니다.
  • 예약은 충돌 감지에만 적용됩니다. 예약된 파일은 스테이징된상태로 유지되어야 하며 게시가 성공할 때까지 공개적으로 표시되어서는 안 됩니다.
  • 게시가 성공하면 예약은 영구 게시로 전환됩니다. 게시가 실패하면(세션을 편집 가능한 상태로 남기는 동기적 실패이거나, error 상태로 전환되는 지연된 processing 중의 실패인 경우) 서버는 예약을 해제하여 해당 파일명을 다시 사용할 수 있도록 해야 합니다.

아직 open 상태인 세션은 파일 이름을 예약하지 않으며, 예약은 게시를 요청할 때만 획득됩니다. 즉시(201 Created) 게시의 경우 예약은 단일 요청의 지속 시간 동안만 유지되므로 사실상 관찰할 수 없습니다. 이 요구 사항은 주로 지연된(202 Acceptedprocessing) 게시에서 의미가 있습니다. 이러한 게시에서는 색인이 하나의 스테이징된 아티팩트를 검증한 후 나머지를 커밋하기 전까지 실제 시간 간격이 존재합니다.

이렇게 하면 의도적이고 보수적인 비용으로 해당 시간 간격을 해소할 수 있습니다. 즉, 궁극적으로 실패하는 게시 중에 동시 업로드가 409 Conflict받을 수도 있으며, 예약이 해제된 후 재시도하면 성공할 수 있습니다. 색인은 동일한 이름을 가진 두 파일을 절대 게시하지 않지만, 그 대가로 나중에 재시도하면 허용될 동시 업로드를 간혹 거부할 수 있습니다.

게시 시점 충돌 보고. 색인이 게시 중 충돌을 감지하면(위와 같은 파일명 충돌이든, 세션 생성 시에는 충족되었지만 더 이상 충족되지 않는 다른 전제 조건이든, 예를 들어 할당량 소진 또는 권한 철회인 경우) 게시 세션 상태 머신에 따라 실패를 보고합니다.

  • 서버가 게시를 동기적으로 완료하는 경우, 충돌하는 파일을 식별하는 오류 응답을 반환해야 하며 파일명 충돌의 경우에는 409 Conflict를 반환하고 세션을 현재 편집 가능한 상태로 유지해야 합니다.
  • 서버가 지연된 처리를 위해 게시를 수락했고 processing 중에 충돌을 감지한 경우, 세션을 error 상태로 전환하고 세션의 notices에 충돌하는 파일을 보고해야 합니다(실패가 특정 파일에 귀속되는 경우 해당 파일의 notices에도 보고해야 합니다).

어느 경우든 클라이언트는 문제가 되는 파일을 삭제하거나 교체하거나 다른 방식으로 충돌을 해결한 후 다시 게시하거나 세션을 취소할 수 있습니다.

게시 세션 취소

게시 세션을 취소하려면 클라이언트는 세션 생성 응답 본문에 지정된 session링크DELETE 요청을 발행합니다. 그러면 서버는 세션을 canceled로 표시하고, 해당 세션의 일부로 업로드된 모든 데이터를 SHOULD 삭제합니다. 해당 데이터가 삭제되면 세션의 작업 및 데이터 제공 URL인 links.upload, links.publish, links.extend, links.stage와 개별 파일 URL은 사용할 수 없게 SHOULD 되며 404 Not Found를 반환할 수도 MAY 있습니다. 세션 상태 URL(links.session)은 대신 세션 상태 보존에 설명된 대로 유지됩니다. 이 URL은 색인별 기간 동안 canceled 상태를 계속 보고한 후, 해당 URL 역시 404 Not Found를 반환할 수도 MAY 있습니다.

세션이 열려 있거나 오류 상태인 경우에만 취소할 수 있습니다. 세션이 processing 상태인 경우(즉, 지연된 게시 요청이 이미 처리 중인 경우) 게시가 이미 진행 중일 수 있으므로 서버는 409 Conflict와 함께 취소를 거부해야 MUST 합니다. 클라이언트는 대신 처리가 완료될 때까지 기다릴 수 있으며, 처리가 error로 완료되면 세션을 취소할 수 있습니다.

그 밖의 경우에는 세션 파일의 상태와 관계없이 취소할 수 있습니다. 특히 하나 이상의 파일 업로드 세션이 processing 상태라는 이유로 세션 취소가 거부되어서는 MUST NOT 안 됩니다. 세션을 활성 상태로 유지하고 게시를 향해 진행시키며 해당 파일의 처리 결과에 따라 게시 내용이 달라지게 되는 개별 파일 삭제와 달리, 세션을 취소하면 아무것도 게시되지 않음이 보장되므로 처리 중인 검증 결과가 결과에 영향을 줄 수 없습니다. 서버는 이러한 처리 중인 작업을 중단하는 대신 완료될 때까지 실행하고 그 결과를 폐기하도록 허용할 수도 MAY 있습니다. 세션의 모든 파일 업로드 세션은 canceled로 간주되며, 해당 URL에는 위에서 설명한 세션의 다른 데이터 제공 URL과 동일한 처리가 적용됩니다.

서버는 세션이 방치되는 것을 방지하기 위해 시간 초과된 세션을 자체적으로 취소하도록 선택할 수도 있습니다. 서버는 최소 일주일이 지난 후 세션을 삭제하는 것이 권장되지만, 각 서버는 자체 일정을 선택할 수 있습니다. 서버는 클라이언트가 지시하는 세션 확장을 지원할 수도 MAY 있습니다.

게시 세션 상태

클라이언트는 언제든지 links.session URL에 지정된 URL( 세션 생성 응답의 Location 헤더에도 제공됨)에 GET 요청을 발행하여 세션 상태를 조회할 수 있습니다.

서버는 이 GET 요청에 대해 게시 세션을 처음 생성했을 때 받았던 것과 동일한 게시 세션 생성 응답을 응답하지만, status, expires-at 또는 files의 변경 사항은 반영합니다.

세션 상태 보존

세션 상태 URL이 무기한 유효하게 유지된다는 보장은 없습니다. 세션이 종단 상태인 published 또는 canceled에 도달하면 서버는 클라이언트가 끝까지 지켜보지 않은 세션의 최종 결과를 안정적으로 확인할 수 있도록 색인별 보존 기간 동안 해당 상태 URL을 계속 제공하고 종단 status를 보고해야 SHOULD 합니다. 해당 보존 기간이 지나면 서버는 상태 URL에 대해 404 Not Found를 반환할 수도 MAY 있습니다. 보존 기간의 길이는 색인에 맡기지만, 세션을 시작했거나 세션에 기여한 클라이언트가 그 결과를 알 수 있을 만큼 충분히 길어야 SHOULD 합니다.

이 보존은 세션 상태에만 적용됩니다. 종료된 세션의 데이터 제공 및 작업 URL(예: links.stage와 개별 파일 URL)은 기본 데이터가 더 이상 필요하지 않게 되는 즉시 사용할 수 없게 될 수 있으며, 이는 취소에 설명된 바와 같습니다.

클라이언트는 세션이 종료되고 보존 기간이 지난 후 세션 상태 URL이 404 Not Found를 반환할 수 있음에 대비해야 MUST 합니다. 이전에 유효했던 세션 상태 URL에서 404가 반환되는 것은 그 자체로 오류가 아니며, 클라이언트는 이를 세션이 더 이상 존재하지 않음을 나타내는 것으로 처리해야 SHOULD 합니다. 종료된 세션이 삭제된 후 동일한 nameversion에 대해 새 세션 생성을 요청하면, 아직 활성 상태인 세션이 반환했을 409 Conflict 대신 201 Created와 함께 성공한다는 점에 유의하십시오.

게시 세션 확장

서버는 클라이언트가 세션을 확장하도록 허용할 수도 MAY 있지만, 전체 수명과 허용되는 확장 횟수는 서버에 맡겨집니다. 세션을 확장하려면 클라이언트는 links.extend URL에 POST 요청을 발행합니다. 서버가 세션 확장을 지원하지 않으면 응답에 links.extend 키가 포함되지 않습니다.

요청은 다음과 같습니다:

{
  "meta": {
    "api-version": "2.0"
  },
  "extend-for": 3600
}

지정된 초 수는 현재 세션을 연장할 추가 시간에 대해 서버에 제안하는 값일 뿐입니다. 예를 들어 클라이언트가 현재 세션을 한 시간 더 연장하려는 경우 extend-for3600입니다. 연장이 성공하면 서버는 게시 세션을 처음 생성했을 때 받은 것과 동일한 게시 세션 생성 응답 본문을 반환하지만, status, expires-at 또는 files에 변경 사항이 있으면 이를 반영합니다.

서버가 요청된 초만큼 세션을 연장하지 않기로 하더라도 성공 응답을 반드시 반환해야 하며, expires-at 키에는 현재 세션 만료 시간이 그대로 반영됩니다.

게시 세션 토큰

색인은 업로드된 파일을 게시하기 전에 실시간으로 테스트할 수 있도록 미리 보기 단계지원해야 합니다. 예를 들어 CI 클라이언트는 사전 게시된 휠을 사용하여 설치 테스트를 수행함으로써 새 릴리스가 공개적으로 게시되기 전에 예상대로 작동하는지 확인할 수 있습니다.

색인은 게시 세션 생성에 대한 응답에 두 가지 핵심 정보를 반환하여 스테이징된 프리뷰 지원 여부를 알립니다. 스테이지 미리 보기를 지원하지 않는 색인은 응답에 이러한 항목을 포함해서는 안 됩니다.

session-token은 설치 도구의 UX를 편리하게 하는 데 사용할 수 있는 짧은 토큰입니다. 예를 들어 pip는 스테이징된 프리뷰에서 설치할 때 편리하도록 --stage $SESSION_TOKEN 플래그를 추가할 수 있습니다. links.stage 키는 스테이지의 전체 URL을 제공하며, 현재 설치 도구와 함께 사용할 수 있습니다. 예를 들어 pip install --extra-index-url $STAGE_URL과 같이 사용할 수 있습니다. 세션 토큰과 URL은 모두 암호학적으로 추측할 수 없어야 하지만, 토큰 생성 알고리즘은 색인에 맡깁니다. 스테이지 URL은 색인이 문서화한 형식을 사용하여 세션 토큰으로부터 계산할 수 있어야 하지만, URL의 정확한 형식 역시 색인에 맡깁니다.

파일 업로드 세션

파일 업로드 세션 생성

게시 세션을 생성한 후, 응답의 세션 링크 매핑에 있는 upload 엔드포인트를 사용하여 해당 세션에 새 파일을 업로드하기 시작합니다. 클라이언트는 제공된 upload URL을 사용해야 하며, 한 세션에서 다음 세션으로 이어지는 URL에 어떤 패턴이나 공통성이 있다고 가정해서는 안 됩니다.

파일 업로드를 시작하려면 클라이언트는 먼저 upload URL로 POST 요청을 보냅니다. 요청은 다음과 같습니다.

{
  "meta": {
    "api-version": "2.0"
  },
  "filename": "foo-1.0.tar.gz",
  "size": 1000,
  "hashes": {"sha256": "...", "blake2b": "..."},
  "mechanism": "http-post-bytes"
}

표준 meta 키 외에도 요청 JSON에는 다음과 같은 추가 키가 있습니다.

filename (필수)
업로드할 파일의 이름입니다. 파일 이름은 다음 중 하나를 따라야 합니다: source distribution file name specification 또는 binary distribution file name convention. 색인은 파일 이름이 규격에 맞지 않을 때 오류 섹션에 설명된 대로 400 Bad Request 오류 코드와 RFC 9457 스타일의 오류 본문을 반환하면서, 요청 시점에 이러한 파일 이름을 검증해야 합니다.
size (필수)
업로드할 파일의 최종 총 크기(바이트)입니다.
hashes (필수)
해시 이름과 16진수로 인코딩된 다이제스트의 매핑입니다. 이러한 각 다이제스트는 이름으로 식별되는 알고리즘으로 업로드할 파일을 해시했을 때의 체크섬입니다.

기본적으로 hashlib 에서 사용할 수 있는 모든 해시 알고리즘을 hashes 딕셔너리 [2]의 키로 사용할 수 있습니다. hashlib.algorithms_guaranteed에서 안전한 알고리즘을 하나 이상은 항상 포함해야 합니다. 이 PEP에서는 특히 sha256을 권장합니다.

여러 해시를 한 번에 전달할 수 있지만, 제공되는 모든 해시는 파일에 대해 유효해야 합니다.

mechanism (필수)
클라이언트가 이 파일에 사용하려는 파일 업로드 메커니즘입니다. 이 메커니즘은 게시 세션 생성 응답 본문에서 광고된 메커니즘 목록에서 선택해야 합니다. 서버 운영자가 “시험판” 방식으로 사용할 수 있는 새 메커니즘이나 곧 제공될 메커니즘을 문서화한 경우, 클라이언트는 광고되지 않은 메커니즘을 전송할 수도 있습니다.

서버는 파일 업로드를 허용하기 전에 일부 기본적인 유효성 검사를 수행하기 위해 이 요청에 제공된 데이터를 사용할 수도 있습니다. 이러한 검사에는 다음이 포함될 수 있지만, 이에 국한되지는 않습니다:

  • 게시된 릴리스에 filename이 이미 존재하는지 확인하기;
  • size가 프로젝트 또는 파일 할당량을 초과하는지 확인하기.

이미 게시된 nameversion에 대해 게시 세션을 생성할 수도 있습니다. 예를 들어 기존 릴리스에 추가 플랫폼용 휠을 추가하기 위해서입니다. 그러나 게시된 아티팩트는 변경할 수 없으므로, 이 요청의 filename이 이 릴리스에 이미 게시된 파일과 일치하면 서버는 409 Conflict로 요청을 거부해야 하며, 게시된 파일을 덮어써서는 안 됩니다. 이 검사는 최선의 노력으로 수행되며 요청 시점의 게시 상태를 반영합니다. 권위 있는 원자적 충돌 검사는 원자적 게시와 충돌에 설명된 대로 게시 시 수행됩니다.

서버가 업로드를 진행해야 한다고 판단하면 아래의 응답 본문과 함께 202 Accepted응답을 반환합니다. 게시 세션의 status에는 files매핑의 파일 이름도 포함됩니다. 클라이언트가 제공한 mechanism을 지원하지 않아 서버가 업로드를 진행할 수 없는 경우 422 Unprocessable Content를 반환해야 합니다. 서버는 파일의 병렬 업로드를 허용할 수도 있지만, 반드시 허용해야 하는 것은 아닙니다. 서버가 업로드를 진행할 수 없다고 판단하면 409 Conflict를 반환해야 합니다.

응답 본문

성공적인 응답에는 다음이 포함됩니다:

{
  "meta": {
    "api-version": "2.0"
  },
  "links": {
    "file-upload-session": "...",
    "complete": "...",
    "extend": "..."
  },
  "status": "pending",
  "expires-at": "2030-08-01T13:00:00Z",
  "mechanism": {
    "identifier": "http-post-bytes",
    "file_url": "...",
    "attestations_url": "..."
  }
}

클라이언트에 업데이트된 상태를 언제 다시 폴링해야 하는지 나타내려면 Retry-After 응답 헤더가 반드시 있어야 합니다.

요청 JSON과 동일한 형식인 meta 키 외에도 성공 응답에는 다음 키가 포함됩니다:

links
이 세션과 관련된 키와 URL을 매핑하는 딕셔너리이며, 자세한 내용은 아래에 제공됩니다.
status
파일 업로드 세션의 현재 상태를 나타내는 문자열이며, 유효한 값은 pending, processing, completed, errorcanceled입니다.
expires-at
서버가 이 파일 업로드 세션을 만료시킬 시점을 나타내는 RFC 3339 형식의 타임스탬프 문자열입니다. 이 문자열은 MUST UTC 타임스탬프를 나타내야 하며, “Zulu”(즉, Z) 마커를 사용하고 정수 초만 사용해야 합니다(즉, 소수 초는 사용하지 않습니다). 클라이언트가 세션을 취소하거나 완료하지 않는 한, 세션은 적어도 이 시점까지 활성 상태로 유지SHOULD 합니다. 서버는 이 만료 시간을 연장할 수 MAY 있지만, 더 이른 시점으로 변경해서는 안 됩니다.
mechanism
클라이언트와 서버가 협상한 지원되는 메커니즘에 필요한 세부 정보를 포함하는 매핑입니다. 이 매핑은 선택한 파일 업로드 메커니즘의 식별자 문자열에 매핑되는 identifier키를 포함MUST 합니다.

파일 업로드 세션 상태

파일 업로드 세션은 항상 다음 상태 중 정확히 하나에 있으며, 이는 파일 업로드 세션 상태 응답status키로 보고됩니다. 동일한 값이 게시 세션 상태files 매핑에서 해당 파일에 대해 반영되며, canceled는 예외입니다: 취소되거나 삭제된 파일은 해당 매핑에서 완전히 제거되고, 그 파일 자체의 상태 URL만 계속 canceled를 보고합니다.

파일 업로드 세션에 대한 상태 다이어그램입니다. 초기 상태에서 세션은 ``pending``\ 으로 진입하며, 이 동안 협상된 업로드 메커니즘이 실행됩니다. ``pending``\ 에서 업로드를 완료하면 즉시 성공(``201``)하여 ``completed``\ 로 전환되거나, 지연 처리를 위해 수락(``202``)되어 ``processing``\ 으로 전환되거나, 동기적으로 실패(``4xx``/``5xx``)하여 ``error``\ 로 전환됩니다. ``pending``\ 은 또한 취소(``DELETE``)되어 종단 상태인 ``canceled``\ 로 전환될 수 있습니다. ``processing``\ 은 성공 시 ``completed``\ 로, 실패 시 ``error``\ 로 귀결됩니다. ``completed``\ 와 ``error`` 둘 다 삭제(``DELETE``)되어 ``canceled``\ 로 전환될 수 있습니다. ``processing`` 중의 취소는 ``409``\ 로 거부됩니다.

각 상태에 대한 텍스트 설명과 전체 전이 표가 이어집니다.

pending
파일 업로드 세션이 생성되었고 협상된 업로드 메커니즘이 실행 중이며, 파일의 바이트가 전송 중이거나 아직 완전히 전송되지 않은 상태입니다. 새로 생성된 세션은 이 상태에서 시작하며, 클라이언트가 업로드를 완료하거나 취소할 때까지 이 상태로 유지됩니다. 업로드가 아직 pending상태인 파일은 교체할 수 없습니다.
processing
클라이언트가 완료를 요청했고 서버가 지연 처리를 위한 요청을 수락하여 202 Accepted를 반환한 상태입니다(파일 업로드 세션 완료 참조). 이는 전환 상태입니다. 클라이언트는 Retry-After헤더를 준수하면서 파일 업로드 세션 상태를 폴링하여 completed 또는 error로 확정될 때까지 확인합니다.
completed
파일이 완전히 업로드되고, 검증되었으며, 게시 세션에 수락된 상태입니다. 파일을 게시할 수 있는 유일한 상태입니다. 파일은 여전히 삭제할 수 있으며, 삭제하면 게시 세션에서 제거되고 이 세션은 canceled로 전환됩니다.
error
업로드에 실패했으며 파일은 사용할 수 없는 상태입니다. 오류 상태의 게시 세션와 달리, 파일 업로드 세션은 그 자리에서 복구할 수 없습니다. 클라이언트는 MUST 파일을 취소하거나 삭제하고, 계속 업로드하려는 경우 완전히 새로운 파일 업로드 세션을 시작해야 합니다. 완료 시도가 실패하면 파일 업로드 세션은 언제나 error상태가 됩니다. 서버가 complete 요청 내에서 동기식으로 실패를 감지하는 경우든, 세션이 processing 상태인 동안 비동기식으로 감지하는 경우든 동일합니다.
canceled (터미널)
세션이 취소되었거나(진행 중인 업로드) 완료된 파일이 삭제되었습니다. 세션 리소스와 연결된 업로드 메커니즘을 재사용할 수 있다고가정해서는 안 됩니다. 파일을 복구하거나 교체하려면 새로운 파일 업로드 세션이 필요합니다.

canceled만 터미널 상태입니다. completederror 상태에서도 DELETE를 실행할 수 있으며(세션을 canceled로 전환함), error에서는 삭제만 다음 작업으로 수행할 수 있습니다.

이러한 상태들 간의 전이는 다음과 같습니다:

출발 이벤트 도착
(없음) 파일 업로드 세션이 생성되었습니다(202 Accepted) pending
pending 업로드 메커니즘이 실행됩니다(바이트 전송됨) pending
pending 완료 요청이 즉시 완료되었습니다(201 Created) completed
pending 완료 요청이 지연 처리를 위해 수락되었습니다(202 Accepted) processing
pending 완료 요청이 동기적으로 실패합니다 error
pending 취소가 요청되었습니다(DELETE) canceled
processing 지연 처리가 성공합니다 completed
processing 지연 처리가 실패합니다 error
processing 취소가 요청되었습니다 409 Conflict로 거부됩니다(취소 및 삭제 참조)
completed 파일이 삭제되었습니다(DELETE) canceled
error 파일이 삭제되었습니다(DELETE) canceled

동기식 게시 실패가 세션을 편집 가능한 상태로 유지하고 오직 지연된 실패만 error 상태에 도달하는 게시 세션과 달리, 파일 업로드 세션은 부분적으로 또는 잘못 업로드된 파일을 제자리에서 편집할 수 없기 때문에 모든 완료 실패를 해당 파일에 대해 복구 불가능한 것으로 취급합니다. 따라서 동기식 완료 실패와 지연된 완료 실패 모두 세션을 error로 전환하며, 이 상태에서 클라이언트는 파일을 삭제하고 처음부터 다시 시작합니다.

파일 업로드 세션 완료

파일 업로드 메커니즘이 실행되었고 오류가 발생하지 않았음을 나타내는 파일 업로드 세션을 완료하려면, 클라이언트는 파일 업로드 세션 생성 응답 본문의 complete 링크POST를 발행합니다.

요청은 다음과 같습니다:

{
  "meta": {
    "api-version": "2.0"
  }
}

서버가 파일 업로드 세션을 즉시 완료할 수 있으면 그렇게 처리하고 201 Created 응답을 반환한 다음 파일 업로드 세션의 상태를 completed로 설정할 수 있습니다. 서버가 파일 업로드 세션을 즉시 완료할 수 없으면(예를 들어 단일 HTTP 요청에서 처리하기에 합리적인 시간보다 오래 걸릴 수 있는 검증을 수행해야 하는 경우) 202 Accepted 응답을 반환하고 파일 업로드 세션의 상태를 processing으로 설정할 수 있습니다.

어느 경우든 서버는 파일 업로드 세션 상태 URL을 가리키는 Location 헤더를 포함해야 합니다.

서버는 클라이언트가 파일 업로드 세션 상태 URL을 폴링하여 상태 변경을 확인할 수 있도록 반드시 허용해야 합니다. 서버가 202 Accepted로 응답하면 클라이언트는 파일 업로드 세션 상태 URL을 폴링하여 상태 변경을 확인할 수 있습니다. 클라이언트는 파일 업로드 세션 상태 응답의 Retry-After 헤더 값을 준수해야 합니다.

완료 시도가 동기식으로 실패하거나(이 경우 서버는 오류 응답도 반환함) 세션이 processing 상태인 동안 비동기식으로 실패하면 세션은 오류 상태로 전환됩니다. 이 상태에서 클라이언트는 파일을 취소하거나 삭제하고 재시도하려면 새로운 파일 업로드 세션을 시작해야 합니다.

취소 및 삭제

클라이언트는 진행 중인 파일 업로드 세션을 취소하거나 완전히 업로드된 파일을 삭제할 수 있습니다. 두 경우 모두 클라이언트는 삭제하려는 파일의 파일 업로드 세션 생성 응답에 있는 links.file-upload-session URL로 DELETE요청을 발행합니다.

성공적인 삭제 요청은 반드시 204 No Content로 응답해야 합니다.

세션이 pending 상태(진행 중인 업로드 취소), completed 상태(업로드된 파일 삭제) 또는 error 상태(실패한 업로드 폐기)인 동안에는 DELETE를 실행할 수 있습니다. 세션이 processing 상태인 경우, 즉 지연된 완료가 이미 진행 중인 경우에는 결과가 이미 결정되고 있으므로 서버는 DELETE409 Conflict반드시 거부해야 합니다. 대신 클라이언트는 처리가 완료될 때까지 기다린 다음 필요한 경우 파일을 삭제할 수 있습니다.

취소되거나 삭제된 후에는 클라이언트가 이전 파일 업로드 세션 리소스 또는 연결된 파일 업로드 메커니즘을 재사용할 수 있다고 절대로 가정해서는 안 됩니다.

일부 또는 전체가 업로드된 파일 교체

세션 파일을 교체하려면 파일 업로드가 이전에 완료되었거나 취소되었거나 삭제된 상태여야 반드시 합니다. 아직 업로드가 진행 중인 파일은 교체할 수 없습니다. 클라이언트가 교체를 시도하면 서버는 409 Conflict반드시 반환해야 합니다.

세션 파일을 교체하려면 클라이언트는 먼저 진행 중인 업로드를 취소하고 삭제해야 합니다. 그런 다음 전체 파일 업로드 순서를 다시 시작하여 새 파일 업로드를 시작할 수 있습니다. 이는 새 업로드 리소스 URL을 가져오기 위해 메타데이터 요청을 다시 제공한다는 의미입니다. 클라이언트는 삭제 후 이전 업로드 리소스 URL을 재사용할 수 있다고 가정해서는 안 됩니다.

파일 업로드 세션 상태

클라이언트는 파일 업로드 세션 생성 응답links.file-upload-session URL에 GET요청을 보내 파일 업로드 세션의 상태를 조회할 수 있습니다. 서버는 statusexpires-at의 변경 사항이 반영된 것을 제외하고, 파일 업로드 세션 생성 응답과 동일한 페이로드로 이 요청에 응답합니다.

파일 업로드 세션은 해당 세션이 속한 게시 세션과 독립적으로 존재하지 않으며, 이에 따라 상태 URL도 유지됩니다. 부모 게시 세션이 비종단 상태인 동안 서버는 각 파일 업로드 세션 상태 URL을 유효하게 유지하여, 클라이언트가 업로드한 파일의 결과를 확인할 수 있도록 파일 업로드 세션의 현재 status를 보고해야 합니다. 여기에는 종단 상태인 canceled도 포함됩니다. 상위 게시 세션 자체가 종료되면 해당 파일 업로드 세션 URL은 상위 세션의 자체 상태 URL보다 오래 유지되지 않으며, 이후 MAY 404 Not Found를 반환할 수 있습니다. 취소와 마찬가지로 이러한 URL의 데이터 제공 부분과 메커니즘 부분은 상태 URL과 무관하게, 기반 파일 데이터가 삭제되는 즉시 사용할 수 없게 될 수 있습니다.

파일 업로드 세션 확장

서버는 클라이언트가 파일 업로드 세션을 확장하도록 허용할 수 있지만, 전체 수명과 허용되는 확장 횟수는 서버에 맡겨집니다. 파일 업로드 세션을 확장하려면 클라이언트는 파일 업로드 세션 생성 응답extend링크POST요청을 보냅니다. 서버가 파일 업로드 세션 확장을 지원하지 않는 경우 응답에 links.extend 키가 포함되지 않습니다.

요청은 다음과 같습니다:

{
  "meta": {
    "api-version": "2.0"
  },
  "extend-for": 3600
}

지정된 초 수는 현재 파일 업로드 세션을 연장할 추가 초 수에 대한 서버への 제안일 뿐입니다. 예를 들어 클라이언트가 세션을 한 시간 더 연장하려는 경우 extend-for3600입니다. 확장이 성공하면 서버는 게시 세션을 처음 생성할 때 받은 것과 동일한 파일 업로드 세션 생성 응답 본문으로 응답하되, status 또는 expires-at의 변경 사항을 반영합니다.

서버가 요청된 초 수만큼 세션을 연장하는 것을 거부하더라도 성공 응답을 반환해야 하며, expires-at 키에는 단순히 세션의 현재 만료 시간이 반영됩니다.

스테이징된 미리 보기

게시되기 전에 스테이징된 릴리스를 미리 볼 수 있는 기능은 이 PEP의 중요한 기능이며, 릴리스가 일반에 공개되기 전에 최종 단계 테스트를 한 단계 더 수행할 수 있게 합니다. 패키지 색인은 게시 세션 생성 시 반환되는 links 키stage 하위 키에 제공된 URL을 통해 이 기능을 제공할 수 있습니다. stage URL은 해당 값으로 –extra-index-url 플래그를 설정하여 pip와 같은 설치 도구에 전달할 수 있습니다. 여러 값을 사용하여 이 플래그를 반복하면 여러 스테이지도 미리 볼 수 있습니다.

지원되는 경우 색인은 스테이징된 릴리스를 설치 도구에 노출하는 뷰를 반환하여, 최종 단계 테스트를 위해 구축된 가상 환경에서 해당 릴리스를 다운로드하고 설치할 수 있게 합니다. 이 옵션을 사용하면 기존 설치 도구를 변경하지 않고도 스테이징된 릴리스를 미리 볼 수 있습니다. 이 사용자 경험의 세부 사항은 설치 도구 유지 관리자에게 맡겨집니다.

파일 업로드 메커니즘

서버는 필수 파일 업로드 메커니즘을 구현해야 합니다. 이러한 메커니즘은 서버별 구현이 존재하지 않는 경우 폴백으로 사용됩니다.

Upload API의 각 주요 버전은 하나 이상의 필수 파일 업로드 메커니즘을 지정해야 합니다.

새로운 필수 메커니즘은 추가해서는 안 되며, 기존 필수 메커니즘은 주 버전 업데이트 없이는 제거해서는 안 됩니다. 추가되거나 제거되는 서버별 또는 실험적 메커니즘은 이 사양의 주 버전이나 부 버전 번호를 변경해서는 안 됩니다.

필수 파일 업로드 메커니즘

http-post-bytes

Upload API 버전 2.0을 준수하는 서버는 http-post-bytes 메커니즘을 지원해야 합니다.

이 메커니즘은 나머지 Upload 2.0 프로토콜 엔드포인트와 동일한 인증 방식을 사용해야 합니다.

클라이언트는 파일 업로드 세션 생성 응답 본문mechanism 맵에 있는 http-post-bytes 맵에서 반환된 file_urlPOST 요청을 다음과 같이 제출하여 이 메커니즘을 실행합니다:

Content-Type: application/octet-stream

<binary contents of the file to upload>

서버는 파일에 대한 디지털 증명서 업로드를 지원할 수 있습니다(PEP 740 참조). 이 지원 여부는 파일 업로드 세션 생성 응답 본문mechanism 맵에 있는 http-post-bytes 맵에 attestations_url 키를 포함하는 것으로 표시됩니다. 증명서는 파일 업로드 세션 완료 전에 attestations_url업로드해야 합니다.

증명서를 업로드하려면 클라이언트는 증명서 객체의 JSON 배열을 포함하는 attestations_url로의 POST 요청을 다음과 같이 제출합니다:

Content-Type: application/json

[{"version": 1, "verification_material": {...}, "envelope": {...}},...]

서버별 파일 업로드 메커니즘

특정 서버는 임의의 수의 서버별 메커니즘을 구현할 수 있으며, 그 사용 방법을 문서화할 책임이 있습니다.

서버별 구현 파일 업로드 메커니즘 식별자는 세 부분으로 구성됩니다:

<prefix>-<operator identifier>-<implementation identifier>

서버별 구현은 prefixvnd사용해야 합니다. operator identifier는 서버 운영자를 명확하게 식별하고, 잘 알려진 다른 색인과 중복되지 않으며, 영숫자 [a-z0-9]만 포함해야 합니다. implementation identifier는 기반 구현을 간결하게 설명하고 영숫자 [a-z0-9]-만 포함해야 합니다.

서버 운영자가 업로드 메커니즘을 호환성이 깨지는 방식으로 변경해야 하는 경우, 기존 식별자를 수정하기보다 새 메커니즘 식별자를 생성해야 합니다. 권장되는 패턴은 -v1, -v2 등과 같은 버전 접미사를 구현 식별자에 추가하는 것입니다. 이렇게 하면 클라이언트가 기존 클라이언트와의 하위 호환성을 유지하면서 새 버전을 명시적으로 선택할 수 있습니다.

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

파일 업로드 메커니즘 문자열 서버 운영자 메커니즘 설명
vnd-pypi-s3multipart-presigned PyPI 사전 서명된 URL을 통한 S3 멀티파트 업로드
vnd-pypi-s3multipart-presigned-v2 PyPI 버전 2 사전 서명된 URL을 통한 S3 멀티파트 업로드
vnd-pypi-http-fetch PyPI HTTP 요청을 통해 서버에 URL에서 가져오도록 지시하여 전달되는 파일입니다.
vnd-acmecorp-http-fetch Acme Corp HTTP 요청을 통해 서버에 URL에서 가져오도록 지시하여 전달되는 파일입니다.
vnd-acmecorp-postal Acme Corp 우편으로 전달되는 파일입니다.
vnd-widgetinc-stream-v1 Widget Inc. 스트리밍 업로드 프로토콜 버전 1입니다.
vnd-widgetinc-stream-v2 Widget Inc. 스트리밍 업로드 프로토콜 버전 2입니다.
vnd-madscience-quantumentanglement Mad Science Labs 양자 얽힘을 통한 업로드입니다.

서버가 다른 서버 구현의 동작을 정확히 일치시키려는 경우, 해당 구현의 파일 업로드 메커니즘 이름으로 응답할 있습니다.

클라이언트 구현자를 위한 권장 사항

이 절은 비규범적이며 Upload 2.0 프로토콜을 구현하는 클라이언트 도구 작성자에게 지침을 제공합니다. 이러한 권장 사항은 프로토콜의 예상 사용 패턴에 기반한 제안이며, 클라이언트 작성자는 사용자의 요구에 가장 적합한 대체 접근 방식을 자유롭게 구현할 수 있습니다.

일반 워크플로

Upload 2.0 프로토콜을 사용하는 일반적인 업로드 워크플로는 다음 단계로 진행됩니다.

  1. 프로젝트 이름과 버전에 대한 게시 세션을 생성하십시오.
  2. 각 아티팩트(sdist, wheels)에 대해 파일 업로드 세션 생성을 수행하고, 협상된 업로드 메커니즘을 실행한 다음, 파일 업로드 세션 완료를 수행하십시오.
  3. 선택적으로 색인이 스테이지 미리 보기를 지원하는 경우, 게시하기 전에 릴리스를 테스트하려면 links.stage URL을 사용하십시오.
  4. 릴리스를 공개하려면 세션 게시를 수행하고, 문제가 발견되면 세션 취소를 수행하십시오.

클라이언트는 각 단계에서 실패를 원활하게 처리해야 합니다. 파일 업로드 중 오류가 발생하면 클라이언트는 파일 업로드 세션 취소를 수행해야 합니다. 어느 시점에서든 복구할 수 없는 오류가 발생하면, 서버 측 리소스를 정리하기 위해 클라이언트는 게시 세션 취소를 수행해야 합니다.

병렬 업로드

클라이언트는 동일한 게시 세션 내에서 여러 파일 업로드 세션을 동시에 생성하고 실행하여 여러 파일을 병렬로 업로드할 MAY 수 있습니다. 이를 통해 휠 변형이 많은 릴리스의 업로드 시간을 크게 단축할 수 있습니다. 그러나 클라이언트는 병렬 업로드를 지원하지 않는 서버가 있을 수 있으며, 병렬 업로드를 시도하면 409 Conflict를 반환할 수 있음에 대비해야 합니다.

여러 세션

클라이언트는 업로드할 아티팩트의 구성에 따라 단일 세션을 생성하고 관리할지, 여러 세션을 순차적으로 생성하고 관리할지, 또는 여러 세션을 병렬로 생성하고 관리할지 결정할 수 있습니다. 게시 세션은 특정 이름-버전 식별자에 연결되므로, 단일 클라이언트 명령이 서로 다른 여러 이름-버전 아티팩트를 업로드하려는 경우 각 아티팩트는 별도의 게시 세션에 있어야 합니다.

예를 들어, twine upload foo-1.1.tar.gz foo-2.0.tar.gz bar-2.0.tar.gz 는 세 개의 별도 게시 세션이 필요하지만, 각 sdist에 이름과 버전이 일치하는 휠도 함께 제공된다면 세 개의 게시 세션으로 충분합니다. 클라이언트는 이 모든 작업을 내부적으로 관리할 수 있어야 합니다.

세션 관리

클라이언트는 세션 응답의 expires-at 타임스탬프를 모니터링해야 합니다. 장시간 실행되는 업로드의 경우(예: 연결 속도가 느릴 때 대용량 파일을 업로드하는 경우), links.extend 엔드포인트를 사용할 수 있다면 세션 연장 요청이 필요할 수 있습니다. 서버가 연장을 지원하지 않는 경우(links.extend의 부재로 알 수 있음), 업로드가 세션 수명을 초과할 수 있을 때 클라이언트는 사용자에게 경고해야 합니다.

제안하는 명령줄 인터페이스

다음 예시는 기존 도구가 Upload 2.0 프로토콜을 사용자에게 어떻게 제공할 수 있는지 보여 줍니다. 이는 제안일 뿐이며, 실제 구현은 달라질 수 있습니다.

twine

twine는 현재 간단한 twine upload dist/* 명령을 제공합니다. Upload 2.0 프로토콜은 추가 옵션을 통해 제공할 수 있습니다.

twine upload dist/*
하위 호환성을 유지합니다. 사용 가능한 경우 Upload 2.0 프로토콜을 사용하고, 그렇지 않으면 레거시 프로토콜로 대체합니다. 세션을 생성하고 모든 파일을 업로드한 다음 즉시 게시합니다.
twine upload --stage dist/*
Upload 2.0 프로토콜을 사용하여 세션을 생성하고 파일을 업로드하지만 게시하지는 않습니다. 색인이 스테이지 미리 보기 URL을 지원하지 않는 경우에도 유용합니다. Upload 2.0의 원자적 릴리스 의미 체계를 제공하기 때문입니다. 색인이 스테이지 미리 보기를 지원하면 테스트를 위해 links.stage URL을 출력합니다. 후속 명령에서 사용할 수 있는 세션 식별자를 출력합니다. 이 세션 식별자는 클라이언트에 로컬이며, 진행 중인 서버 세션에 내부적으로 매핑됩니다.
twine session publish <session-id>
이전에 스테이징된 세션을 게시합니다.
twine session cancel <session-id>
스테이징된 세션을 취소하고 업로드된 모든 파일을 삭제합니다.
twine session status <session-id>
세션의 현재 상태를 조회하고 표시합니다.

uv

uv은 추가 통합 기능과 함께 유사한 기능을 제공할 수 있습니다:

uv publish dist/*
세션을 생성하고 모든 파일을 업로드한 후 게시합니다. 여러 휠을 더 빠르게 게시하기 위해 병렬 업로드를 활용할 수 있습니다.
uv publish --stage dist/*
게시하지 않고 업로드합니다. 스테이지 미리 보기를 지원하지 않더라도 twine과 마찬가지로 유용합니다. uv session 하위 명령에서 사용할 수 있는 세션 식별자를 출력합니다.
uv publish --test-install dist/*
패키지 색인이 스테이지 미리 보기를 지원하는 경우 파일을 업로드하고, 스테이지 URL에서 패키지를 임시 가상 환경으로 설치하며, 선택적으로 스모크 테스트 명령을 실행한 후 성공한 경우에만 게시합니다. 이를 통해 통합된 “업로드, 테스트, 게시” 작업 흐름을 제공합니다.
uv session publish <session-id>
이전에 스테이징한 세션을 게시합니다.
uv session cancel <session-id>
스테이징한 세션을 취소하고 업로드된 모든 파일을 삭제합니다.
uv session status <session-id>
세션의 현재 상태를 조회하고 표시합니다.

GitHub Actions

pypa/gh-action-pypi-publish 액션은 강력한 CI/CD 작업 흐름을 구현하기 위해 스테이징된 릴리스를 활용할 수 있습니다. 여러 작업으로 구성된 작업 흐름은 다음과 같을 수 있습니다:

jobs:
  upload:
    runs-on: ubuntu-latest
    outputs:
      stage-url: ${{ steps.upload.outputs.stage-url }}
      session-id: ${{ steps.upload.outputs.session-id }}
    steps:
      - uses: actions/download-artifact@v4
        with:
          name: dist
          path: dist/
      - id: upload
        uses: pypa/gh-action-pypi-publish@v2
        with:
          stage: true  # Upload but don't publish

  test:
    needs: upload
    runs-on: ubuntu-latest
    steps:
      - uses: actions/setup-python@v5
      - name: Test staged release
        run: |
          pip install --extra-index-url "${{ needs.upload.outputs.stage-url }}" my-package
          python -c "import my_package; my_package.smoke_test()"

  publish:
    needs: [upload, test]
    runs-on: ubuntu-latest
    steps:
      - uses: pypa/gh-action-pypi-publish@v2
        with:
          publish-session: ${{ needs.upload.outputs.session-id }}

이 패턴을 사용하면 실제 PyPI 아티팩트를 게시하기 전에 현실적인 설치 시나리오에서 테스트할 수 있습니다. 테스트 작업이 실패하면 작업 흐름에 세션을 취소하는 정리 작업을 포함할 수 있습니다:

cancel-on-failure:
  needs: [upload, test]
  if: failure()
  runs-on: ubuntu-latest
  steps:
    - uses: pypa/gh-action-pypi-publish@v2
      with:
        cancel-session: ${{ needs.upload.outputs.session-id }}

패키지 색인이 스테이지 미리 보기 URL을 지원하지 않는 경우에도 스테이징된 업로드 패턴은 모든 아티팩트를 함께 게시하거나 아무것도 게시하지 않는 원자적 릴리스를 보장하므로 여전히 유용합니다.

오류 처리

클라이언트는 여러 단계로 구성된 업로드 프로세스에 대해 강력한 오류 처리를 구현해야 합니다:

파일 업로드 실패: 파일 업로드가 실패하면(네트워크 오류, 유효성 검사 오류 등) 클라이언트는 재시도하기 전에 해당 파일 업로드 세션을 취소해야 합니다. 그런 다음 클라이언트는 동일한 파일 이름에 대해 새로운 파일 업로드 세션을 생성할 수 있습니다.

부분 업로드 복구: 일부 파일은 성공적으로 업로드되었지만 다른 파일의 업로드가 실패한 경우 클라이언트에는 다음과 같은 선택지가 있습니다:

  • 전체 게시 세션을 취소하고 처음부터 다시 시작합니다.
  • 실패한 파일 업로드 세션만 취소하고 해당 파일을 다시 시도하십시오.
  • --stage 모드를 사용하는 경우 수동 개입을 위해 세션을 열어 두십시오.

세션 만료: 업로드 중 세션이 만료되면 클라이언트는 새 게시 세션을 생성하고 모든 파일을 다시 업로드해야 합니다. 클라이언트는 expires-at를 모니터링하고 사용자에게 사전에 경고해야 합니다.

게시 실패: 게시 요청이 실패하면 세션은 현재 상태로 유지됩니다. 클라이언트는 세션 상태를 조회하여 원인을 확인하고 게시 작업을 다시 시도할 수 있습니다.

정상적인 취소: 사용자가 업로드를 중단하는 경우(예: Ctrl+C), 클라이언트는 서버에 고아 세션이 남지 않도록 게시 세션을 취소하려고 시도해야 합니다.

레거시 API 폴백입니다.

전환 기간 동안 클라이언트는 Upload 2.0 및 레거시 프로토콜을 모두 SHOULD 지원해야 합니다. 권장되는 접근 방식은 다음과 같습니다.

  1. 2.0 엔드포인트를 확인하거나 콘텐츠 협상을 사용하여 Upload 2.0을 사용하도록 시도하십시오.
  2. 서버가 Upload 2.0을 지원하지 않는 경우(예: 404 또는 406을 반환하는 경우), 레거시 프로토콜로 폴백하십시오.
  3. 디버깅 또는 하위 호환성을 위해 필요한 경우 특정 프로토콜 버전을 강제하는 명령줄 옵션을 제공하십시오.

보안 관련 사항입니다.

이름 선점 가능성입니다.

PEP 694가 프로젝트 이름을 악의적으로 등록하여 이름 선점 또는 오타 선점을 더 쉽게 만들까요? 저자들은 그렇지 않다고 봅니다. 레거시 API를 사용하면 프로젝트 이름을 등록하기 위해 더미 패키지를 생성하고 업로드하는 일이 매우 쉽습니다. 이 PEP는 어느 쪽으로도 이러한 상황을 실질적으로 변경하지 않으며, 변경을 목표로 하지도 않습니다. 다만 PyPI와 같은 색인은 프로젝트 등록 활동에 추가적인 제한을 둘 수 있습니다. 예를 들어 빈 패키지나 세션에 대해 레거시 API 또는 Upload 2.0 API의 요청률을 제한할 수 있습니다. 조직 또는 PEP 752-스타일의 암시적 네임스페이스를 지원하는 PyPI와 같은 색인은 행위자마다 서로 다른 요청률 제한 규칙을 구현할 수 있습니다. 이러한 구현은 색인별 정책 결정에 맡겨집니다.

세션 권한 부여입니다.

세션 액세스 권한은 세션을 생성한 자격 증명에 연결되는 것이 아니라 현재 시점에 부여됩니다(Authentication 참조). 색인은 각 세션 요청에서 권한을 다시 검증해야 MUST 합니다. 여기에는 아티팩트 업로드, 파일 업로드 세션 완료, 세션 연장 요청 및 게시가 포함됩니다. 이를 통해 세션이 열려 있는 동안 업로드 권한을 잃은 주체는 이후 요청이 거부되고, 권한을 얻은 주체는 열린 세션에 참여할 수 있습니다.

이 모델에는 언급할 가치가 있는 두 가지 결과가 있습니다. 첫째, 모든 변경 작업에 동일하게 권한이 부여되므로 현재 프로젝트에 업로드할 권한이 있는 주체는 다른 주체의 열린 세션에 추가하거나, 이를 취소하거나, 게시할 수 있습니다. 게시된 아티팩트는 변경할 수 없고 게시 작업은 원자적으로 수행되므로, 영향 범위는 게시되지 않은 스테이징 세션으로 제한됩니다. 둘째로, stage preview URL은 업로드 권한으로 제한되지 않는 기능이므로, 세션 중간에 권한이 취소되었더라도 이미 stage URL을 획득한 주체는 세션이 게시되거나 취소될 때까지 스테이징된 파일에 대한 읽기 전용 미리 보기 액세스 권한을 유지합니다. 이는 범위가 좁고 수용된 제한 사항입니다. 이를 우려하는 색인은 해당 세션을 취소하거나 세션 수명 및 연장을 제한하여 완화할 수 있습니다.

악성 코드 호스팅 가능성입니다.

스테이징된 릴리스는 테스트와 엠바고에 유용하지만, 스테이징된 아티팩트는 스테이징 토큰/URL을 보유한 클라이언트에게만 표시되므로 제3자 외부 검사 도구로 탐지되지 않는 악성 코드가 더 큰 규모로 호스팅될 가능성도 어느 정도 제공합니다. PyPI와 같은 색인에서 현재 실제로 어느 정도의 사전 예방적 악성 코드 검사가 수행되고 있는지는 명확하지 않으므로, (선택적) 스테이징 기능이 추가적인 악성 코드 유포 경로를 크게 늘리는지는 불분명합니다. 색인은 아티팩트를 업로드하는 데 사용된 프로토콜과 관계없이 모든 아티팩트에 대해 일정 수준의 사전 예방적 악성 코드 검사를 수행해야 할 가능성이 높습니다. 이 PEP에서 제안하는 다단계 프로토콜을 통해 색인은 검사를 지원할 수 있는 신뢰할 수 있는 제3자 보안 파트너와 세션 링크 또는 업로드된 스테이징 파일을 공유할 수 있습니다.

색인은 세션 연장에 제한을 설정하여 이 문제를 완화할 수도 있으며, 이러한 제한은 프로젝트를 소유한 사용자 또는 (PyPI의 경우) 조직에 따라 프로젝트별로 달라질 수 있습니다. 색인은 세션 연장을 거부할 수 있으며, 이를 통해 콘텐츠가 검증되지 않은 패키지의 이용 가능성을 제한할 수 있습니다.

테스트 및 엠바고 사용 사례를 고려하면 서로 다른 세션 만료 선택이 필요할 수 있습니다. 릴리스를 테스트하는 세션의 수명은 비교적 짧을 수 있으며, 예를 들어 몇 시간 정도일 수 있습니다. 엠바고 세션은 며칠 또는 몇 주 동안 연장해야 할 수 있습니다. PyPI와 같은 색인은 특정 세션의 전체 수명을 결정하기 위해 자격 증명이 사용자용인지 조직용인지 여부와 같은 여러 기준을 사용할 수 있습니다. 색인은 테스트 사용 사례가 사용되고 있는지 또는 엠바고 사용 사례가 사용되고 있는지를 결정하기 위해 선택적 색인별 메타데이터를 지원할 수도 있습니다.

자주 묻는 질문

이는 PyPI가 레거시 업로드 API 지원을 중단할 계획이라는 의미입니까?

현재 PyPI에는 레거시 업로드 API 지원을 중단할 구체적인 계획이 없습니다.

관련 PEP 691과 달리 그렇게 하는 데에는 상당한 이점이 있으므로, 레거시 업로드 API 지원은 미래의 어느 시점에 (책임 있는 방식으로) 사용 중단 처리되고 제거될 가능성이 큽니다. 이러한 향후 폐기 계획은 명시적으로 PEP의 범위를 벗어납니다.

업로드 2.0 API를 사용하여 프로젝트 이름을 예약할 수 있습니까?

예! 아직 릴리스를 만들 파일을 업로드할 준비가 되지 않았더라도 프로젝트 이름을 예약할 수 있습니다(물론 해당 이름이 이미 존재하지 않는다는 전제하에).

이를 위해 새 퍼블리싱 세션을 생성하고, 파일을 업로드하지 않은 채 세션을 퍼블리시하십시오. 세션 생성 요청의 JSON 본문에는 version 키가 필요하지만, "0.0.0a0"과 같은 자리 표시자 버전 번호를 간단히 사용할 수 있습니다. 아티팩트가 업로드되지 않으면 버전은 무시됩니다.

일반적으로 세션을 생성한 사용자가 새 프로젝트의 소유자가 되지만, 색인은 index-specific metadata를 정의하여 예를 들어 퍼블리셔가 구성원인 조직이 새 프로젝트를 소유하도록 허용할 수 있습니다.

퍼블리싱 세션을 생성할 때 프로젝트 이름이 필요한 이유는 무엇입니까?

색인 권한은 근본적으로 프로젝트 소유권에 연결되어 있으므로 세션 생성 시 프로젝트 이름이 필요합니다. 사용자에게는 특정 프로젝트에 대한 역할과 권한이 있으며, 업로드를 진행하기 전에 이러한 권한을 확인해야 합니다.

프로젝트 이름을 미리 요구하면 다음과 같은 여러 이점이 있습니다.

즉각적인 권한 검증: 서버는 세션 생성 시 인증된 사용자에게 프로젝트 업로드 권한이 있는지 확인할 수 있으므로, 파일이 업로드된 후 권한 문제를 발견하는 대신 명확한 오류와 함께 신속하게 실패할 수 있습니다.

단순화된 오류 처리: 세션이 여러 프로젝트에 걸쳐 있을 수 있다면 업로드 중 한 프로젝트에서 권한 오류가 발생할 때 세션이 복잡한 부분 상태에 놓이게 됩니다. 세션당 프로젝트가 하나이면 권한 오류가 모호하지 않습니다.

Trusted Publisher 호환성: PyPI와 같은 색인은 OIDC 토큰의 범위가 특정 프로젝트로 제한되는 Trusted Publishers를 지원합니다. 단일 프로젝트 세션은 이 인증 모델에 자연스럽게 부합합니다.

할당량 적용: 프로젝트마다 업로드 할당량이나 크기 제한이 다를 수 있습니다. 프로젝트를 세션 생성 시점에 알고 있으면 이러한 제약 조건을 미리 검증하기가 더 간단합니다.

원자적 릴리스 의미 체계: 게시 세션은 단일 프로젝트 버전의 원자적 릴리스를 나타냅니다. 여러 프로젝트를 허용하면 이 모델이 근본적으로 변경되고 세션에서 “게시”가 무엇을 의미하는지 정의하기가 복잡해집니다.

단일 프로젝트 제한이 있더라도 이 PEP는 여전히 다중 프로젝트 릴리스를 개선합니다. 여러 프로젝트를 한 번에 릴리스하는 클라이언트는 최종 단계에서 각 프로젝트를 차례로 publishes하기 전에 모든 프로젝트를 완전히 stage할 수 있습니다 – 프로젝트마다 게시 세션을 생성하고 해당 프로젝트의 모든 아티팩트를 업로드합니다. 따라서 각 게시가 여전히 프로젝트별로 자체 원자성을 유지하더라도 전체 집합에 대해 “모두 준비한 다음 게시”하는 작업 흐름을 제공합니다.

단일 프로젝트 세션은 이미 준비된 여러 세션의 게시를 조정하는 별도의 엔드포인트로서 향후 “여러 프로젝트 게시” 작업이 기반으로 삼을 토대도 마련하며, 여기에서 정의한 세션별 모델은 변경하지 않습니다.

게시 세션을 생성할 때 버전이 필요한 이유는 무엇입니까?

모든 파일 업로드가 시작되기 전에 검증 계약을 설정하려면 세션 생성 시 버전이 필요합니다. 아티팩트 파일 이름에는 버전이 인코딩되므로(sdistwheel 파일 이름 명세에 따름), 서버는 업로드된 모든 파일이 선언된 버전과 일치하는지 검증할 수 있습니다.

이 설계를 통해 parallel uploads에서도 결정론적인 동작이 가능합니다. 버전이 선택 사항이고 처음 업로드된 파일에서 추론된다면, 여러 파일이 병렬로 업로드될 때 경쟁 조건이 발생합니다. 서버가 먼저 처리하는 업로드가 버전을 “승리”하여 설정하고, 버전이 일치하지 않는 다른 업로드는 비결정적으로 실패하기 때문입니다.

버전을 미리 요구하면 모든 병렬 업로드가 동일하게 선언된 버전에 대해 검증됩니다. 버전이 일치하지 않는 파일은 업로드 시점이나 순서와 관계없이 항상 실패합니다.

아티팩트가 업로드되지 않는 name registration의 경우, 세션에 파일이 포함되지 않으면 버전이 무시되므로 "0.0.0a0"과 같은 유효한 자리 표시자를 사용할 수 있습니다.

미해결 질문

Upload 2.0 프로토콜의 확장

업로드 처리 완료를 알리는 비동기 웹훅 알림과 같은 기능이 이 PEP를 검토하는 동안 논의되었습니다. 업로드 프로토콜을 위한 기능 확장이라는 개념도 논의되었으며, 이를 통해 구현자는 비동기 알림이나 웹훅과 같은 선택적 기능에 대한 지원을 제공한다고 알릴 수 있습니다.

Upload 2.0이 배포되는 과정에서 이러한 확장 프로토콜을 설계하고 생태계가 과도하게 분열되지 않도록 보장하는 데 복잡성이 발생할 수 있으므로 이 아이디어는 미결 상태로 남겨졌습니다.

업로드 프로토콜의 향후 개정판은 Upload 2.0을 운영하며 경험을 쌓아감에 따라 이러한 확장을 탐구해야 합니다.

각주

변경 이력

  • 29-Jul-2026
    • 원자적 게시 및 충돌 섹션을 추가합니다. 게시가 릴리스의 파일 이름 네임스페이스에 대해 원자적으로 수행된다는 점을 명시합니다. 서버는 게시가 진행되는 동안 세션의 파일 이름을 예약하므로 동시 업로드(레거시 API를 통한 업로드 포함)는 409 Conflict를 받고, 게시가 실패하면 예약을 해제합니다. 파일 업로드 세션 생성 시의 충돌 확인은 최선의 노력으로 수행되며 권위 있는 확인은 게시 시점에 원자적으로 수행된다는 점을 명확히 합니다. 이 결과는 동기적으로 409 Conflict로 보고되거나, 지연된 게시의 경우 사유를 notices에 기록한 채 세션을 error 상태로 전환하여 보고됩니다.
    • 세션 상태 보존 섹션을 추가합니다. 세션이 종단 상태(published 또는 canceled)에 도달한 후 서버는 인덱스별 보존 기간 동안 종단 상태를 보고하는 상태 URL을 SHOULD 계속 제공해야 하며, 그 이후에는 MAY 404 Not Found를 반환할 수 있습니다. 클라이언트는 이러한 404에 대비해야 합니다. 이에 맞게 취소 규칙을 조정합니다. 삭제된 후에는 데이터를 제공하는 URL과 작업 URL을 사용할 수 없게 될 수 있지만, 상태 URL은 보존됩니다. 파일 업로드 세션 상태 URL의 보존을 상위 게시 세션과 연계하십시오. 상위 세션이 종단 상태가 아닌 동안 서버는 해당 파일 업로드 세션 상태 URL을 SHOULD 유효하게 유지해야 하며, 상위 세션이 종료되면 해당 URL은 상위 세션의 상태 URL보다 오래 유지되지 않습니다.
    • 이전에는 허용했던 것을 변경하여, 이전 릴리스가 없는 프로젝트를 위한 세션을 생성할 때 인덱스가 프로젝트 이름을 예약하도록 요구합니다. 예약은 임시적이며(스테이지의 수명 동안만 유지되고, 게시 시 영구화되며, 스테이지가 취소되면 해제됨), 새 프로젝트를 처음 업로드하기 위해 서로 다른 두 클라이언트가 각각 스테이지를 생성하고 먼저 게시한 쪽이 이름을 차지하는 이름 선점 경쟁 조건을 방지하기 위해 존재합니다.
    • “프로젝트 이름이 필요한 이유” FAQ를 확장하여, 단일 프로젝트 세션도 다중 프로젝트 릴리스를 개선한다는 점(최종 단계에서 각 프로젝트를 게시하기 전에 모든 프로젝트를 완전히 스테이징할 수 있음)과 향후 “여러 프로젝트 게시” 엔드포인트를 위한 기반을 마련한다는 점을 설명합니다.
    • 파일 업로드가 아직 진행 중인 동안 세션 게시가 요청되면 어떻게 처리되는지 정의합니다. 이전에는 이 동작이 지정되지 않았습니다. 이제 게시에는 명시적인 선행 조건이 있습니다. 세션의 files 매핑에 있는 모든 항목은 completed 상태여야 MUST 하며, 그렇지 않으면 서버는 문제가 있는 파일을 식별하는 409 Conflict와 함께 게시 요청을 MUST 거부하고 세션을 편집 가능한 상태로 유지해야 합니다. 이 규칙은 허용 목록 방식으로 작성되므로, error 상태의 파일과 향후 개정판에서 추가되는 모든 파일 상태는 조용히 포함되거나 삭제되지 않고 게시를 차단합니다. 게시 세션 전이 표에 해당 행을 추가하고, 파일 이름 예약 범위를 세션이 게시할 완전히 업로드된 파일로 한정합니다.
    • 게시 세션은 파일 상태와 관계없이 MUST 취소할 수 있어야 하며, 특히 파일 업로드 세션이 processing 상태라는 이유로 취소를 거부해서는 MUST NOT 합니다. 취소하면 아무것도 게시되지 않음이 보장되므로 진행 중인 검증 결과는 결과에 영향을 미칠 수 없습니다. 따라서 개별 파일 삭제와 달리 보호해야 할 경쟁 상태가 없으며, 서버는 진행 중인 처리가 완료되도록 두고 결과를 폐기할 수 있고, 이를 중단하지 MAY 않습니다.
    • 파일 업로드 세션의 complete 상태를 completed로 이름을 변경합니다. 이는 다른 종결 상태(canceled 및 게시 세션의 published)의 과거분사형과 일치하며, state와 이름을 유지하는 complete actionlinks.complete 엔드포인트를 구분합니다.
    • 게시 세션의 files 매핑에서 status 키의 유효한 값에서 canceled를 제거하여, 파일을 취소하거나 삭제하면 해당 매핑에서 항목이 제거된다는 기존 규칙과의 모순을 해결합니다. 해당 파일 자체의 파일 업로드 세션 상태 URL은 계속 canceled를 보고합니다.
  • 26-Jun-2026
    • 이제 세션 작업은 요청 본문의 action 키 대신 전용 엔드포인트 링크를 사용합니다. 게시 세션에는 links.publishlinks.extend를 추가하고, 파일 업로드 세션에는 links.completelinks.extend를 추가합니다. 이제 links.sessionlinks.file-upload-session 엔드포인트는 GET(상태) 및 DELETE(취소) 작업에만 사용됩니다.
    • twine, uv 및 GitHub Actions와 같은 도구에 권장되는 UX 패턴을 포함하는 비규범적 클라이언트 구현자를 위한 권장 사항 섹션을 추가합니다.
    • 세션 생성 시 프로젝트 이름과 버전이 필요한 이유를 설명하는 FAQ 항목을 추가합니다.
    • 다음 보안 관련 사항입니다. 섹션을 추가하십시오.
    • 진행 중인 파일 업로드를 대체하려고 시도하면 409 Conflict를 반환한다고 명시합니다.
    • 기존 릴리스에 이미 게시된 파일과 일치하는 파일을 업로드하면 409 Conflict를 반환한다고 명시합니다. 게시된 아티팩트는 변경할 수 없기 때문입니다.
    • Multiple Sessions 클라이언트 권장 사항 예제의 문구를 명확히 합니다.
    • 세션 접근을 세션을 생성한 정확한 자격 증명으로 제한하지 않고, 프로젝트에 업로드할 권한이 있는 모든 주체로 완화하며 각 요청 시점에 이를 평가합니다. 인증 및 권한 부여 모델을 추가하고, 세션 중간의 권한 변경을 처리하며, Trusted Publishing 토큰 교체와 여러 게시자의 단일 세션 공동 기여를 지원하고, 관련 보안 영향을 설명합니다.
    • 파일 업로드 세션 생성 요청에서 선택적 metadata 키를 제거합니다. 업로드된 파일이 메타데이터의 권위 있는 원본이며, 인덱스가 파일 자체에서 메타데이터를 추출합니다.
    • 명시적인 게시 세션 상태 머신을 정의합니다. 세션 수준의 pending상태를 open으로 변경하고, 지연된 (202 Accepted) 게시를 위한 과도기적 processing상태를 추가하며, error상태를 실패한 지연 게시를 기록하면서도 계속 편집할 수 있는 상태로 문서화합니다(이유는 notices에 보고합니다). Publishing Session States섹션을 상태 설명 및 전이 표와 함께 추가하고, 동기식 게시 실패 시 세션이 error상태로 전환되지 않고 편집 가능한 상태로 유지되도록 명시하며, 세션이 processing상태인 동안 서버가 취소 요청을 409 Conflict로 거부하도록 요구합니다. Multiple Session Creation Requests규칙을 pending이 아닌 모든 비종료 상태를 기준으로 적용합니다.
    • File Upload Session States섹션과 전이 표를 사용하여 파일 업로드 세션 상태 머신을 문서화합니다. 동기식이든 지연된 것이든 모든 완료 실패는 세션을 error 상태로 이동시키며, error 파일은 그 자리에서 복구할 수 없습니다. 클라이언트는 해당 파일을 취소하거나 삭제하고 새로운 파일 업로드 세션을 시작해야 하며, 서버는 세션이 processing 상태인 동안의 DELETE409 Conflict와 함께 MUST 거부해야 합니다.
    • 기존 전이 표와 함께 Publishing Session StatesFile Upload Session States섹션에 상태 전이 다이어그램을 추가합니다.
    • 제안된 twineuv 명령줄 인터페이스를 일관되게 만들기 위해 스테이징 세션 작업을 session서브커맨드(session publish/session cancel/session status) 아래에 그룹화하고, uvtwine 과 동일한 스테이징 세션 후속 작업 및 세션 ID 출력을 제공하며, GitHub Action의 stage입력을 --stage플래그에 맞춥니다.
  • 07-Dec-2025
    • 오류 응답은 RFC 9457 형식을 준수합니다.
  • 23-Sep-2025
    • noncegentoken() 알고리즘을 제거합니다. 이제 인덱스가 암호학적으로 안전한 세션 토큰과 난독화된 스테이지 URL을 생성할 책임을 집니다(단, 스테이징 미리 보기를 지원하는 경우에만 해당합니다).
    • 여러 세션 생성 요청이 수신될 때의 의미를 명확히 합니다.
    • 상태 폴링 및 세션 연장과 같은 게시 세션 단계를 명확히 합니다.
    • name 이 정규화 규칙을 준수하도록 요구하고 링크를 포함합니다.
    • version 이 버전 사양을 준수하도록 요구하고 링크를 포함합니다.
    • filename 이 소스 또는 바이너리 배포 파일 이름 규칙 중 하나를 준수하도록 요구하고 링크를 포함합니다.
    • 타임스탬프 사양으로 ISO 8601 대신 RFC 3399를 참조합니다. RFC는 ISO 표준의 부분집합인 더 단순한 형식이며, 이 사용 사례에 더 적합합니다.
    • 기타 프로토콜을 명확히 합니다.
    • 선택적 인덱스별 메타데이터 키를 추가합니다.
  • 06-Aug-2025
    • Dustin을 PEP 위임자로 추가합니다.
  • 14-Apr-2025
    • PyCon US 논의를 바탕으로 업데이트합니다.
    • 충분히 명시되지 않았던 일부 오류 반환 코드 설명을 추가했습니다.
    • 업로드 파일의 취소 및 삭제 섹션을 통합합니다.
    • 스테이징되었지만 아직 게시되지 않은 파일을 교체하는 규칙을 단순화합니다.
    • 스테이지 미리 보기 지연에 대한 미해결 질문을 추가합니다.
    • 일부 철자 오류와 부적절한 표현을 수정합니다.
  • 06-Jan-2025
    • PEP를 부활시키고 업데이트합니다.
    • Barry를 공동 저자로 추가했습니다.
    • “draft” 대신 “stage”를 사용하도록 용어를 표준화합니다.
    • PyPI의 루트 URL로 https://upload.pypi.org/2.0을 제안했습니다.
    • 세션 난독화를 위한 선택적 nonce 키를 추가했습니다.
    • JSON 키를 표준화하고 용어와 일관되도록 했습니다.
    • 여러 API를 추가하고 수정하여 누락된 부분을 보완하고 세부 사항을 구체화했습니다.
    • 업로드 프로토콜을 인터넷 표준 초안에 맞췄습니다.