Skip to content

Commit 5cff2a1

Browse files
dimblebyCopilotradoering
authored
fix: retry upload after package registration instead of raising (#10801)
After _register() succeeded, resp.raise_for_status() raised on the original 400 response, so the upload was never retried. Now retries the upload once after registration, with a guard against infinite recursion if the server keeps returning 400. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Randy Döring <30527984+radoering@users.noreply.github.com>
1 parent bef7937 commit 5cff2a1

File tree

2 files changed

+60
-1
lines changed

2 files changed

+60
-1
lines changed

src/poetry/publishing/uploader.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,8 @@ def _upload_file(
204204
file: Path,
205205
dry_run: bool = False,
206206
skip_existing: bool = False,
207+
*,
208+
registered: bool = False,
207209
) -> None:
208210
from cleo.ui.progress_bar import ProgressBar
209211

@@ -254,7 +256,16 @@ def _upload_file(
254256
"Is the URL missing a trailing slash?"
255257
)
256258
elif resp.status_code == 400 and "was ever registered" in resp.text:
257-
self._register(session, url)
259+
if not registered:
260+
self._register(session, url)
261+
return self._upload_file(
262+
session,
263+
url,
264+
file,
265+
dry_run,
266+
skip_existing,
267+
registered=True,
268+
)
258269
resp.raise_for_status()
259270
elif skip_existing and self._is_file_exists_error(resp):
260271
bar.set_format(

tests/publishing/test_uploader.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,54 @@ def test_uploader_registers_with_sdist_for_appropriate_400_errors(
225225
assert b"bdist_wheel" not in bodies[1]
226226

227227

228+
def test_uploader_retries_upload_after_register(
229+
http: responses.RequestsMock, uploader: Uploader
230+
) -> None:
231+
"""After registering a package, the upload must be retried.
232+
233+
The server returns 400 "was ever registered" on the first upload,
234+
then 200 on the registration and the retried upload.
235+
"""
236+
http.post("https://foo.com", status=400, body="No package was ever registered")
237+
http.post("https://foo.com", status=200) # register
238+
http.post("https://foo.com", status=200) # retry upload (first file)
239+
http.post("https://foo.com", status=200) # upload second file
240+
241+
uploader.upload("https://foo.com")
242+
243+
assert len(http.calls) == 4
244+
bodies = [c.request.body or b"" for c in http.calls]
245+
assert b'name=":action"\r\n\r\nfile_upload\r\n' in bodies[0]
246+
assert b'name=":action"\r\n\r\nsubmit\r\n' in bodies[1]
247+
assert b'name=":action"\r\n\r\nfile_upload\r\n' in bodies[2]
248+
assert b'name=":action"\r\n\r\nfile_upload\r\n' in bodies[3]
249+
250+
251+
def test_uploader_retries_upload_after_register_but_does_not_loop_infinitely(
252+
http: responses.RequestsMock, uploader: Uploader
253+
) -> None:
254+
"""After registering a package, the upload must be retried but only once.
255+
256+
The server returns 400 "was ever registered" on the first upload,
257+
then 200 on the registration,
258+
but then again 400 "was ever registered" on the second upload.
259+
"""
260+
http.post("https://foo.com", status=400, body="No package was ever registered")
261+
http.post("https://foo.com", status=200) # register
262+
http.post( # retry upload
263+
"https://foo.com", status=400, body="No package was ever registered"
264+
)
265+
266+
with pytest.raises(UploadError):
267+
uploader.upload("https://foo.com")
268+
269+
assert len(http.calls) == 3
270+
bodies = [c.request.body or b"" for c in http.calls]
271+
assert b'name=":action"\r\n\r\nfile_upload\r\n' in bodies[0]
272+
assert b'name=":action"\r\n\r\nsubmit\r\n' in bodies[1]
273+
assert b'name=":action"\r\n\r\nfile_upload\r\n' in bodies[2]
274+
275+
228276
def test_uploader_register_uses_wheel_if_no_sdist(
229277
http: responses.RequestsMock, poetry: Poetry, tmp_path: Path
230278
) -> None:

0 commit comments

Comments
 (0)