@@ -71,7 +71,7 @@ def download_python_build_standalone(python_version: str, override: bool = False
7171 logger .warning (f"A previous attempt to install python { python_version } failed. Retrying." )
7272 shutil .rmtree (install_dir )
7373
74- full_version , download_link = resolve_python_version (python_version )
74+ full_version , ( download_link , digest ) = resolve_python_version (python_version )
7575
7676 with tempfile .TemporaryDirectory () as tempdir :
7777 archive = Path (tempdir ) / f"python-{ full_version } .tar.gz"
@@ -81,7 +81,7 @@ def download_python_build_standalone(python_version: str, override: bool = False
8181 _download (full_version , download_link , archive )
8282
8383 # unpack the python build
84- _unpack (full_version , download_link , archive , download_dir )
84+ _unpack (full_version , download_link , archive , download_dir , digest )
8585
8686 # the python installation we want is nested in the tarball
8787 # under a directory named 'python'. We move it to the install
@@ -104,15 +104,13 @@ def _download(full_version: str, download_link: str, archive: Path):
104104 raise PipxError (f"Unable to download python { full_version } build." ) from e
105105
106106
107- def _unpack (full_version , download_link , archive : Path , download_dir : Path ):
107+ def _unpack (full_version , download_link , archive : Path , download_dir : Path , expected_checksum : str ):
108108 with animate (f"Unpacking python { full_version } build" , True ):
109109 # Calculate checksum
110110 with open (archive , "rb" ) as python_zip :
111- checksum = hashlib .sha256 (python_zip .read ()).hexdigest ()
111+ checksum = "sha256:" + hashlib .sha256 (python_zip .read ()).hexdigest ()
112112
113113 # Validate checksum
114- checksum_link = download_link + ".sha256"
115- expected_checksum = urlopen (checksum_link ).read ().decode ().rstrip ("\n " )
116114 if checksum != expected_checksum :
117115 raise PipxError (
118116 f"Checksum mismatch for python { full_version } build. Expected { expected_checksum } , got { checksum } ."
@@ -152,7 +150,7 @@ def get_latest_python_releases() -> List[str]:
152150 # raise
153151 raise PipxError (f"Unable to fetch python-build-standalone release data (from { GITHUB_API_URL } )." ) from e
154152
155- return [asset ["browser_download_url" ] for asset in release_data ["assets" ]]
153+ return [( asset ["browser_download_url" ], asset . get ( "digest" )) for asset in release_data ["assets" ]]
156154
157155
158156def list_pythons (use_cache : bool = True ) -> Dict [str , str ]:
@@ -168,23 +166,23 @@ def list_pythons(use_cache: bool = True) -> Dict[str, str]:
168166 python_releases = get_or_update_index (use_cache )["releases" ]
169167
170168 available_python_links = [
171- link
169+ ( link , digest )
172170 # Suffixes are in order of preference.
173171 for download_link_suffix in download_link_suffixes
174- for link in python_releases
172+ for link , digest in python_releases
175173 if link .endswith (download_link_suffix )
176174 ]
177175
178176 python_versions : dict [str , str ] = {}
179- for link in available_python_links :
177+ for link , digest in available_python_links :
180178 match = PYTHON_VERSION_REGEX .search (link )
181179 assert match is not None
182180 python_version = match [1 ]
183181 # Don't override already found versions, they are in order of preference
184182 if python_version in python_versions :
185183 continue
186184
187- python_versions [python_version ] = link
185+ python_versions [python_version ] = link , digest
188186
189187 return {
190188 version : python_versions [version ]
0 commit comments