Skip to content

Commit 8f50377

Browse files
committed
Fix resolution of setup files which partially have dynamic dependencies
Signed-off-by: Tushar Goel <tushar.goel.dav@gmail.com>
1 parent 9e765ec commit 8f50377

15 files changed

+412
-245
lines changed

src/python_inspector/api.py

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
from python_inspector.resolution import get_environment_marker_from_environment
3838
from python_inspector.resolution import get_package_list
3939
from python_inspector.resolution import get_python_version_from_env_tag
40+
from python_inspector.resolution import get_reqs_insecurely
4041
from python_inspector.resolution import get_requirements_from_python_manifest
4142
from python_inspector.utils_pypi import PLATFORMS_BY_OS
4243
from python_inspector.utils_pypi import PYPI_SIMPLE_URL
@@ -175,22 +176,30 @@ def resolve_dependencies(
175176
f"is not compatible with setup.py {setup_py_file} "
176177
f"python_requires {python_requires}",
177178
)
178-
179-
setup_py_file_deps = package_data.dependencies
180-
for dep in package_data.dependencies:
181-
# TODO : we need to handle to all the scopes
182-
if dep.scope == "install":
183-
direct_dependencies.append(dep)
184-
185-
if not package_data.dependencies:
186-
reqs = get_requirements_from_python_manifest(
187-
sdist_location=os.path.dirname(setup_py_file),
188-
setup_py_location=setup_py_file,
189-
files=[setup_py_file],
190-
analyze_setup_py_insecurely=analyze_setup_py_insecurely,
179+
if analyze_setup_py_insecurely:
180+
reqs = list(
181+
get_reqs_insecurely(
182+
setup_py_location=setup_py_file,
183+
)
191184
)
192185
setup_py_file_deps = list(get_dependent_packages_from_reqs(reqs))
193186
direct_dependencies.extend(setup_py_file_deps)
187+
else:
188+
setup_py_file_deps = package_data.dependencies
189+
for dep in package_data.dependencies:
190+
# TODO : we need to handle to all the scopes
191+
if dep.scope == "install":
192+
direct_dependencies.append(dep)
193+
194+
if not package_data.dependencies:
195+
reqs = get_requirements_from_python_manifest(
196+
sdist_location=os.path.dirname(setup_py_file),
197+
setup_py_location=setup_py_file,
198+
files=[setup_py_file],
199+
analyze_setup_py_insecurely=analyze_setup_py_insecurely,
200+
)
201+
setup_py_file_deps = list(get_dependent_packages_from_reqs(reqs))
202+
direct_dependencies.extend(setup_py_file_deps)
194203

195204
package_data.dependencies = setup_py_file_deps
196205
file_package_data = [package_data.to_dict()]

src/python_inspector/resolution.py

Lines changed: 20 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -292,19 +292,6 @@ def get_requirements_from_python_manifest(
292292
if requirements:
293293
yield from requirements
294294

295-
elif contain_string(string="_require", files=[setup_py_location]):
296-
if analyze_setup_py_insecurely:
297-
yield from get_reqs_insecurely(
298-
setup_py_location=setup_py_location,
299-
)
300-
301-
else:
302-
# We should not raise exception here as we may have a setup.py that does not
303-
# have any dependencies. We should not fail in this case.
304-
raise Exception(
305-
f"Unable to collect setup.py dependencies securely: {setup_py_location}"
306-
)
307-
308295

309296
DEFAULT_ENVIRONMENT = utils_pypi.Environment.from_pyver_and_os(
310297
python_version="38", operating_system="linux"
@@ -454,25 +441,30 @@ def get_requirements_for_package_from_pypi_simple(
454441
"setup.cfg",
455442
)
456443

457-
requirements = list(
458-
get_setup_requirements(
459-
sdist_location=sdist_location,
444+
if self.analyze_setup_py_insecurely:
445+
yield from get_reqs_insecurely(
460446
setup_py_location=setup_py_location,
461-
setup_cfg_location=setup_cfg_location,
462447
)
463-
)
464-
if requirements:
465-
yield from requirements
466448
else:
467-
# Look in requirements file if and only if thy are refered in setup.py or setup.cfg
468-
# And no deps have been yielded by requirements file
469-
470-
yield from get_requirements_from_python_manifest(
471-
sdist_location=sdist_location,
472-
setup_py_location=setup_py_location,
473-
files=[setup_cfg_location, setup_py_location],
474-
analyze_setup_py_insecurely=self.analyze_setup_py_insecurely,
449+
requirements = list(
450+
get_setup_requirements(
451+
sdist_location=sdist_location,
452+
setup_py_location=setup_py_location,
453+
setup_cfg_location=setup_cfg_location,
454+
)
475455
)
456+
if requirements:
457+
yield from requirements
458+
else:
459+
# Look in requirements file if and only if thy are refered in setup.py or setup.cfg
460+
# And no deps have been yielded by requirements file
461+
462+
yield from get_requirements_from_python_manifest(
463+
sdist_location=sdist_location,
464+
setup_py_location=setup_py_location,
465+
files=[setup_cfg_location, setup_py_location],
466+
analyze_setup_py_insecurely=self.analyze_setup_py_insecurely,
467+
)
476468

477469
def get_requirements_for_package_from_pypi_json_api(
478470
self, purl: PackageURL

tests/data/azure-devops.req-310-expected.json

Lines changed: 40 additions & 38 deletions
Large diffs are not rendered by default.

tests/data/azure-devops.req-38-expected.json

Lines changed: 40 additions & 38 deletions
Large diffs are not rendered by default.

tests/data/partial-setup.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from setuptools import setup
2+
3+
semver_version = "2.13.0"
4+
5+
setup(
6+
name="example",
7+
version="0.0.1",
8+
install_requires=[
9+
f"semver @ git+https://github.com/python-semver/python-semver.git@{semver_version}",
10+
],
11+
extras_require={"test": ["botocore==1.27.76"]},
12+
)

tests/data/pinned-pdt-requirements.txt-expected.json

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2831,12 +2831,12 @@
28312831
"type": "pypi",
28322832
"namespace": null,
28332833
"name": "openpyxl",
2834-
"version": "3.1.0",
2834+
"version": "3.1.1",
28352835
"qualifiers": {},
28362836
"subpath": null,
28372837
"primary_language": "Python",
28382838
"description": "A Python library to read/write Excel 2010 xlsx/xlsm files\n.. image:: https://coveralls.io/repos/bitbucket/openpyxl/openpyxl/badge.svg?branch=default\n :target: https://coveralls.io/bitbucket/openpyxl/openpyxl?branch=default\n :alt: coverage status\n\nIntroduction\n------------\n\nopenpyxl is a Python library to read/write Excel 2010 xlsx/xlsm/xltx/xltm files.\n\nIt was born from lack of existing library to read/write natively from Python\nthe Office Open XML format.\n\nAll kudos to the PHPExcel team as openpyxl was initially based on PHPExcel.\n\n\nSecurity\n--------\n\nBy default openpyxl does not guard against quadratic blowup or billion laughs\nxml attacks. To guard against these attacks install defusedxml.\n\nMailing List\n------------\n\nThe user list can be found on http://groups.google.com/group/openpyxl-users\n\n\nSample code::\n\n from openpyxl import Workbook\n wb = Workbook()\n\n # grab the active worksheet\n ws = wb.active\n\n # Data can be assigned directly to cells\n ws['A1'] = 42\n\n # Rows can also be appended\n ws.append([1, 2, 3])\n\n # Python types will automatically be converted\n import datetime\n ws['A2'] = datetime.datetime.now()\n\n # Save the file\n wb.save(\"sample.xlsx\")\n\n\nDocumentation\n-------------\n\nThe documentation is at: https://openpyxl.readthedocs.io\n\n* installation methods\n* code examples\n* instructions for contributing\n\nRelease notes: https://openpyxl.readthedocs.io/en/stable/changes.html",
2839-
"release_date": "2023-01-31T14:40:28",
2839+
"release_date": "2023-02-13T16:51:26",
28402840
"parties": [
28412841
{
28422842
"type": "person",
@@ -2860,11 +2860,11 @@
28602860
"Programming Language :: Python :: 3.9"
28612861
],
28622862
"homepage_url": "https://openpyxl.readthedocs.io",
2863-
"download_url": "https://files.pythonhosted.org/packages/0d/89/f78a9a895e221ec8b13ae7f9495f340a0fb43563b13e2891b5df134f20ea/openpyxl-3.1.0-py2.py3-none-any.whl",
2864-
"size": 250043,
2863+
"download_url": "https://files.pythonhosted.org/packages/9e/57/1d3c2ce7f6f783be9b21569fc468a9f3660e35cc17017abfbbc26d3bd061/openpyxl-3.1.1-py2.py3-none-any.whl",
2864+
"size": 249839,
28652865
"sha1": null,
2866-
"md5": "66351b61736b19d3c88cd108908447d1",
2867-
"sha256": "24d7d361025d186ba91eff58135d50855cf035a84371b891e58fb6eb5125660f",
2866+
"md5": "864e1e1ea061fe056ade64f4e7bbaf22",
2867+
"sha256": "a0266e033e65f33ee697254b66116a5793c15fc92daf64711080000df4cfe0a8",
28682868
"sha512": null,
28692869
"bug_tracking_url": "https://foss.heptapod.net/openpyxl/openpyxl/-/issues",
28702870
"code_view_url": "https://foss.heptapod.net/openpyxl/openpyxl",
@@ -2884,20 +2884,20 @@
28842884
"dependencies": [],
28852885
"repository_homepage_url": null,
28862886
"repository_download_url": null,
2887-
"api_data_url": "https://pypi.org/pypi/openpyxl/3.1.0/json",
2887+
"api_data_url": "https://pypi.org/pypi/openpyxl/3.1.1/json",
28882888
"datasource_id": null,
2889-
"purl": "pkg:pypi/openpyxl@3.1.0"
2889+
"purl": "pkg:pypi/openpyxl@3.1.1"
28902890
},
28912891
{
28922892
"type": "pypi",
28932893
"namespace": null,
28942894
"name": "openpyxl",
2895-
"version": "3.1.0",
2895+
"version": "3.1.1",
28962896
"qualifiers": {},
28972897
"subpath": null,
28982898
"primary_language": "Python",
28992899
"description": "A Python library to read/write Excel 2010 xlsx/xlsm files\n.. image:: https://coveralls.io/repos/bitbucket/openpyxl/openpyxl/badge.svg?branch=default\n :target: https://coveralls.io/bitbucket/openpyxl/openpyxl?branch=default\n :alt: coverage status\n\nIntroduction\n------------\n\nopenpyxl is a Python library to read/write Excel 2010 xlsx/xlsm/xltx/xltm files.\n\nIt was born from lack of existing library to read/write natively from Python\nthe Office Open XML format.\n\nAll kudos to the PHPExcel team as openpyxl was initially based on PHPExcel.\n\n\nSecurity\n--------\n\nBy default openpyxl does not guard against quadratic blowup or billion laughs\nxml attacks. To guard against these attacks install defusedxml.\n\nMailing List\n------------\n\nThe user list can be found on http://groups.google.com/group/openpyxl-users\n\n\nSample code::\n\n from openpyxl import Workbook\n wb = Workbook()\n\n # grab the active worksheet\n ws = wb.active\n\n # Data can be assigned directly to cells\n ws['A1'] = 42\n\n # Rows can also be appended\n ws.append([1, 2, 3])\n\n # Python types will automatically be converted\n import datetime\n ws['A2'] = datetime.datetime.now()\n\n # Save the file\n wb.save(\"sample.xlsx\")\n\n\nDocumentation\n-------------\n\nThe documentation is at: https://openpyxl.readthedocs.io\n\n* installation methods\n* code examples\n* instructions for contributing\n\nRelease notes: https://openpyxl.readthedocs.io/en/stable/changes.html",
2900-
"release_date": "2023-01-31T14:40:31",
2900+
"release_date": "2023-02-13T16:51:28",
29012901
"parties": [
29022902
{
29032903
"type": "person",
@@ -2921,11 +2921,11 @@
29212921
"Programming Language :: Python :: 3.9"
29222922
],
29232923
"homepage_url": "https://openpyxl.readthedocs.io",
2924-
"download_url": "https://files.pythonhosted.org/packages/3d/73/bb87810cdde809f69fef11d31e77297894e58710d47626dc5e5b3ff8f92a/openpyxl-3.1.0.tar.gz",
2925-
"size": 186306,
2924+
"download_url": "https://files.pythonhosted.org/packages/10/bf/950ea7896f3c42ab04073cd2903f0a190ba77ef28bdf76191f6f86373712/openpyxl-3.1.1.tar.gz",
2925+
"size": 185802,
29262926
"sha1": null,
2927-
"md5": "b7ba597b801b9a102f27599b2fa227b3",
2928-
"sha256": "eccedbe1cdd8b2494057e73959b496821141038dbb7eb9266ea59e3f34208231",
2927+
"md5": "0b1a5d776707ef471810f61c7bf77a2d",
2928+
"sha256": "f06d44e2c973781068bce5ecf860a09bcdb1c7f5ce1facd5e9aa82c92c93ae72",
29292929
"sha512": null,
29302930
"bug_tracking_url": "https://foss.heptapod.net/openpyxl/openpyxl/-/issues",
29312931
"code_view_url": "https://foss.heptapod.net/openpyxl/openpyxl",
@@ -2945,9 +2945,9 @@
29452945
"dependencies": [],
29462946
"repository_homepage_url": null,
29472947
"repository_download_url": null,
2948-
"api_data_url": "https://pypi.org/pypi/openpyxl/3.1.0/json",
2948+
"api_data_url": "https://pypi.org/pypi/openpyxl/3.1.1/json",
29492949
"datasource_id": null,
2950-
"purl": "pkg:pypi/openpyxl@3.1.0"
2950+
"purl": "pkg:pypi/openpyxl@3.1.1"
29512951
},
29522952
{
29532953
"type": "pypi",
@@ -5025,7 +5025,7 @@
50255025
{
50265026
"key": "openpyxl",
50275027
"package_name": "openpyxl",
5028-
"installed_version": "3.1.0",
5028+
"installed_version": "3.1.1",
50295029
"dependencies": [
50305030
{
50315031
"key": "et-xmlfile",

tests/data/pinned-requirements.txt-expected.json

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2831,12 +2831,12 @@
28312831
"type": "pypi",
28322832
"namespace": null,
28332833
"name": "openpyxl",
2834-
"version": "3.1.0",
2834+
"version": "3.1.1",
28352835
"qualifiers": {},
28362836
"subpath": null,
28372837
"primary_language": "Python",
28382838
"description": "A Python library to read/write Excel 2010 xlsx/xlsm files\n.. image:: https://coveralls.io/repos/bitbucket/openpyxl/openpyxl/badge.svg?branch=default\n :target: https://coveralls.io/bitbucket/openpyxl/openpyxl?branch=default\n :alt: coverage status\n\nIntroduction\n------------\n\nopenpyxl is a Python library to read/write Excel 2010 xlsx/xlsm/xltx/xltm files.\n\nIt was born from lack of existing library to read/write natively from Python\nthe Office Open XML format.\n\nAll kudos to the PHPExcel team as openpyxl was initially based on PHPExcel.\n\n\nSecurity\n--------\n\nBy default openpyxl does not guard against quadratic blowup or billion laughs\nxml attacks. To guard against these attacks install defusedxml.\n\nMailing List\n------------\n\nThe user list can be found on http://groups.google.com/group/openpyxl-users\n\n\nSample code::\n\n from openpyxl import Workbook\n wb = Workbook()\n\n # grab the active worksheet\n ws = wb.active\n\n # Data can be assigned directly to cells\n ws['A1'] = 42\n\n # Rows can also be appended\n ws.append([1, 2, 3])\n\n # Python types will automatically be converted\n import datetime\n ws['A2'] = datetime.datetime.now()\n\n # Save the file\n wb.save(\"sample.xlsx\")\n\n\nDocumentation\n-------------\n\nThe documentation is at: https://openpyxl.readthedocs.io\n\n* installation methods\n* code examples\n* instructions for contributing\n\nRelease notes: https://openpyxl.readthedocs.io/en/stable/changes.html",
2839-
"release_date": "2023-01-31T14:40:28",
2839+
"release_date": "2023-02-13T16:51:26",
28402840
"parties": [
28412841
{
28422842
"type": "person",
@@ -2860,11 +2860,11 @@
28602860
"Programming Language :: Python :: 3.9"
28612861
],
28622862
"homepage_url": "https://openpyxl.readthedocs.io",
2863-
"download_url": "https://files.pythonhosted.org/packages/0d/89/f78a9a895e221ec8b13ae7f9495f340a0fb43563b13e2891b5df134f20ea/openpyxl-3.1.0-py2.py3-none-any.whl",
2864-
"size": 250043,
2863+
"download_url": "https://files.pythonhosted.org/packages/9e/57/1d3c2ce7f6f783be9b21569fc468a9f3660e35cc17017abfbbc26d3bd061/openpyxl-3.1.1-py2.py3-none-any.whl",
2864+
"size": 249839,
28652865
"sha1": null,
2866-
"md5": "66351b61736b19d3c88cd108908447d1",
2867-
"sha256": "24d7d361025d186ba91eff58135d50855cf035a84371b891e58fb6eb5125660f",
2866+
"md5": "864e1e1ea061fe056ade64f4e7bbaf22",
2867+
"sha256": "a0266e033e65f33ee697254b66116a5793c15fc92daf64711080000df4cfe0a8",
28682868
"sha512": null,
28692869
"bug_tracking_url": "https://foss.heptapod.net/openpyxl/openpyxl/-/issues",
28702870
"code_view_url": "https://foss.heptapod.net/openpyxl/openpyxl",
@@ -2884,20 +2884,20 @@
28842884
"dependencies": [],
28852885
"repository_homepage_url": null,
28862886
"repository_download_url": null,
2887-
"api_data_url": "https://pypi.org/pypi/openpyxl/3.1.0/json",
2887+
"api_data_url": "https://pypi.org/pypi/openpyxl/3.1.1/json",
28882888
"datasource_id": null,
2889-
"purl": "pkg:pypi/openpyxl@3.1.0"
2889+
"purl": "pkg:pypi/openpyxl@3.1.1"
28902890
},
28912891
{
28922892
"type": "pypi",
28932893
"namespace": null,
28942894
"name": "openpyxl",
2895-
"version": "3.1.0",
2895+
"version": "3.1.1",
28962896
"qualifiers": {},
28972897
"subpath": null,
28982898
"primary_language": "Python",
28992899
"description": "A Python library to read/write Excel 2010 xlsx/xlsm files\n.. image:: https://coveralls.io/repos/bitbucket/openpyxl/openpyxl/badge.svg?branch=default\n :target: https://coveralls.io/bitbucket/openpyxl/openpyxl?branch=default\n :alt: coverage status\n\nIntroduction\n------------\n\nopenpyxl is a Python library to read/write Excel 2010 xlsx/xlsm/xltx/xltm files.\n\nIt was born from lack of existing library to read/write natively from Python\nthe Office Open XML format.\n\nAll kudos to the PHPExcel team as openpyxl was initially based on PHPExcel.\n\n\nSecurity\n--------\n\nBy default openpyxl does not guard against quadratic blowup or billion laughs\nxml attacks. To guard against these attacks install defusedxml.\n\nMailing List\n------------\n\nThe user list can be found on http://groups.google.com/group/openpyxl-users\n\n\nSample code::\n\n from openpyxl import Workbook\n wb = Workbook()\n\n # grab the active worksheet\n ws = wb.active\n\n # Data can be assigned directly to cells\n ws['A1'] = 42\n\n # Rows can also be appended\n ws.append([1, 2, 3])\n\n # Python types will automatically be converted\n import datetime\n ws['A2'] = datetime.datetime.now()\n\n # Save the file\n wb.save(\"sample.xlsx\")\n\n\nDocumentation\n-------------\n\nThe documentation is at: https://openpyxl.readthedocs.io\n\n* installation methods\n* code examples\n* instructions for contributing\n\nRelease notes: https://openpyxl.readthedocs.io/en/stable/changes.html",
2900-
"release_date": "2023-01-31T14:40:31",
2900+
"release_date": "2023-02-13T16:51:28",
29012901
"parties": [
29022902
{
29032903
"type": "person",
@@ -2921,11 +2921,11 @@
29212921
"Programming Language :: Python :: 3.9"
29222922
],
29232923
"homepage_url": "https://openpyxl.readthedocs.io",
2924-
"download_url": "https://files.pythonhosted.org/packages/3d/73/bb87810cdde809f69fef11d31e77297894e58710d47626dc5e5b3ff8f92a/openpyxl-3.1.0.tar.gz",
2925-
"size": 186306,
2924+
"download_url": "https://files.pythonhosted.org/packages/10/bf/950ea7896f3c42ab04073cd2903f0a190ba77ef28bdf76191f6f86373712/openpyxl-3.1.1.tar.gz",
2925+
"size": 185802,
29262926
"sha1": null,
2927-
"md5": "b7ba597b801b9a102f27599b2fa227b3",
2928-
"sha256": "eccedbe1cdd8b2494057e73959b496821141038dbb7eb9266ea59e3f34208231",
2927+
"md5": "0b1a5d776707ef471810f61c7bf77a2d",
2928+
"sha256": "f06d44e2c973781068bce5ecf860a09bcdb1c7f5ce1facd5e9aa82c92c93ae72",
29292929
"sha512": null,
29302930
"bug_tracking_url": "https://foss.heptapod.net/openpyxl/openpyxl/-/issues",
29312931
"code_view_url": "https://foss.heptapod.net/openpyxl/openpyxl",
@@ -2945,9 +2945,9 @@
29452945
"dependencies": [],
29462946
"repository_homepage_url": null,
29472947
"repository_download_url": null,
2948-
"api_data_url": "https://pypi.org/pypi/openpyxl/3.1.0/json",
2948+
"api_data_url": "https://pypi.org/pypi/openpyxl/3.1.1/json",
29492949
"datasource_id": null,
2950-
"purl": "pkg:pypi/openpyxl@3.1.0"
2950+
"purl": "pkg:pypi/openpyxl@3.1.1"
29512951
},
29522952
{
29532953
"type": "pypi",
@@ -4976,7 +4976,7 @@
49764976
"pkg:pypi/click@8.0.4",
49774977
"pkg:pypi/jinja2@3.1.2",
49784978
"pkg:pypi/license-expression@30.1.0",
4979-
"pkg:pypi/openpyxl@3.1.0",
4979+
"pkg:pypi/openpyxl@3.1.1",
49804980
"pkg:pypi/packageurl-python@0.9.9",
49814981
"pkg:pypi/saneyaml@0.5.2"
49824982
]
@@ -5066,7 +5066,7 @@
50665066
"dependencies": []
50675067
},
50685068
{
5069-
"package": "pkg:pypi/openpyxl@3.1.0",
5069+
"package": "pkg:pypi/openpyxl@3.1.1",
50705070
"dependencies": [
50715071
"pkg:pypi/et-xmlfile@1.1.0"
50725072
]

0 commit comments

Comments
 (0)