Skip to content

Commit f510b95

Browse files
authored
Merge pull request #53 from nexB/52
Ensure to filter out top level dependencies on the basis of their environment markers
2 parents f2b5e09 + 10c22ec commit f510b95

11 files changed

+161
-31
lines changed

src/python_inspector/resolution.py

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,17 @@ def get_requirements_from_distribution(
101101
return list(get_requirements_from_dependencies(dependencies=deps[0].dependencies))
102102

103103

104+
def get_environment_marker_from_environment(environment):
105+
return {
106+
"extra": "",
107+
"python_version": get_python_version_from_env_tag(
108+
python_version=environment.python_version
109+
),
110+
"platform_system": environment.operating_system.capitalize(),
111+
"sys_platform": environment.operating_system,
112+
}
113+
114+
104115
def is_requirements_file_in_setup_files(setup_files: List[str]) -> bool:
105116
"""
106117
Return True if the string ``requirements.txt`` is found in any of the ``setup_files`` location
@@ -220,6 +231,7 @@ def remove_extras(identifier: str) -> str:
220231
class PythonInputProvider(AbstractProvider):
221232
def __init__(self, environment=None, repos=tuple()):
222233
self.environment = environment
234+
self.environment_marker = get_environment_marker_from_environment(environment)
223235
self.repos = repos or []
224236
self.versions_by_package = {}
225237
self.dependencies_by_purl = {}
@@ -484,16 +496,7 @@ def _iter_dependencies(self, candidate: Candidate) -> Generator[Requirement, Non
484496
if r.marker is None:
485497
yield r
486498
else:
487-
if r.marker.evaluate(
488-
{
489-
"extra": "",
490-
"python_version": get_python_version_from_env_tag(
491-
python_version=self.environment.python_version
492-
),
493-
"platform_system": self.environment.operating_system.capitalize(),
494-
"sys_platform": self.environment.operating_system,
495-
}
496-
):
499+
if r.marker.evaluate(self.environment_marker):
497500
yield r
498501

499502
def get_dependencies(self, candidate: Candidate) -> List[Requirement]:

src/python_inspector/resolve_cli.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import json
1313
import os
14+
from typing import Dict
1415
from typing import List
1516

1617
import click
@@ -24,6 +25,7 @@
2425
from python_inspector import utils
2526
from python_inspector import utils_pypi
2627
from python_inspector.cli_utils import FileOptionType
28+
from python_inspector.resolution import get_environment_marker_from_environment
2729
from python_inspector.resolution import get_resolved_dependencies
2830

2931
TRACE = False
@@ -351,7 +353,13 @@ def resolve(
351353
If empty, use instead the PyPI.org JSON API exclusively.
352354
"""
353355

354-
requirements = list(get_requirements_from_direct_dependencies(direct_dependencies))
356+
environment_marker = get_environment_marker_from_environment(environment)
357+
358+
requirements = list(
359+
get_requirements_from_direct_dependencies(
360+
direct_dependencies=direct_dependencies, environment_marker=environment_marker
361+
)
362+
)
355363

356364
resolved_dependencies = get_resolved_dependencies(
357365
requirements=requirements,
@@ -369,15 +377,20 @@ def resolve(
369377

370378

371379
def get_requirements_from_direct_dependencies(
372-
direct_dependencies: List[DependentPackage],
380+
direct_dependencies: List[DependentPackage], environment_marker: Dict
373381
) -> List[Requirement]:
374382
for dependency in direct_dependencies:
375383
# FIXME We are skipping editable requirements
376384
# and other pip options for now
377385
# https://github.com/nexB/python-inspector/issues/41
378386
if not can_process_dependent_package(dependency):
379387
continue
380-
yield Requirement(requirement_string=dependency.extracted_requirement)
388+
req = Requirement(requirement_string=dependency.extracted_requirement)
389+
if req.marker is None:
390+
yield req
391+
else:
392+
if req.marker.evaluate(environment_marker):
393+
yield req
381394

382395

383396
def write_output(headers, requirements, resolved_dependencies, json_output, pdt_output=False):
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
click>6,<6.8
2+
Flask==1.0
3+
itsdangerous<0.25
4+
license-expression ; platform_system == "Windows"
5+
Jinja2==2.11.3
6+
MarkupSafe==1.0
7+
Werkzeug==0.15.3
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
[
2+
{
3+
"key": "flask",
4+
"package_name": "flask",
5+
"installed_version": "1.0",
6+
"dependencies": [
7+
{
8+
"key": "click",
9+
"package_name": "click",
10+
"installed_version": "6.7",
11+
"dependencies": []
12+
},
13+
{
14+
"key": "itsdangerous",
15+
"package_name": "itsdangerous",
16+
"installed_version": "0.24",
17+
"dependencies": []
18+
},
19+
{
20+
"key": "jinja2",
21+
"package_name": "jinja2",
22+
"installed_version": "2.11.3",
23+
"dependencies": [
24+
{
25+
"key": "markupsafe",
26+
"package_name": "markupsafe",
27+
"installed_version": "1.0",
28+
"dependencies": []
29+
}
30+
]
31+
},
32+
{
33+
"key": "werkzeug",
34+
"package_name": "werkzeug",
35+
"installed_version": "0.15.3",
36+
"dependencies": []
37+
}
38+
]
39+
}
40+
]
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
aboutcode-toolkit==7.0.2
2+
attrs==21.4.0
3+
beautifulsoup4==4.11.1
4+
certifi==2022.5.18.1
5+
charset-normalizer==2.0.12
6+
click==8.0.4
7+
colorama==0.4.4
8+
commoncode==30.2.0
9+
dparse2==0.6.1
10+
idna==3.3
11+
importlib-metadata==4.8.3
12+
intbitset==3.0.1
13+
packageurl-python==0.9.9
14+
packaging==21.3
15+
-e git+https://github.com/nexB/python-inspector@18baae17824d6bacb4b1d519b10a0d0e50775884#egg=python_inspector
16+
pip-requirements-parser==31.2.0
17+
pkginfo2==30.0.0
18+
pyparsing==3.0.9
19+
PyYAML==6.0
20+
requests==2.27.1
21+
resolvelib==0.8.1
22+
saneyaml==0.5.2
23+
soupsieve==2.3.2.post1
24+
text-unidecode==1.3
25+
toml==0.10.2
26+
typing==3.6.6
27+
typing_extensions==4.1.1
28+
urllib3==1.26.9
29+
zipp==3.6.0

tests/data/single-url-except-simple-expected.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,18 @@
3737
"sdist_url": "https://files.pythonhosted.org/packages/59/87/84326af34517fca8c58418d148f2403df25303e02736832403587318e9e8/click-8.1.3.tar.gz"
3838
},
3939
{
40-
"package": "pkg:pypi/[email protected].1",
40+
"package": "pkg:pypi/[email protected].2",
4141
"dependencies": [
4242
"pkg:pypi/[email protected]",
4343
"pkg:pypi/[email protected]",
4444
"pkg:pypi/[email protected]",
4545
"pkg:pypi/[email protected]",
46-
"pkg:pypi/[email protected].1"
46+
"pkg:pypi/[email protected].2"
4747
],
4848
"wheel_urls": [
49-
"https://files.pythonhosted.org/packages/3c/96/6c896f80f466b7f5e2cfd6d632fe5b0464dcb412757c595a663e59589a93/Flask-2.2.1-py3-none-any.whl"
49+
"https://files.pythonhosted.org/packages/0f/43/15f4f9ab225b0b25352412e8daa3d0e3d135fcf5e127070c74c3632c8b4c/Flask-2.2.2-py3-none-any.whl"
5050
],
51-
"sdist_url": "https://files.pythonhosted.org/packages/4b/4f/50888944490f2263bd70171e8298c9626675fd3dfd750694a7beaa3484fb/Flask-2.2.1.tar.gz"
51+
"sdist_url": "https://files.pythonhosted.org/packages/69/b6/53cfa30eed5aa7343daff36622843688ba8c6fe9829bb2b92e193ab1163f/Flask-2.2.2.tar.gz"
5252
},
5353
{
5454
"package": "pkg:pypi/[email protected]",
@@ -87,14 +87,14 @@
8787
"sdist_url": "https://files.pythonhosted.org/packages/1d/97/2288fe498044284f39ab8950703e88abbac2abbdf65524d576157af70556/MarkupSafe-2.1.1.tar.gz"
8888
},
8989
{
90-
"package": "pkg:pypi/[email protected].1",
90+
"package": "pkg:pypi/[email protected].2",
9191
"dependencies": [
9292
"pkg:pypi/[email protected]"
9393
],
9494
"wheel_urls": [
95-
"https://files.pythonhosted.org/packages/c0/93/d6d60870e47162ea6a1bbdd787649eea776b2a70618dd66ed87cb2238543/Werkzeug-2.2.1-py3-none-any.whl"
95+
"https://files.pythonhosted.org/packages/c8/27/be6ddbcf60115305205de79c29004a0c6bc53cec814f733467b1bb89386d/Werkzeug-2.2.2-py3-none-any.whl"
9696
],
97-
"sdist_url": "https://files.pythonhosted.org/packages/32/19/a92cdbd9fb795928dfca1031278ae8a7f051e78a2c057c224ad2d4cdd95e/Werkzeug-2.2.1.tar.gz"
97+
"sdist_url": "https://files.pythonhosted.org/packages/f8/c1/1c8e539f040acd80f844c69a5ef8e2fccdf8b442dabb969e497b55d544e1/Werkzeug-2.2.2.tar.gz"
9898
},
9999
{
100100
"package": "pkg:pypi/[email protected]",

tests/test_cli.py

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def test_cli_with_default_urls():
4545
@pytest.mark.online
4646
def test_pdt_output():
4747
requirements_file = test_env.get_test_loc("pdt-requirements.txt")
48-
expected_file = test_env.get_test_loc("pdt-expected.json", must_exist=False)
48+
expected_file = test_env.get_test_loc("pdt-requirements.txt-expected.json", must_exist=False)
4949
extra_options = []
5050
check_requirements_resolution(
5151
requirements_file=requirements_file,
@@ -58,8 +58,10 @@ def test_pdt_output():
5858

5959
@pytest.mark.online
6060
def test_pdt_output_with_pinned_requirements():
61-
requirements_file = test_env.get_test_loc("pinned-requirements.txt")
62-
expected_file = test_env.get_test_loc("pinned-requirements-pdt-expected.json", must_exist=False)
61+
requirements_file = test_env.get_test_loc("pinned-pdt-requirements.txt")
62+
expected_file = test_env.get_test_loc(
63+
"pinned-pdt-requirements.txt-expected.json", must_exist=False
64+
)
6365
extra_options = []
6466
check_requirements_resolution(
6567
requirements_file=requirements_file,
@@ -73,7 +75,7 @@ def test_pdt_output_with_pinned_requirements():
7375
@pytest.mark.online
7476
def test_pdt_output_with_frozen_requirements():
7577
requirements_file = test_env.get_test_loc("frozen-requirements.txt")
76-
expected_file = test_env.get_test_loc("frozen-requirements-pdt-expected.json", must_exist=False)
78+
expected_file = test_env.get_test_loc("frozen-requirements.txt-expected.json", must_exist=False)
7779
extra_options = []
7880
check_requirements_resolution(
7981
requirements_file=requirements_file,
@@ -137,6 +139,27 @@ def test_cli_with_multiple_index_url_and_tilde_req():
137139
)
138140

139141

142+
@pytest.mark.online
143+
def test_cli_with_environment_marker_and_complex_ranges():
144+
requirements_file = test_env.get_test_loc("environment-marker-test-requirements.txt")
145+
expected_file = test_env.get_test_loc(
146+
"environment-marker-test-requirements.txt-expected.json", must_exist=False
147+
)
148+
extra_options = [
149+
"--operating-system",
150+
"linux",
151+
"--python-version",
152+
"37",
153+
]
154+
check_requirements_resolution(
155+
requirements_file=requirements_file,
156+
expected_file=expected_file,
157+
extra_options=extra_options,
158+
pdt_output=True,
159+
regen=REGEN_TEST_FIXTURES,
160+
)
161+
162+
140163
@pytest.mark.online
141164
def test_cli_with_multiple_index_url_and_tilde_req_with_max_rounds():
142165
expected_file = test_env.get_test_loc("tilde_req-expected.json", must_exist=False)
@@ -345,13 +368,23 @@ def test_get_requirements_from_direct_dependencies():
345368
)
346369
]
347370

348-
requirements = [str(r) for r in get_requirements_from_direct_dependencies(direct_dependencies)]
371+
requirements = [
372+
str(r)
373+
for r in get_requirements_from_direct_dependencies(
374+
direct_dependencies=direct_dependencies, environment_marker={}
375+
)
376+
]
349377

350378
assert requirements == ["django>=1.11.11"]
351379

352380

353381
def test_get_requirements_from_direct_dependencies_with_empty_list():
354-
assert list(get_requirements_from_direct_dependencies(direct_dependencies=[])) == []
382+
assert (
383+
list(
384+
get_requirements_from_direct_dependencies(direct_dependencies=[], environment_marker={})
385+
)
386+
== []
387+
)
355388

356389

357390
def test_get_requirements_from_direct_dependencies_with_editable_requirements():
@@ -378,6 +411,11 @@ def test_get_requirements_from_direct_dependencies_with_editable_requirements():
378411
)
379412
]
380413

381-
requirements = [str(r) for r in get_requirements_from_direct_dependencies(direct_dependencies)]
414+
requirements = [
415+
str(r)
416+
for r in get_requirements_from_direct_dependencies(
417+
direct_dependencies=direct_dependencies, environment_marker={}
418+
)
419+
]
382420

383421
assert requirements == []

tests/test_resolution.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def test_get_resolved_dependencies_with_flask_and_python_310():
4040
"pkg:pypi/[email protected]",
4141
"pkg:pypi/[email protected]",
4242
"pkg:pypi/[email protected]",
43-
"pkg:pypi/[email protected].1",
43+
"pkg:pypi/[email protected].2",
4444
]
4545

4646

@@ -65,7 +65,7 @@ def test_get_resolved_dependencies_with_flask_and_python_310_windows():
6565
"pkg:pypi/[email protected]",
6666
"pkg:pypi/[email protected]",
6767
"pkg:pypi/[email protected]",
68-
"pkg:pypi/[email protected].1",
68+
"pkg:pypi/[email protected].2",
6969
]
7070

7171

@@ -118,7 +118,7 @@ def test_get_resolved_dependencies_with_tilde_requirement_using_json_api():
118118
"pkg:pypi/[email protected]",
119119
"pkg:pypi/[email protected]",
120120
"pkg:pypi/[email protected]",
121-
"pkg:pypi/[email protected].1",
121+
"pkg:pypi/[email protected].2",
122122
"pkg:pypi/[email protected]",
123123
]
124124

@@ -145,7 +145,7 @@ def test_without_supported_wheels():
145145
"pkg:pypi/[email protected]",
146146
"pkg:pypi/[email protected]",
147147
"pkg:pypi/[email protected]",
148-
"pkg:pypi/setuptools@63.4.1",
148+
"pkg:pypi/setuptools@65.0.0",
149149
"pkg:pypi/[email protected]",
150150
]
151151

0 commit comments

Comments
 (0)