Skip to content

Commit 3ccfe41

Browse files
committed
Clarify some gaps in the protocol
* When some file uploads are still being processing, publication of the session now MUST explicitly return a 409 conflict. Previously this was unspecified. * The file upload session `complete` status was renamed to `completed` for clarity and consistency. * Clarify that publishing sessions MUST be cancelable, regardless of the state of its file upload sessions. * Removed `canceled` from the list of valid values in the `files` status mapping, since canceling a file upload purges all state about that file.
1 parent 9bb3132 commit 3ccfe41

2 files changed

Lines changed: 76 additions & 24 deletions

File tree

peps/pep-0694.rst

Lines changed: 75 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -561,14 +561,16 @@ The ``files`` key contains a mapping from the names of the files uploaded in thi
561561
sub-mapping with the following keys:
562562

563563
``status``
564-
A string with valid values
565-
``pending``, ``processing``, ``complete``, ``error``, and ``canceled``.
566-
If there was an error during upload,
567-
then clients should not assume the file is in any usable state,
568-
``error`` will be returned and it's best to
569-
:ref:`cancel or delete <file-upload-session-cancellation>` the file and start over.
570-
This action would remove the file name from the ``files`` key of the
571-
:ref:`session status response body <publishing-session-response>`.
564+
A string with valid values ``pending``, ``processing``, ``completed``, and ``error``, mirroring
565+
the :ref:`state of that file's upload session <file-upload-session-states>`. If there was an
566+
error during upload, then clients should not assume the file is in any usable state, ``error``
567+
will be returned and it's best to :ref:`cancel or delete <file-upload-session-cancellation>` the
568+
file and start over.
569+
570+
``canceled`` never appears here. Canceling or deleting a file removes its entry from the ``files``
571+
mapping of the :ref:`session status response body <publishing-session-response>` entirely, since the
572+
file is no longer part of the session. The file's own :ref:`file upload session status URL
573+
<file-upload-session-status>` continues to report ``canceled``.
572574

573575
``link``
574576
The *absolute* URL that the client should use to reference this specific file. This URL is used to
@@ -661,6 +663,9 @@ The transitions between these states are:
661663
* - ``open``
662664
- Publish request accepted for deferred processing (``202 Accepted``)
663665
- ``processing``
666+
* - ``open`` or ``error``
667+
- Publish requested while any file is not ``completed``
668+
- rejected with ``409 Conflict`` (see :ref:`publishing-session-completion`)
664669
* - ``open`` or ``error``
665670
- Publish request fails synchronously
666671
- unchanged (the error is returned to the caller)
@@ -710,6 +715,20 @@ The request looks like:
710715
}
711716
712717
718+
Every file in the session **MUST** have finished uploading before the session can be published. If any entry
719+
in the session's :ref:`files mapping <publishing-session-files>` is in a state other than ``completed``, the
720+
server **MUST** reject the publish request with a ``409 Conflict`` :ref:`error response <session-errors>`
721+
identifying the offending file(s) and their current states, and leave the session in its current editable
722+
state. The client resolves this by waiting for each in-flight :ref:`file upload session
723+
<file-upload-session-states>` to resolve, and then either publishing again or first :ref:`deleting
724+
<file-upload-session-cancellation>` the files it no longer intends to publish.
725+
726+
This precondition is deliberately expressed as an allow-list -- only ``completed`` files may be published --
727+
so that a file in any other state blocks publication rather than being silently included or silently dropped.
728+
In particular this covers files in the ``error`` state, which cannot be repaired in place and **MUST** be
729+
deleted (see :ref:`file-upload-session-states`), as well as any additional file states that a future revision
730+
of this protocol might introduce.
731+
713732
If the server is able to immediately complete the publishing session, it may do so and return a ``201
714733
Created`` response, moving the session to the terminal :ref:`status <publishing-session-states>`
715734
``published``. If it is unable to immediately complete the publishing session (for instance, if it needs to
@@ -745,7 +764,9 @@ is therefore performed atomically at publish time.
745764

746765
**Filename reservation.** When a client requests publication, the server **MUST** atomically reserve the
747766
filenames of all files in the session within the target release, and hold that reservation for the duration of
748-
the publish:
767+
the publish. Because :ref:`publication requires every file in the session to have finished uploading
768+
<publishing-session-completion>`, this reservation covers exactly the fully uploaded files that the session
769+
will publish:
749770

750771
- While the reservation is held, any other attempt to upload a file with one of those filenames to the same
751772
release -- whether through this API or the legacy API -- **MUST** be rejected with a ``409 Conflict``,
@@ -807,6 +828,15 @@ publishing request is already being processed) the server **MUST** reject the ca
807828
Conflict``, since publication may already be in progress. The client can instead wait for processing to
808829
resolve; if it resolves to ``error``, the session can then be canceled.
809830

831+
Cancellation is otherwise permitted regardless of the states of the session's files. In particular, a session
832+
**MUST NOT** be refused cancellation because one or more of its file upload sessions is in the ``processing``
833+
state. Unlike :ref:`deleting an individual file <file-upload-session-cancellation>`, which leaves the session
834+
live and heading toward a publish whose contents would then depend on how that file's processing resolved,
835+
canceling the session guarantees that nothing will be published, so no in-flight validation outcome can affect
836+
the result. The server **MAY** allow such in-flight processing to run to completion and discard the result
837+
rather than interrupting it. All of the session's file upload sessions are considered ``canceled``, and their
838+
URLs receive the same treatment as the session's other data-bearing URLs described above.
839+
810840
To prevent dangling sessions, servers may also choose to cancel timed-out sessions on their own
811841
accord. It is recommended that servers expunge their sessions after no less than a week, but each
812842
server may choose their own schedule. Servers **MAY** support client-directed :ref:`session
@@ -1025,7 +1055,7 @@ the following keys:
10251055
the details of which are provided below.
10261056

10271057
``status``
1028-
A string with valid values ``pending``, ``processing``, ``complete``, ``error``, and ``canceled``
1058+
A string with valid values ``pending``, ``processing``, ``completed``, ``error``, and ``canceled``
10291059
indicating the current :ref:`state of the file upload session <file-upload-session-states>`.
10301060

10311061
``expires-at``
@@ -1069,17 +1099,18 @@ File Upload Session States
10691099
A file upload session is always in exactly one of the following states, reported by the ``status``
10701100
key of the :ref:`file upload session status response <file-upload-session-response>`. The same
10711101
value is reflected for the file in the ``files`` mapping of the :ref:`publishing session status
1072-
<publishing-session-files>`.
1102+
<publishing-session-files>`, except for ``canceled``: a canceled or deleted file is removed from that
1103+
mapping altogether, and only its own status URL continues to report ``canceled``.
10731104

10741105
.. image:: pep-0694/file-upload-session-states.drawio.svg
10751106
:align: center
10761107
:class: invert-in-dark-mode
10771108
:alt: State diagram for a file upload session. From the initial state the session enters ``pending``,
10781109
during which the negotiated upload mechanism executes. From ``pending`` completing the upload either
1079-
succeeds immediately (``201``) to ``complete``, is accepted for deferred processing (``202``) into
1110+
succeeds immediately (``201``) to ``completed``, is accepted for deferred processing (``202``) into
10801111
``processing``, or fails synchronously (``4xx``/``5xx``) to ``error``; ``pending`` can also be
1081-
canceled (``DELETE``) to the terminal ``canceled`` state. ``processing`` resolves to ``complete`` on
1082-
success or to ``error`` on failure. Both ``complete`` and ``error`` can be deleted (``DELETE``) to
1112+
canceled (``DELETE``) to the terminal ``canceled`` state. ``processing`` resolves to ``completed`` on
1113+
success or to ``error`` on failure. Both ``completed`` and ``error`` can be deleted (``DELETE``) to
10831114
``canceled``. Canceling during ``processing`` is rejected with ``409``.
10841115

10851116
The textual description of each state and a complete transition table follow.
@@ -1095,10 +1126,11 @@ The textual description of each state and a complete transition table follow.
10951126
The client has requested completion and the server accepted the request for deferred processing, returning
10961127
a ``202 Accepted`` (see :ref:`file-upload-session-completion`). This is a transitional state; the client
10971128
polls the :ref:`file upload session status <file-upload-session-status>`, respecting the ``Retry-After``
1098-
header, until it resolves to ``complete`` or ``error``.
1129+
header, until it resolves to ``completed`` or ``error``.
10991130

1100-
``complete``
1101-
The file has been fully uploaded, validated, and accepted into the publishing session. The file can still
1131+
``completed``
1132+
The file has been fully uploaded, validated, and accepted into the publishing session. This is the only
1133+
state from which a file may be :ref:`published <publishing-session-completion>`. The file can still
11021134
be :ref:`deleted <file-upload-session-cancellation>`, which removes it from the publishing session and
11031135
moves this session to ``canceled``.
11041136

@@ -1115,7 +1147,7 @@ The textual description of each state and a complete transition table follow.
11151147
and its associated upload mechanisms **MUST NOT** be assumed reusable; recovering or replacing the file
11161148
requires a new file upload session.
11171149

1118-
Only ``canceled`` is terminal. Both ``complete`` and ``error`` still permit a ``DELETE`` (which moves the
1150+
Only ``canceled`` is terminal. Both ``completed`` and ``error`` still permit a ``DELETE`` (which moves the
11191151
session to ``canceled``); from ``error``, deletion is the only forward action.
11201152

11211153
The transitions between these states are:
@@ -1135,7 +1167,7 @@ The transitions between these states are:
11351167
- ``pending``
11361168
* - ``pending``
11371169
- Completion request completed immediately (``201 Created``)
1138-
- ``complete``
1170+
- ``completed``
11391171
* - ``pending``
11401172
- Completion request accepted for deferred processing (``202 Accepted``)
11411173
- ``processing``
@@ -1147,14 +1179,14 @@ The transitions between these states are:
11471179
- ``canceled``
11481180
* - ``processing``
11491181
- Deferred processing succeeds
1150-
- ``complete``
1182+
- ``completed``
11511183
* - ``processing``
11521184
- Deferred processing fails
11531185
- ``error``
11541186
* - ``processing``
11551187
- Cancellation requested
11561188
- rejected with ``409 Conflict`` (see :ref:`file-upload-session-cancellation`)
1157-
* - ``complete``
1189+
* - ``completed``
11581190
- File deleted (``DELETE``)
11591191
- ``canceled``
11601192
* - ``error``
@@ -1188,7 +1220,7 @@ The request looks like:
11881220
}
11891221
11901222
If the server is able to immediately complete the file upload session, it may do so and return a ``201
1191-
Created`` response and set the status of the file upload session to ``complete``. If it is unable to
1223+
Created`` response and set the status of the file upload session to ``completed``. If it is unable to
11921224
immediately complete the file upload session (for instance, if it needs to do validation that may take longer
11931225
than reasonable in a single HTTP request), then it may return a ``202 Accepted`` response and set the status
11941226
of the file upload session to ``processing``.
@@ -1219,7 +1251,7 @@ to delete.
12191251

12201252
A successful deletion request **MUST** respond with a ``204 No Content``.
12211253

1222-
A ``DELETE`` is permitted while the session is ``pending`` (canceling an in-progress upload), ``complete``
1254+
A ``DELETE`` is permitted while the session is ``pending`` (canceling an in-progress upload), ``completed``
12231255
(deleting an uploaded file), or ``error`` (discarding a failed upload). If the session is in the
12241256
``processing`` state -- that is, a deferred completion is already underway -- the server **MUST** reject the
12251257
``DELETE`` with a ``409 Conflict``, since the outcome is already being decided. The client can instead wait
@@ -1839,6 +1871,26 @@ Change History
18391871
* Expand the "Why is the project name required" FAQ to note that single-project sessions still improve
18401872
multi-project releases (all projects can be fully staged before a final step publishes each one) and lay a
18411873
foundation for a possible future "publish multiple projects" endpoint.
1874+
* Define what happens when a publish is requested while file uploads are still in flight, which
1875+
was previously unspecified. Publication now has an explicit precondition: every entry in the
1876+
session's ``files`` mapping **MUST** be in the ``completed`` state, otherwise the server
1877+
**MUST** reject the publish request with a ``409 Conflict`` identifying the offending file(s)
1878+
and leave the session editable. The rule is written as an allow-list so that files in
1879+
``error``, and any file states added by future revisions, block publication rather than being
1880+
silently included or dropped. Add a corresponding row to the publishing session transition
1881+
table and scope the filename reservation to the fully uploaded files the session will publish.
1882+
* Rename the file upload session ``complete`` status to ``completed``. This matches the
1883+
past-participle form of the other settled statuses (``canceled``, and the publishing session's
1884+
``published``), and disambiguates the *state* from the ``complete`` *action* and its
1885+
``links.complete`` endpoint, which keep their names.
1886+
* Specify that a publishing session **MUST** be cancelable regardless of the states of its files, and in
1887+
particular **MUST NOT** be refused cancellation because a file upload session is ``processing``. Because
1888+
canceling guarantees nothing will be published, no in-flight validation outcome can affect the result, so
1889+
unlike an individual file deletion there is no race to protect against; the server **MAY** let in-flight
1890+
processing finish and discard the result rather than interrupting it.
1891+
* Remove ``canceled`` from the valid values of the publishing session ``files`` mapping ``status`` key,
1892+
resolving a contradiction with the existing rule that canceling or deleting a file removes its entry from
1893+
that mapping. The file's own file upload session status URL continues to report ``canceled``.
18421894

18431895
* `26-Jun-2026 <https://discuss.python.org/t/pep-694-pypi-upload-api-2-0-round-3/107923>`__
18441896

peps/pep-0694/file-upload-session-states.drawio.svg

Lines changed: 1 addition & 1 deletion
Loading

0 commit comments

Comments
 (0)