Skip to content

Commit 9ae2874

Browse files
authored
Merge pull request #32 from nexB/download_urls
Add support for download urls
2 parents 6dab7e1 + 8aa1dc3 commit 9ae2874

7 files changed

Lines changed: 314 additions & 74 deletions

src/python_inspector/resolution.py

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,36 @@ def get_dependencies(self, candidate):
384384
return list(self._iter_dependencies(candidate))
385385

386386

387+
def get_wheel_download_urls(purl, repos, environment, python_version):
388+
"""
389+
Return a list of download urls for the given purl.
390+
"""
391+
for repo in repos:
392+
for wheel in utils_pypi.get_supported_and_valid_wheels(
393+
repo=repo,
394+
name=purl.name,
395+
version=purl.version,
396+
environment=environment,
397+
python_version=python_version,
398+
):
399+
yield wheel.download_url
400+
401+
402+
def get_sdist_download_url(purl, repos, python_version):
403+
"""
404+
Return a list of download urls for the given purl.
405+
"""
406+
for repo in repos:
407+
sdist = utils_pypi.get_valid_sdist(
408+
repo=repo,
409+
name=purl.name,
410+
version=purl.version,
411+
python_version=python_version,
412+
)
413+
if sdist:
414+
return sdist.download_url
415+
416+
387417
def get_all_srcs(mapping, graph):
388418
"""
389419
Return a list of all sources in the graph.
@@ -412,7 +442,7 @@ def dfs(mapping, graph, src):
412442
)
413443

414444

415-
def format_resolution(results, as_tree=False):
445+
def format_resolution(results, environment, repos, as_tree=False):
416446
"""
417447
Return a formatted resolution either as a tree or parent/children.
418448
"""
@@ -437,7 +467,28 @@ def format_resolution(results, as_tree=False):
437467
)
438468
dependencies.append(str(dep_purl))
439469
dependencies.sort()
440-
parent_children = dict(package=str(parent_purl), dependencies=dependencies)
470+
python_version = get_python_version_from_env_tag(
471+
python_version=environment.python_version
472+
)
473+
wheel_urls = list(
474+
get_wheel_download_urls(
475+
purl=parent_purl,
476+
repos=repos,
477+
environment=environment,
478+
python_version=python_version,
479+
)
480+
)
481+
sdist_url = get_sdist_download_url(
482+
purl=parent_purl,
483+
repos=repos,
484+
python_version=python_version,
485+
)
486+
parent_children = dict(
487+
package=str(parent_purl),
488+
dependencies=dependencies,
489+
wheel_urls=list(dict.fromkeys(wheel_urls)),
490+
sdist_url=sdist_url,
491+
)
441492
as_parent_children.append(parent_children)
442493
as_parent_children.sort(key=lambda d: d["package"])
443494
return as_parent_children
@@ -477,5 +528,5 @@ def get_resolved_dependencies(
477528
reporter=BaseReporter(),
478529
)
479530
results = resolver.resolve(requirements=requirements, max_rounds=max_rounds)
480-
results = format_resolution(results, as_tree=as_tree)
531+
results = format_resolution(results, as_tree=as_tree, environment=environment, repos=repos)
481532
return results

src/python_inspector/utils_pypi.py

Lines changed: 62 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -219,28 +219,17 @@ def download_wheel(
219219
repos = DEFAULT_PYPI_REPOS
220220

221221
fetched_wheel_filenames = []
222-
223222
for repo in repos:
224-
package = repo.get_package_version(name=name, version=version)
225-
if not package:
226-
if TRACE_DEEP:
227-
print(f" download_wheel: No package in {repo.index_url} for {name}=={version}")
228-
continue
229-
supported_wheels = list(package.get_supported_wheels(environment=environment))
230-
if not supported_wheels:
223+
supported_and_valid_wheels = get_supported_and_valid_wheels(
224+
repo, name, version, environment, python_version
225+
)
226+
if not supported_and_valid_wheels:
231227
if TRACE_DEEP:
232228
print(
233-
f" download_wheel: No supported wheel for {name}=={version}: {environment} "
229+
f" download_wheel: No supported and valid wheel for {name}=={version}: {environment} "
234230
)
235231
continue
236-
237-
for wheel in supported_wheels:
238-
if not valid_distribution(wheel, python_version):
239-
continue
240-
if TRACE_DEEP:
241-
print(
242-
f" download_wheel: Getting wheel from index (or cache): {wheel.download_url}"
243-
)
232+
for wheel in supported_and_valid_wheels:
244233
fetched_wheel_filename = wheel.download(
245234
dest_dir=dest_dir,
246235
verbose=verbose,
@@ -251,10 +240,62 @@ def download_wheel(
251240
if fetched_wheel_filenames:
252241
# do not futher fetch from other repos if we find in first, typically PyPI
253242
break
254-
255243
return fetched_wheel_filenames
256244

257245

246+
def get_valid_sdist(repo, name, version, python_version=DEFAULT_PYTHON_VERSION):
247+
package = repo.get_package_version(name=name, version=version)
248+
if not package:
249+
if TRACE_DEEP:
250+
print(
251+
print(f" get_valid_sdist: No package in {repo.index_url} for {name}=={version}")
252+
)
253+
return
254+
sdist = package.sdist
255+
if not sdist:
256+
if TRACE_DEEP:
257+
print(f" get_valid_sdist: No sdist for {name}=={version}")
258+
return
259+
if not valid_distribution(sdist, python_version):
260+
return
261+
if TRACE_DEEP:
262+
print(f" get_valid_sdist: Getting sdist from index (or cache): {sdist.download_url}")
263+
return sdist
264+
265+
266+
def get_supported_and_valid_wheels(
267+
repo, name, version, environment, python_version=DEFAULT_PYTHON_VERSION
268+
) -> List:
269+
"""
270+
Return a list of wheels matching the ``environment`` Environment constraints.
271+
"""
272+
package = repo.get_package_version(name=name, version=version)
273+
if not package:
274+
if TRACE_DEEP:
275+
print(
276+
f" get_supported_and_valid_wheels: No package in {repo.index_url} for {name}=={version}"
277+
)
278+
return []
279+
supported_wheels = list(package.get_supported_wheels(environment=environment))
280+
if not supported_wheels:
281+
if TRACE_DEEP:
282+
print(
283+
f" get_supported_and_valid_wheels: No supported wheel for {name}=={version}: {environment}"
284+
)
285+
return []
286+
wheels = []
287+
for wheel in supported_wheels:
288+
if not valid_distribution(wheel, python_version):
289+
continue
290+
if TRACE_DEEP:
291+
print(
292+
f""" get_supported_and_valid_wheels: Getting wheel from index (or cache):
293+
{wheel.download_url}"""
294+
)
295+
wheels.append(wheel)
296+
return wheels
297+
298+
258299
def valid_distribution(distribution, python_version):
259300
"""
260301
Return True if distribution is a valid distribution for the given Python version.
@@ -289,22 +330,12 @@ def download_sdist(
289330
fetched_sdist_filename = None
290331

291332
for repo in repos:
292-
package = repo.get_package_version(name=name, version=version)
293-
294-
if not package:
295-
if TRACE_DEEP:
296-
print(f" download_sdist: No package in {repo.index_url} for {name}=={version}")
297-
continue
298-
sdist = package.sdist
333+
sdist = get_valid_sdist(repo, name, version, python_version=DEFAULT_PYTHON_VERSION)
299334
if not sdist:
300335
if TRACE_DEEP:
301-
print(f" download_sdist: No sdist for {name}=={version}")
336+
print(f" download_sdist: No valid sdist for {name}=={version}")
302337
continue
303-
if not valid_distribution(sdist, python_version):
304-
continue
305-
if TRACE_DEEP:
306-
print(f" download_sdist: Getting sdist from index (or cache): {sdist.download_url}")
307-
fetched_sdist_filename = package.sdist.download(
338+
fetched_sdist_filename = sdist.download(
308339
dest_dir=dest_dir,
309340
verbose=verbose,
310341
echo_func=echo_func,

tests/data/default-url-expected.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@
2828
"resolved_dependencies": [
2929
{
3030
"package": "pkg:pypi/zipp@3.8.0",
31-
"dependencies": []
31+
"dependencies": [],
32+
"wheel_urls": [],
33+
"sdist_url": null
3234
}
3335
]
3436
}

0 commit comments

Comments
 (0)