11#!/usr/bin/env python
2+ # -*- coding: utf-8 -*-
23#
34# Copyright (c) nexB Inc. and others. All rights reserved.
45# ScanCode is a trademark of nexB Inc.
2425import packageurl
2526import requests
2627import saneyaml
27- import utils_pip_compatibility_tags
2828from commoncode import fileutils
2929from commoncode .hash import multi_checksums
3030from commoncode .text import python_safe_name
3131from packvers import tags as packaging_tags
3232from packvers import version as packaging_version
3333
34+ import utils_pip_compatibility_tags
35+
3436"""
3537Utilities to manage Python thirparty libraries source, binaries and metadata in
3638local directories and remote repositories.
9193
9294- parse requirement file
9395- create a TODO queue of requirements to process
94- - done: create an empty map of processed binary requirements as
95- {package name: (list of versions/tags}
96+ - done: create an empty map of processed binary requirements as {package name: (list of versions/tags}
9697
9798
9899- while we have package reqs in TODO queue, process one requirement:
114115TRACE_ULTRA_DEEP = False
115116
116117# Supported environments
117- PYTHON_VERSIONS = "39" , "310" , "311"
118+ PYTHON_VERSIONS = "39" , "310" , "311" , "312" , "313" , "314"
118119
119120PYTHON_DOT_VERSIONS_BY_VER = {
120121 "39" : "3.9" ,
121122 "310" : "3.10" ,
122123 "311" : "3.11" ,
124+ "312" : "3.12" ,
125+ "313" : "3.13" ,
126+ "314" : "3.14" ,
123127}
124128
125129
@@ -131,10 +135,12 @@ def get_python_dot_version(version):
131135
132136
133137ABIS_BY_PYTHON_VERSION = {
134- "37" : ["cp37" , "cp37m" , "abi3" ],
135- "38" : ["cp38" , "cp38m" , "abi3" ],
136138 "39" : ["cp39" , "cp39m" , "abi3" ],
137139 "310" : ["cp310" , "cp310m" , "abi3" ],
140+ "311" : ["cp311" , "cp311m" , "abi3" ],
141+ "312" : ["cp312" , "cp312m" , "abi3" ],
142+ "313" : ["cp313" , "cp313m" , "abi3" ],
143+ "314" : ["cp314" , "cp314m" , "abi3" ],
138144}
139145
140146PLATFORMS_BY_OS = {
@@ -552,8 +558,7 @@ def download(self, dest_dir=THIRDPARTY_DIR):
552558 Download this distribution into `dest_dir` directory.
553559 Return the fetched filename.
554560 """
555- if not self .filename :
556- raise ValueError (f"self.filename has no value but is required: { self .filename !r} " )
561+ assert self .filename
557562 if TRACE_DEEP :
558563 print (
559564 f"Fetching distribution of { self .name } =={ self .version } :" ,
@@ -821,9 +826,9 @@ def fetch_license_files(self, dest_dir=THIRDPARTY_DIR, use_cached_index=False):
821826 """
822827 urls = LinksRepository .from_url (use_cached_index = use_cached_index ).links
823828 errors = []
824- extra_lic_names = [lic .get ("file" ) for lic in self .extra_data .get ("licenses" , {})]
829+ extra_lic_names = [l .get ("file" ) for l in self .extra_data .get ("licenses" , {})]
825830 extra_lic_names += [self .extra_data .get ("license_file" )]
826- extra_lic_names = [eln for eln in extra_lic_names if eln ]
831+ extra_lic_names = [ln for ln in extra_lic_names if ln ]
827832 lic_names = [f"{ key } .LICENSE" for key in self .get_license_keys ()]
828833 for filename in lic_names + extra_lic_names :
829834 floc = os .path .join (dest_dir , filename )
@@ -843,7 +848,7 @@ def fetch_license_files(self, dest_dir=THIRDPARTY_DIR, use_cached_index=False):
843848 if TRACE :
844849 print (f"Fetched license from remote: { lic_url } " )
845850
846- except Exception :
851+ except :
847852 try :
848853 # try licensedb second
849854 lic_url = f"{ LICENSEDB_API_URL } /{ filename } "
@@ -856,9 +861,8 @@ def fetch_license_files(self, dest_dir=THIRDPARTY_DIR, use_cached_index=False):
856861 if TRACE :
857862 print (f"Fetched license from licensedb: { lic_url } " )
858863
859- except Exception :
860- msg = f"No text for license { filename } in expression "
861- f"{ self .license_expression !r} from { self } "
864+ except :
865+ msg = f'No text for license { filename } in expression "{ self .license_expression } " from { self } '
862866 print (msg )
863867 errors .append (msg )
864868
@@ -998,7 +1002,7 @@ def get_license_link_for_filename(filename, urls):
9981002 exception if no link is found or if there are more than one link for that
9991003 file name.
10001004 """
1001- path_or_url = [url for url in urls if url .endswith (f"/{ filename } " )]
1005+ path_or_url = [l for l in urls if l .endswith (f"/{ filename } " )]
10021006 if not path_or_url :
10031007 raise Exception (f"Missing link to file: { filename } " )
10041008 if not len (path_or_url ) == 1 :
@@ -1287,7 +1291,7 @@ def is_pure(self):
12871291def is_pure_wheel (filename ):
12881292 try :
12891293 return Wheel .from_filename (filename ).is_pure ()
1290- except Exception :
1294+ except :
12911295 return False
12921296
12931297
@@ -1483,7 +1487,8 @@ def get_distributions(self):
14831487 """
14841488 if self .sdist :
14851489 yield self .sdist
1486- yield from self .wheels
1490+ for wheel in self .wheels :
1491+ yield wheel
14871492
14881493 def get_url_for_filename (self , filename ):
14891494 """
@@ -1612,8 +1617,7 @@ class PypiSimpleRepository:
16121617 type = dict ,
16131618 default = attr .Factory (lambda : defaultdict (dict )),
16141619 metadata = dict (
1615- help = "Mapping of {name: {version: PypiPackage, version: PypiPackage, etc} "
1616- "available in this repo"
1620+ help = "Mapping of {name: {version: PypiPackage, version: PypiPackage, etc} available in this repo"
16171621 ),
16181622 )
16191623
@@ -1627,8 +1631,7 @@ class PypiSimpleRepository:
16271631 type = bool ,
16281632 default = False ,
16291633 metadata = dict (
1630- help = "If True, use any existing on-disk cached PyPI index files. "
1631- "Otherwise, fetch and cache."
1634+ help = "If True, use any existing on-disk cached PyPI index files. Otherwise, fetch and cache."
16321635 ),
16331636 )
16341637
@@ -1637,8 +1640,7 @@ def _get_package_versions_map(self, name):
16371640 Return a mapping of all available PypiPackage version for this package name.
16381641 The mapping may be empty. It is ordered by version from oldest to newest
16391642 """
1640- if not name :
1641- raise ValueError (f"name is required: { name !r} " )
1643+ assert name
16421644 normalized_name = NameVer .normalize_name (name )
16431645 versions = self .packages [normalized_name ]
16441646 if not versions and normalized_name not in self .fetched_package_normalized_names :
@@ -1693,7 +1695,7 @@ def fetch_links(self, normalized_name):
16931695 )
16941696 links = collect_urls (text )
16951697 # TODO: keep sha256
1696- links = [link .partition ("#sha256=" ) for link in links ]
1698+ links = [l .partition ("#sha256=" ) for l in links ]
16971699 links = [url for url , _ , _sha256 in links ]
16981700 return links
16991701
@@ -1914,7 +1916,7 @@ def get_remote_file_content(
19141916 # several redirects and that we can ignore content there. A HEAD request may
19151917 # not get us this last header
19161918 print (f" DOWNLOADING: { url } " )
1917- with requests .get (url , allow_redirects = True , stream = True , headers = headers ) as response : # noqa: S113
1919+ with requests .get (url , allow_redirects = True , stream = True , headers = headers ) as response :
19181920 status = response .status_code
19191921 if status != requests .codes .ok : # NOQA
19201922 if status == 429 and _delay < 20 :
@@ -2133,7 +2135,7 @@ def call(args, verbose=TRACE):
21332135 """
21342136 if TRACE_DEEP :
21352137 print ("Calling:" , " " .join (args ))
2136- with subprocess .Popen ( # noqa: S603
2138+ with subprocess .Popen (
21372139 args , stdout = subprocess .PIPE , stderr = subprocess .PIPE , encoding = "utf-8"
21382140 ) as process :
21392141 stdouts = []
@@ -2198,7 +2200,7 @@ def download_wheels_with_pip(
21982200 cli_args .extend (["--requirement" , req_file ])
21992201
22002202 if TRACE :
2201- print ("Downloading wheels using command:" , " " .join (cli_args ))
2203+ print (f "Downloading wheels using command:" , " " .join (cli_args ))
22022204
22032205 existing = set (os .listdir (dest_dir ))
22042206 error = False
@@ -2231,7 +2233,7 @@ def download_wheels_with_pip(
22312233
22322234def check_about (dest_dir = THIRDPARTY_DIR ):
22332235 try :
2234- subprocess .check_output (f"venv/bin/about check { dest_dir } " .split ()) # noqa: S603
2236+ subprocess .check_output (f"venv/bin/about check { dest_dir } " .split ())
22352237 except subprocess .CalledProcessError as cpe :
22362238 print ()
22372239 print ("Invalid ABOUT files:" )
@@ -2282,5 +2284,5 @@ def get_license_expression(declared_licenses):
22822284 return get_only_expression_from_extracted_license (declared_licenses )
22832285 except ImportError :
22842286 # Scancode is not installed, clean and join all the licenses
2285- lics = [python_safe_name (lic ).lower () for lic in declared_licenses ]
2287+ lics = [python_safe_name (l ).lower () for l in declared_licenses ]
22862288 return " AND " .join (lics ).lower ()
0 commit comments