88# See https://github.com/nexB/skeleton for support or download.
99# See https://aboutcode.org for more information about nexB OSS projects.
1010#
11- from collections import defaultdict
1211import email
12+ import functools
1313import itertools
1414import os
1515import re
1818import tempfile
1919import time
2020import urllib
21+ from collections import defaultdict
22+ from urllib .parse import quote_plus
2123
2224import attr
2325import license_expression
2931from commoncode .text import python_safe_name
3032from packaging import tags as packaging_tags
3133from packaging import version as packaging_version
32- from urllib .parse import quote_plus
3334
3435import utils_pip_compatibility_tags
3536from utils_requirements import load_requirements
111112
112113"""
113114
114- TRACE = True
115+ TRACE = False
115116TRACE_DEEP = False
116117TRACE_ULTRA_DEEP = False
117118
@@ -233,7 +234,7 @@ def download_wheel(
233234 tuple of lists of (fetched_wheel_filenames, existing_wheel_filenames)
234235 """
235236 if TRACE_DEEP :
236- print (f" download_wheel: { name } =={ version } : { environment } " )
237+ print (f" download_wheel: { name } =={ version } : { environment } and index_urls: { index_urls } " )
237238
238239 fetched_wheel_filenames = []
239240 existing_wheel_filenames = []
@@ -311,6 +312,7 @@ def download_sdist(
311312 raise DistributionNotFound (f"Failed to fetch sdist: { name } =={ version } : No sources found" )
312313
313314
315+ @functools .cache
314316def get_package_versions (
315317 name ,
316318 version = None ,
@@ -321,15 +323,28 @@ def get_package_versions(
321323 repository ``index_urls`` list of URLs.
322324 If ``version`` is not provided, return the latest available versions.
323325 """
326+ found = []
327+ not_found = []
324328 for index_url in index_urls :
325329 try :
326330 repo = get_pypi_repo (index_url )
327331 package = repo .get_package (name , version )
332+
328333 if package :
329- yield package
334+ found .append ((package , index_url ))
335+ else :
336+ not_found .append ((name , version , index_url ))
330337 except RemoteNotFetchedException as e :
331- print (f"Failed to fetch PyPI package { name } @ { version } info from { index_url } : { e } " )
338+ if TRACE_ULTRA_DEEP :
339+ print (f"Failed to fetch PyPI package { name } @ { version } info from { index_url } : { e } " )
340+ not_found .append ((name , version , index_url ))
341+
342+ if not found :
343+ raise Exception (f"No PyPI package { name } @ { version } found!" )
332344
345+ for package , index_url in found :
346+ print (f"Fetched PyPI package { package .name } @ { package .version } info from { index_url } " )
347+ yield package
333348
334349################################################################################
335350#
@@ -546,14 +561,14 @@ def get_best_download_url(
546561 If none is found, return a synthetic remote URL.
547562 """
548563 for index_url in index_urls :
549- pypi_package = get_pypi_package (
564+ pypi_package = get_pypi_package_data (
550565 name = self .normalized_name ,
551566 version = self .version ,
552567 index_url = index_url ,
553568 )
554569 if pypi_package :
555570 if isinstance (pypi_package , tuple ):
556- raise Exception ("############" , repr (pypi_package ))
571+ raise Exception ("############" , repr (pypi_package ), self . normalized_name , self . version , index_url )
557572 try :
558573 pypi_url = pypi_package .get_url_for_filename (self .filename )
559574 except Exception as e :
@@ -1450,7 +1465,7 @@ def get_name_version(cls, name, version, packages):
14501465 nvs = [p for p in cls .get_versions (name , packages ) if p .version == version ]
14511466
14521467 if not nvs :
1453- return name , version
1468+ return
14541469
14551470 if len (nvs ) == 1 :
14561471 return nvs [0 ]
@@ -1494,8 +1509,8 @@ def dists_from_paths_or_urls(cls, paths_or_urls):
14941509 >>> assert expected == result
14951510 """
14961511 dists = []
1497- if TRACE_DEEP :
1498- print (" ###paths_or_urls:" , paths_or_urls )
1512+ if TRACE_ULTRA_DEEP :
1513+ print (" ###paths_or_urls:" , paths_or_urls )
14991514 installable = [f for f in paths_or_urls if f .endswith (EXTENSIONS_INSTALLABLE )]
15001515 for path_or_url in installable :
15011516 try :
@@ -1618,7 +1633,6 @@ def tags(self):
16181633 )
16191634 )
16201635
1621-
16221636################################################################################
16231637#
16241638# PyPI repo and link index for package wheels and sources
@@ -1657,7 +1671,10 @@ def get_versions(self, name):
16571671 The list may be empty.
16581672 """
16591673 name = name and NameVer .normalize_name (name )
1660- self ._populate_links_and_packages (name )
1674+ try :
1675+ self ._populate_links_and_packages (name )
1676+ except Exception as e :
1677+ print (f" ==> Cannot find versions of { name } : { e } " )
16611678 return self .packages_by_normalized_name .get (name , [])
16621679
16631680 def get_latest_version (self , name ):
@@ -1703,7 +1720,7 @@ def _fetch_links(self, name, _LINKS={}):
17031720 _LINKS [index_url ] = [l for l in links if l .endswith (EXTENSIONS )]
17041721
17051722 links = _LINKS [index_url ]
1706- if TRACE_DEEP :
1723+ if TRACE_ULTRA_DEEP :
17071724 print (f" Found links { links !r} " )
17081725 return links
17091726
@@ -1803,7 +1820,6 @@ def from_url(cls, url=ABOUT_BASE_URL, _LINKS_REPO={}):
18031820 _LINKS_REPO [url ] = cls (url = url )
18041821 return _LINKS_REPO [url ]
18051822
1806-
18071823################################################################################
18081824# Globals for remote repos to be lazily created and cached on first use for the
18091825# life of the session together with some convenience functions.
@@ -1824,19 +1840,21 @@ def get_pypi_repo(index_url, _PYPI_REPO={}):
18241840 return _PYPI_REPO [index_url ]
18251841
18261842
1827- def get_pypi_package (name , version , index_url , verbose = TRACE_DEEP ):
1843+ @functools .cache
1844+ def get_pypi_package_data (name , version , index_url , verbose = TRACE_DEEP ):
18281845 """
18291846 Return a PypiPackage or None.
18301847 """
18311848 try :
1849+ if verbose :
1850+ print (f" get_pypi_package_data: Fetching { name } @ { version } info from { index_url } " )
18321851 package = get_pypi_repo (index_url ).get_package (name , version )
18331852 if verbose :
1834- print (f" get_pypi_package: { name } @ { version } info from { index_url } : { package } " )
1853+ print (f" get_pypi_package_data: Fetched : { package } " )
18351854 return package
18361855
18371856 except RemoteNotFetchedException as e :
1838- print (f"Failed to fetch PyPI package { name } @ { version } info from { index_url } : { e } " )
1839-
1857+ print (f" get_pypi_package_data: Failed to fetch PyPI package { name } @ { version } info from { index_url } : { e } " )
18401858
18411859################################################################################
18421860#
@@ -1998,7 +2016,6 @@ def fetch_and_save_path_or_url(
19982016 fo .write (content )
19992017 return content
20002018
2001-
20022019################################################################################
20032020# Requirements processing
20042021################################################################################
@@ -2036,7 +2053,6 @@ def get_required_packages(
20362053 print (" get_required_packages: name:" , name , "version:" , version )
20372054 yield repo .get_package (name , version )
20382055
2039-
20402056################################################################################
20412057# Functions to update or fetch ABOUT and license files
20422058################################################################################
@@ -2115,7 +2131,6 @@ def get_other_dists(_package, _dist):
21152131 for p in packages_by_name [local_package .name ]
21162132 if p .version != local_package .version
21172133 ]
2118-
21192134 other_local_version = other_local_packages and other_local_packages [- 1 ]
21202135 if other_local_version :
21212136 latest_local_dists = list (other_local_version .get_distributions ())
@@ -2187,7 +2202,6 @@ def get_other_dists(_package, _dist):
21872202 lic_errs = "\n " .join (lic_errs )
21882203 print (f"Failed to fetch some licenses:: { lic_errs } " )
21892204
2190-
21912205################################################################################
21922206#
21932207# Functions to build new Python wheels including native on multiple OSes
@@ -2318,9 +2332,9 @@ def build_wheels_locally_if_pure_python(
23182332 "--wheel-dir" ,
23192333 wheel_dir ,
23202334 ]
2321- + deps
2322- + verbose
2323- + [requirements_specifier ]
2335+ + deps
2336+ + verbose
2337+ + [requirements_specifier ]
23242338 )
23252339
23262340 print (f"Building local wheels for: { requirements_specifier } " )
0 commit comments