1414from django .db import transaction
1515from django .db .utils import DatabaseError
1616from django .http .response import (
17- Http404 ,
17+ HttpResponseNotFound ,
1818 HttpResponseForbidden ,
1919 HttpResponseBadRequest ,
2020 StreamingHttpResponse ,
@@ -287,7 +287,7 @@ def list(self, request, path):
287287 kwargs = {"content_type" : media_type , "headers" : headers }
288288 return StreamingHttpResponse (index_data , ** kwargs )
289289
290- def pull_through_package_simple (self , package , path , remote , media_type ):
290+ def pull_through_package_simple (self , package , path , remote ):
291291 """Gets the package's simple page from remote."""
292292
293293 def parse_package (release_package ):
@@ -305,35 +305,26 @@ def parse_package(release_package):
305305
306306 rfilter = get_remote_package_filter (remote )
307307 if not rfilter .filter_project (package ):
308- raise Http404 ( f" { package } does not exist." )
308+ return {}
309309
310310 url = remote .get_remote_artifact_url (f"simple/{ package } /" )
311311 remote .headers = remote .headers or []
312312 remote .headers .append ({"Accept" : ACCEPT_JSON_PREFERRED })
313313 downloader = remote .get_downloader (url = url , max_retries = 1 )
314314 try :
315315 d = downloader .fetch ()
316- except ClientError :
317- return HttpResponse (f"Failed to fetch { package } from { remote .url } ." , status = 502 )
318- except TimeoutException :
319- return HttpResponse (f"{ remote .url } timed out while fetching { package } ." , status = 504 )
316+ except (ClientError , TimeoutException ):
317+ return {}
320318
321319 if d .headers ["content-type" ] == PYPI_SIMPLE_V1_JSON :
322320 page = ProjectPage .from_json_data (json .load (open (d .path , "rb" )), base_url = url )
323321 else :
324322 page = ProjectPage .from_html (package , open (d .path , "rb" ).read (), base_url = url )
325- packages = [
326- parse_package (p ) for p in page .packages if rfilter .filter_release (package , p .version )
327- ]
328- headers = {"X-PyPI-Last-Serial" : str (PYPI_SERIAL_CONSTANT )}
329-
330- if media_type == PYPI_SIMPLE_V1_JSON :
331- detail_data = write_simple_detail_json (package , packages )
332- return Response (detail_data , headers = headers )
333- else :
334- detail_data = write_simple_detail (package , packages )
335- kwargs = {"content_type" : media_type , "headers" : headers }
336- return HttpResponse (detail_data , ** kwargs )
323+ return {
324+ p .filename : parse_package (p )
325+ for p in page .packages
326+ if rfilter .filter_release (package , p .version )
327+ }
337328
338329 @extend_schema (operation_id = "pypi_simple_package_read" , summary = "Get package simple page" )
339330 def retrieve (self , request , path , package ):
@@ -343,44 +334,36 @@ def retrieve(self, request, path, package):
343334 repo_ver , content = self .get_rvc ()
344335 # Should I redirect if the normalized name is different?
345336 normalized = canonicalize_name (package )
337+ releases = {}
346338 if self .distribution .remote :
347- return self .pull_through_package_simple (
348- normalized , path , self .distribution .remote , media_type
349- )
350- if self .should_redirect (repo_version = repo_ver ):
339+ releases = self .pull_through_package_simple (normalized , path , self .distribution .remote )
340+ elif self .should_redirect (repo_version = repo_ver ):
351341 return redirect (urljoin (self .base_content_url , f"{ path } /simple/{ normalized } /" ))
352- packages = (
353- content .filter (name__normalize = normalized )
354- .values_list ("filename" , "sha256" , "name" , "metadata_sha256" , "requires_python" )
355- .iterator ()
356- )
357- try :
358- present = next (packages )
359- except StopIteration :
360- raise Http404 (f"{ normalized } does not exist." )
361- else :
362- packages = chain ([present ], packages )
363- name = present [2 ]
364- releases = (
365- {
366- "filename" : filename ,
367- "url" : urljoin (self .base_content_url , f"{ path } /{ filename } " ),
368- "sha256" : sha256 ,
369- "metadata_sha256" : metadata_sha256 ,
370- "requires_python" : requires_python ,
342+ if content :
343+ packages = content .filter (name__normalize = normalized ).values (
344+ "filename" , "sha256" , "metadata_sha256" , "requires_python"
345+ )
346+ local_releases = {
347+ p ["filename" ]: {
348+ ** p ,
349+ "url" : urljoin (self .base_content_url , f"{ path } /{ p ['filename' ]} " ),
350+ }
351+ for p in packages
371352 }
372- for filename , sha256 , _ , metadata_sha256 , requires_python in packages
373- )
353+ releases .update (local_releases )
354+ if not releases :
355+ return HttpResponseNotFound (f"{ normalized } does not exist." )
356+
374357 media_type = request .accepted_renderer .media_type
375358 headers = {"X-PyPI-Last-Serial" : str (PYPI_SERIAL_CONSTANT )}
376359
377360 if media_type == PYPI_SIMPLE_V1_JSON :
378- detail_data = write_simple_detail_json (name , releases )
361+ detail_data = write_simple_detail_json (normalized , releases . values () )
379362 return Response (detail_data , headers = headers )
380363 else :
381- detail_data = write_simple_detail (name , releases , streamed = True )
364+ detail_data = write_simple_detail (normalized , releases . values () )
382365 kwargs = {"content_type" : media_type , "headers" : headers }
383- return StreamingHttpResponse (detail_data , ** kwargs )
366+ return HttpResponse (detail_data , ** kwargs )
384367
385368 @extend_schema (
386369 request = PackageUploadSerializer ,
0 commit comments