Skip to content

Commit 733fcd5

Browse files
committed
Merge latest main
Signed-off-by: Philippe Ombredanne <pombredanne@nexb.com>
2 parents c9165be + bb4f333 commit 733fcd5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+5755
-27441
lines changed

.github/workflows/pypi-release.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424
runs-on: ubuntu-20.04
2525

2626
steps:
27-
- uses: actions/checkout@v3
27+
- uses: actions/checkout@v4
2828
- name: Set up Python
2929
uses: actions/setup-python@v4
3030
with:
@@ -37,7 +37,7 @@ jobs:
3737
run: python -m build --sdist --wheel --outdir dist/
3838

3939
- name: Upload built archives
40-
uses: actions/upload-artifact@v3
40+
uses: actions/upload-artifact@v4
4141
with:
4242
name: pypi_archives
4343
path: dist/*
@@ -51,7 +51,7 @@ jobs:
5151

5252
steps:
5353
- name: Download built archives
54-
uses: actions/download-artifact@v3
54+
uses: actions/download-artifact@v4
5555
with:
5656
name: pypi_archives
5757
path: dist
@@ -71,7 +71,7 @@ jobs:
7171

7272
steps:
7373
- name: Download built archives
74-
uses: actions/download-artifact@v3
74+
uses: actions/download-artifact@v4
7575
with:
7676
name: pypi_archives
7777
path: dist

CHANGELOG.rst

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Changelog
22
=========
33

4-
v0.13.0
4+
v0.13.2
55
-----------
66

77
- Speed up downloads with asyncio
@@ -33,6 +33,15 @@ v0.13.0
3333
- Merge latest skeleton and adopt ruff for code formatting.
3434

3535

36+
v0.13.1
37+
-----------
38+
39+
- Fix ResolutionImpossible for lief==0.15.1 #202
40+
- Add license expression data from pypi API #208
41+
- Add python 3.13 in python-inspector #196
42+
- Update homepage_url and fix CI and tests
43+
44+
3645
v0.12.1
3746
-----------
3847

azure-pipelines.yml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,46 +9,46 @@ jobs:
99
parameters:
1010
job_name: ubuntu20_cpython
1111
image_name: ubuntu-20.04
12-
python_versions: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]
12+
python_versions: ["3.9", "3.10", "3.11", "3.12"]
1313
test_suites:
1414
all: venv/bin/pytest -n 2 -vvs --reruns 2
1515

1616
- template: etc/ci/azure-posix.yml
1717
parameters:
1818
job_name: ubuntu22_cpython
1919
image_name: ubuntu-22.04
20-
python_versions: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]
20+
python_versions: ["3.9", "3.10", "3.11", "3.12"]
2121
test_suites:
2222
all: venv/bin/pytest -n 2 -vvs --reruns 2
2323

2424
- template: etc/ci/azure-posix.yml
2525
parameters:
26-
job_name: macos12_cpython
27-
image_name: macOS-12
28-
python_versions: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]
26+
job_name: macos14_cpython
27+
image_name: macOS-14
28+
python_versions: ["3.9", "3.10", "3.11", "3.12"]
2929
test_suites:
3030
all: venv/bin/pytest -n 2 -vvs --reruns 2
3131

3232
- template: etc/ci/azure-posix.yml
3333
parameters:
3434
job_name: macos13_cpython
3535
image_name: macos-13
36-
python_versions: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]
36+
python_versions: ["3.9", "3.10", "3.11", "3.12"]
3737
test_suites:
3838
all: venv/bin/pytest -n 2 -vvs --reruns 2
3939

4040
- template: etc/ci/azure-win.yml
4141
parameters:
4242
job_name: win2019_cpython
4343
image_name: windows-2019
44-
python_versions: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]
44+
python_versions: ["3.9", "3.10", "3.11", "3.12"]
4545
test_suites:
4646
all: venv\Scripts\pytest -n 2 -vvs --reruns 2
4747

4848
- template: etc/ci/azure-win.yml
4949
parameters:
5050
job_name: win2022_cpython
5151
image_name: windows-2022
52-
python_versions: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]
52+
python_versions: ["3.9", "3.10", "3.11", "3.12"]
5353
test_suites:
5454
all: venv\Scripts\pytest -n 2 -vvs --reruns 2

requirements-dev.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,5 @@ tomli==1.2.3
3838
tqdm==4.64.0
3939
twine==3.8.0
4040
typed-ast==1.5.4
41-
webencodings==0.5.1
41+
webencodings==0.5.1
42+
pytest-asyncio==0.21.1

requirements.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ idna==3.3
1010
importlib-metadata==4.12.0
1111
intbitset==3.1.0
1212
packageurl-python==0.10.0
13-
packaging==21.3
13+
packaging==24.2
1414
packvers==21.5
1515
pip-requirements-parser==32.0.1
1616
pkginfo2==30.0.0
@@ -26,3 +26,5 @@ text-unidecode==1.3
2626
toml==0.10.2
2727
urllib3==1.26.11
2828
zipp==3.8.1
29+
aiohttp==3.11.14
30+
aiofiles==23.2.1

setup.cfg

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ install_requires =
6969
toml >= 0.10.0
7070
mock >= 3.0.5
7171
packvers >= 21.5
72+
aiohttp >= 3.8
73+
aiofiles >= 23.1
7274
pydantic >= 2.10.0
7375
pydantic_settings >= 2.8.0
7476

@@ -89,6 +91,7 @@ testing =
8991
black
9092
isort
9193
pytest-rerunfailures
94+
pytest-asyncio >= 0.21
9295

9396
docs =
9497
Sphinx>=5.0.2

src/python_inspector/api.py

Lines changed: 94 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@
88
# See https://aboutcode-orgnexB/python-inspector for support or download.
99
# See https://aboutcode.org for more information about nexB OSS projects.
1010
#
11-
11+
import asyncio
1212
import os
1313
from netrc import netrc
1414
from typing import Dict
1515
from typing import List
1616
from typing import NamedTuple
1717
from typing import Sequence
18+
from typing import Tuple
1819

1920
from packageurl import PackageURL
2021
from packvers.requirements import Requirement
@@ -26,6 +27,7 @@
2627
from _packagedcode.pypi import PipRequirementsFileHandler
2728
from _packagedcode.pypi import PythonSetupPyHandler
2829
from _packagedcode.pypi import can_process_dependent_package
30+
from _packagedcode.pypi import get_resolved_purl
2931
from python_inspector import dependencies
3032
from python_inspector import pyinspector_settings as settings
3133
from python_inspector import utils
@@ -39,6 +41,7 @@
3941
from python_inspector.resolution import get_python_version_from_env_tag
4042
from python_inspector.resolution import get_reqs_insecurely
4143
from python_inspector.resolution import get_requirements_from_python_manifest
44+
from python_inspector.utils import Candidate
4245
from python_inspector.utils_pypi import PLATFORMS_BY_OS
4346
from python_inspector.utils_pypi import Environment
4447
from python_inspector.utils_pypi import PypiSimpleRepository
@@ -54,7 +57,7 @@ class Resolution(NamedTuple):
5457
``files`` is a parsed list of input file data.
5558
"""
5659

57-
resolution: Dict
60+
resolution: List[Dict]
5861
packages: List[PackageData]
5962
files: List[Dict]
6063

@@ -286,21 +289,27 @@ def resolve_dependencies(
286289
pdt_output=pdt_output,
287290
analyze_setup_py_insecurely=analyze_setup_py_insecurely,
288291
ignore_errors=ignore_errors,
292+
verbose=verbose,
293+
printer=printer,
289294
)
290295

291-
packages = []
296+
async def gather_pypi_data():
297+
async def get_pypi_data(package):
298+
data = await get_pypi_data_from_purl(
299+
package, repos=repos, environment=environment, prefer_source=prefer_source
300+
)
292301

293-
for package in purls:
294-
packages.extend(
295-
[
296-
pkg.to_dict()
297-
for pkg in list(
298-
get_pypi_data_from_purl(
299-
package, repos=repos, environment=environment, prefer_source=prefer_source
300-
)
301-
)
302-
],
303-
)
302+
if verbose:
303+
printer(f" retrieved package '{package}'")
304+
305+
return data
306+
307+
if verbose:
308+
printer(f"retrieve package data from pypi:")
309+
310+
return await asyncio.gather(*[get_pypi_data(package) for package in purls])
311+
312+
packages = [pkg.to_dict() for pkg in asyncio.run(gather_pypi_data()) if pkg is not None]
304313

305314
if verbose:
306315
printer("done!")
@@ -316,14 +325,16 @@ def resolve_dependencies(
316325

317326

318327
def resolve(
319-
direct_dependencies,
320-
environment,
321-
repos=tuple(),
322-
as_tree=False,
323-
max_rounds=200000,
324-
pdt_output=False,
325-
analyze_setup_py_insecurely=False,
326-
ignore_errors=False,
328+
direct_dependencies: List[DependentPackage],
329+
environment: Environment,
330+
repos: Sequence[utils_pypi.PypiSimpleRepository] = tuple(),
331+
as_tree: bool = False,
332+
max_rounds: int = 200000,
333+
pdt_output: bool = False,
334+
analyze_setup_py_insecurely: bool = False,
335+
ignore_errors: bool = False,
336+
verbose: bool = False,
337+
printer=print,
327338
):
328339
"""
329340
Resolve dependencies given a ``direct_dependencies`` list of
@@ -350,6 +361,8 @@ def resolve(
350361
pdt_output=pdt_output,
351362
analyze_setup_py_insecurely=analyze_setup_py_insecurely,
352363
ignore_errors=ignore_errors,
364+
verbose=verbose,
365+
printer=printer,
353366
)
354367

355368
return resolved_dependencies, packages
@@ -364,32 +377,77 @@ def get_resolved_dependencies(
364377
pdt_output: bool = False,
365378
analyze_setup_py_insecurely: bool = False,
366379
ignore_errors: bool = False,
367-
):
380+
verbose: bool = False,
381+
printer=print,
382+
) -> Tuple[List[Dict], List[str]]:
368383
"""
369384
Return resolved dependencies of a ``requirements`` list of Requirement for
370-
an ``enviroment`` Environment. The resolved dependencies are formatted as
385+
an ``environment`` Environment. The resolved dependencies are formatted as
371386
parent/children or a nested tree if ``as_tree`` is True.
372387
373388
Used the provided ``repos`` list of PypiSimpleRepository.
374-
If empty, use instead the PyPI.org JSON API exclusively instead
389+
If empty, use instead the PyPI.org JSON API exclusively instead.
375390
"""
391+
provider = PythonInputProvider(
392+
environment=environment,
393+
repos=repos,
394+
analyze_setup_py_insecurely=analyze_setup_py_insecurely,
395+
ignore_errors=ignore_errors,
396+
)
397+
398+
# gather version data for all requirements concurrently in advance.
399+
400+
async def gather_version_data():
401+
async def get_version_data(name: str):
402+
versions = await provider.fill_versions_for_package(name)
403+
404+
if verbose:
405+
printer(f" retrieved versions for package '{name}'")
406+
407+
return versions
408+
409+
if verbose:
410+
printer(f"versions:")
411+
412+
return await asyncio.gather(
413+
*[get_version_data(requirement.name) for requirement in requirements]
414+
)
415+
416+
asyncio.run(gather_version_data())
417+
418+
# gather dependencies for all pinned requirements concurrently in advance.
419+
420+
async def gather_dependencies():
421+
async def get_dependencies(requirement: Requirement):
422+
purl = PackageURL(type="pypi", name=requirement.name)
423+
resolved_purl = get_resolved_purl(purl=purl, specifiers=requirement.specifier)
424+
425+
if resolved_purl:
426+
purl = resolved_purl.purl
427+
candidate = Candidate(requirement.name, purl.version, requirement.extras)
428+
await provider.fill_requirements_for_package(purl, candidate)
429+
430+
if verbose:
431+
printer(f" retrieved dependencies for requirement '{str(purl)}'")
432+
433+
if verbose:
434+
printer(f"dependencies:")
435+
436+
return await asyncio.gather(
437+
*[get_dependencies(requirement) for requirement in requirements]
438+
)
439+
440+
asyncio.run(gather_dependencies())
441+
376442
resolver = Resolver(
377-
provider=PythonInputProvider(
378-
environment=environment,
379-
repos=repos,
380-
analyze_setup_py_insecurely=analyze_setup_py_insecurely,
381-
ignore_errors=ignore_errors,
382-
),
443+
provider=provider,
383444
reporter=BaseReporter(),
384445
)
385446
resolver_results = resolver.resolve(requirements=requirements, max_rounds=max_rounds)
386447
package_list = get_package_list(results=resolver_results)
387448
if pdt_output:
388-
return (format_pdt_tree(resolver_results), package_list)
389-
return (
390-
format_resolution(resolver_results, as_tree=as_tree),
391-
package_list,
392-
)
449+
return format_pdt_tree(resolver_results), package_list
450+
return format_resolution(resolver_results, as_tree=as_tree), package_list
393451

394452

395453
def get_requirements_from_direct_dependencies(

0 commit comments

Comments
 (0)