1515from django .db .utils import DatabaseError
1616from django .http .response import (
1717 Http404 ,
18+ HttpResponseNotFound ,
1819 HttpResponseForbidden ,
1920 HttpResponseBadRequest ,
2021 StreamingHttpResponse ,
@@ -287,7 +288,7 @@ def list(self, request, path):
287288 kwargs = {"content_type" : media_type , "headers" : headers }
288289 return StreamingHttpResponse (index_data , ** kwargs )
289290
290- def pull_through_package_simple (self , package , path , remote , media_type ):
291+ def pull_through_package_simple (self , package , path , remote ):
291292 """Gets the package's simple page from remote."""
292293
293294 def parse_package (release_package ):
@@ -305,35 +306,27 @@ def parse_package(release_package):
305306
306307 rfilter = get_remote_package_filter (remote )
307308 if not rfilter .filter_project (package ):
308- raise Http404 ( f" { package } does not exist." )
309+ return {}
309310
310311 url = remote .get_remote_artifact_url (f"simple/{ package } /" )
311312 remote .headers = remote .headers or []
312313 remote .headers .append ({"Accept" : ACCEPT_JSON_PREFERRED })
313314 downloader = remote .get_downloader (url = url , max_retries = 1 )
314315 try :
315316 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 )
317+ except (ClientError , TimeoutException ):
318+ log .info (f"Failed to fetch { package } simple page from { remote .url } " )
319+ return {}
320320
321321 if d .headers ["content-type" ] == PYPI_SIMPLE_V1_JSON :
322322 page = ProjectPage .from_json_data (json .load (open (d .path , "rb" )), base_url = url )
323323 else :
324324 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 )
325+ return {
326+ p .filename : parse_package (p )
327+ for p in page .packages
328+ if rfilter .filter_release (package , p .version )
329+ }
337330
338331 @extend_schema (operation_id = "pypi_simple_package_read" , summary = "Get package simple page" )
339332 def retrieve (self , request , path , package ):
@@ -343,44 +336,36 @@ def retrieve(self, request, path, package):
343336 repo_ver , content = self .get_rvc ()
344337 # Should I redirect if the normalized name is different?
345338 normalized = canonicalize_name (package )
339+ releases = {}
346340 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 ):
341+ releases = self .pull_through_package_simple (normalized , path , self .distribution .remote )
342+ elif self .should_redirect (repo_version = repo_ver ):
351343 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 ,
344+ if content :
345+ packages = content .filter (name__normalize = normalized ).values (
346+ "filename" , "sha256" , "metadata_sha256" , "requires_python"
347+ )
348+ local_releases = {
349+ p ["filename" ]: {
350+ ** p ,
351+ "url" : urljoin (self .base_content_url , f"{ path } /{ p ['filename' ]} " ),
352+ }
353+ for p in packages
371354 }
372- for filename , sha256 , _ , metadata_sha256 , requires_python in packages
373- )
355+ releases .update (local_releases )
356+ if not releases :
357+ return HttpResponseNotFound (f"{ normalized } does not exist." )
358+
374359 media_type = request .accepted_renderer .media_type
375360 headers = {"X-PyPI-Last-Serial" : str (PYPI_SERIAL_CONSTANT )}
376361
377362 if media_type == PYPI_SIMPLE_V1_JSON :
378- detail_data = write_simple_detail_json (name , releases )
363+ detail_data = write_simple_detail_json (normalized , releases . values () )
379364 return Response (detail_data , headers = headers )
380365 else :
381- detail_data = write_simple_detail (name , releases , streamed = True )
366+ detail_data = write_simple_detail (normalized , releases . values () )
382367 kwargs = {"content_type" : media_type , "headers" : headers }
383- return StreamingHttpResponse (detail_data , ** kwargs )
368+ return HttpResponse (detail_data , ** kwargs )
384369
385370 @extend_schema (
386371 request = PackageUploadSerializer ,
0 commit comments