Skip to content

Commit e7baa00

Browse files
authored
Merge pull request #201 from ukaj/fix/unsupported_url_scheme
fix: Incorrect parsing of index_urls in requirements.txt
2 parents c20cbf6 + 7663034 commit e7baa00

11 files changed

+304
-266
lines changed

src/python_inspector/api.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,7 @@ def resolve_dependencies(
155155
for req_file in requirement_files:
156156
deps = dependencies.get_dependencies_from_requirements(requirements_file=req_file)
157157
for extra_data in dependencies.get_extra_data_from_requirements(requirements_file=req_file):
158-
index_urls = (*index_urls, *tuple(extra_data.get("extra_index_urls") or []))
159-
index_urls = (*index_urls, *tuple(extra_data.get("index_url") or []))
158+
index_urls = get_index_urls(index_urls, extra_data)
160159
direct_dependencies.extend(deps)
161160
package_data = [
162161
pkg_data.to_dict() for pkg_data in PipRequirementsFileHandler.parse(location=req_file)
@@ -320,6 +319,25 @@ async def get_pypi_data(package):
320319
)
321320

322321

322+
def get_index_urls(index_urls: Tuple, extra_data: Dict) -> Tuple:
323+
"""
324+
Return a list of index URLs from the extra_data.
325+
The extra_data is a dictionary that may contain
326+
"extra_index_urls" and "index_url" keys.
327+
"""
328+
if isinstance(index_urls, str):
329+
index_urls = [index_urls]
330+
if isinstance(index_urls, tuple):
331+
index_urls = list(index_urls)
332+
extra_index_urls = extra_data.get("extra_index_urls") or []
333+
index_url = extra_data.get("index_url") or []
334+
if isinstance(extra_index_urls, list):
335+
index_urls = (*index_urls, *tuple(extra_index_urls))
336+
if isinstance(index_url, str):
337+
index_urls = (*index_urls, *tuple([index_url]))
338+
return tuple(set(index_urls))
339+
340+
323341
resolver_api = resolve_dependencies
324342

325343

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

Lines changed: 56 additions & 59 deletions
Large diffs are not rendered by default.

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

Lines changed: 56 additions & 59 deletions
Large diffs are not rendered by default.

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

Lines changed: 56 additions & 59 deletions
Large diffs are not rendered by default.

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

Lines changed: 44 additions & 43 deletions
Large diffs are not rendered by default.

tests/data/example-requirements-ignore-errors-expected.json

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -224,12 +224,12 @@
224224
"type": "pypi",
225225
"namespace": null,
226226
"name": "packaging",
227-
"version": "24.2",
227+
"version": "25.0",
228228
"qualifiers": {},
229229
"subpath": null,
230230
"primary_language": "Python",
231231
"description": "Core utilities for Python packages\npackaging\n=========\n\n.. start-intro\n\nReusable core utilities for various Python Packaging\n`interoperability specifications <https://packaging.python.org/specifications/>`_.\n\nThis library provides utilities that implement the interoperability\nspecifications which have clearly one correct behaviour (eg: :pep:`440`)\nor benefit greatly from having a single shared implementation (eg: :pep:`425`).\n\n.. end-intro\n\nThe ``packaging`` project includes the following: version handling, specifiers,\nmarkers, requirements, tags, utilities.\n\nDocumentation\n-------------\n\nThe `documentation`_ provides information and the API for the following:\n\n- Version Handling\n- Specifiers\n- Markers\n- Requirements\n- Tags\n- Utilities\n\nInstallation\n------------\n\nUse ``pip`` to install these utilities::\n\n pip install packaging\n\nThe ``packaging`` library uses calendar-based versioning (``YY.N``).\n\nDiscussion\n----------\n\nIf you run into bugs, you can file them in our `issue tracker`_.\n\nYou can also join ``#pypa`` on Freenode to ask questions or get involved.\n\n\n.. _`documentation`: https://packaging.pypa.io/\n.. _`issue tracker`: https://github.com/pypa/packaging/issues\n\n\nCode of Conduct\n---------------\n\nEveryone interacting in the packaging project's codebases, issue trackers, chat\nrooms, and mailing lists is expected to follow the `PSF Code of Conduct`_.\n\n.. _PSF Code of Conduct: https://github.com/pypa/.github/blob/main/CODE_OF_CONDUCT.md\n\nContributing\n------------\n\nThe ``CONTRIBUTING.rst`` file outlines how to contribute to this project as\nwell as how to report a potential security issue. The documentation for this\nproject also covers information about `project development`_ and `security`_.\n\n.. _`project development`: https://packaging.pypa.io/en/latest/development/\n.. _`security`: https://packaging.pypa.io/en/latest/security/\n\nProject History\n---------------\n\nPlease review the ``CHANGELOG.rst`` file or the `Changelog documentation`_ for\nrecent changes and project history.\n\n.. _`Changelog documentation`: https://packaging.pypa.io/en/latest/changelog/",
232-
"release_date": "2024-11-08T09:47:44",
232+
"release_date": "2025-04-19T11:48:57",
233233
"parties": [
234234
{
235235
"type": "person",
@@ -256,11 +256,11 @@
256256
"Typing :: Typed"
257257
],
258258
"homepage_url": null,
259-
"download_url": "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl",
260-
"size": 65451,
259+
"download_url": "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl",
260+
"size": 66469,
261261
"sha1": null,
262-
"md5": "137b07612433f1ad2cd27dd8ab38ce49",
263-
"sha256": "09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759",
262+
"md5": "5fa4842e2eb0d7883b4b0e7c42d6229e",
263+
"sha256": "29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484",
264264
"sha512": null,
265265
"bug_tracking_url": null,
266266
"code_view_url": "https://github.com/pypa/packaging",
@@ -280,9 +280,9 @@
280280
"dependencies": [],
281281
"repository_homepage_url": null,
282282
"repository_download_url": null,
283-
"api_data_url": "https://pypi.org/pypi/packaging/24.2/json",
283+
"api_data_url": "https://pypi.org/pypi/packaging/25.0/json",
284284
"datasource_id": null,
285-
"purl": "pkg:pypi/packaging@24.2"
285+
"purl": "pkg:pypi/packaging@25.0"
286286
},
287287
{
288288
"type": "pypi",
@@ -491,7 +491,7 @@
491491
"dependencies": []
492492
},
493493
{
494-
"package": "pkg:pypi/packaging@24.2",
494+
"package": "pkg:pypi/packaging@25.0",
495495
"dependencies": []
496496
},
497497
{
@@ -503,7 +503,7 @@
503503
"dependencies": [
504504
"pkg:pypi/[email protected]",
505505
"pkg:pypi/[email protected]",
506-
"pkg:pypi/packaging@24.2",
506+
"pkg:pypi/packaging@25.0",
507507
"pkg:pypi/[email protected]",
508508
"pkg:pypi/[email protected]"
509509
]

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

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -879,12 +879,12 @@
879879
"type": "pypi",
880880
"namespace": null,
881881
"name": "boolean-py",
882-
"version": "4.0",
882+
"version": "5.0",
883883
"qualifiers": {},
884884
"subpath": null,
885885
"primary_language": "Python",
886886
"description": "Define boolean algebras, create and parse boolean expressions and create custom boolean DSL.\nThis library helps you deal with boolean expressions and algebra with variables\nand the boolean functions AND, OR, NOT.\n\nYou can parse expressions from strings and simplify and compare expressions.\nYou can also easily create your custom algreba and mini DSL and create custom\ntokenizers to handle custom expressions.\n\nFor extensive documentation look either into the docs directory or view it online, at\nhttps://booleanpy.readthedocs.org/en/latest/\n\nhttps://github.com/bastikr/boolean.py\n\nCopyright (c) 2009-2020 Sebastian Kraemer, [email protected] and others\nSPDX-License-Identifier: BSD-2-Clause",
887-
"release_date": "2022-05-05T08:18:58",
887+
"release_date": "2025-04-03T10:39:48",
888888
"parties": [
889889
{
890890
"type": "person",
@@ -910,11 +910,11 @@
910910
"Topic :: Utilities"
911911
],
912912
"homepage_url": "https://github.com/bastikr/boolean.py",
913-
"download_url": "https://files.pythonhosted.org/packages/3f/02/6389ef0529af6da0b913374dedb9bbde8eabfe45767ceec38cc37801b0bd/boolean.py-4.0-py3-none-any.whl",
914-
"size": 25909,
913+
"download_url": "https://files.pythonhosted.org/packages/e5/ca/78d423b324b8d77900030fa59c4aa9054261ef0925631cd2501dd015b7b7/boolean_py-5.0-py3-none-any.whl",
914+
"size": 26577,
915915
"sha1": null,
916-
"md5": "73208a6fc38d6904a1d7e793e8da1292",
917-
"sha256": "2876f2051d7d6394a531d82dc6eb407faa0b01a0a0b3083817ccd7323b8d96bd",
916+
"md5": "df9060a88bfb6ba3b9314783b16a0faa",
917+
"sha256": "ef28a70bd43115208441b53a045d1549e2f0ec6e3d08a9d142cbc41c1938e8d9",
918918
"sha512": null,
919919
"bug_tracking_url": null,
920920
"code_view_url": null,
@@ -931,9 +931,9 @@
931931
"dependencies": [],
932932
"repository_homepage_url": null,
933933
"repository_download_url": null,
934-
"api_data_url": "https://pypi.org/pypi/boolean-py/4.0/json",
934+
"api_data_url": "https://pypi.org/pypi/boolean-py/5.0/json",
935935
"datasource_id": null,
936-
"purl": "pkg:pypi/boolean-py@4.0"
936+
"purl": "pkg:pypi/boolean-py@5.0"
937937
},
938938
{
939939
"type": "pypi",
@@ -2820,7 +2820,7 @@
28202820
{
28212821
"key": "boolean-py",
28222822
"package_name": "boolean-py",
2823-
"installed_version": "4.0",
2823+
"installed_version": "5.0",
28242824
"dependencies": []
28252825
},
28262826
{
@@ -2856,7 +2856,7 @@
28562856
{
28572857
"key": "boolean-py",
28582858
"package_name": "boolean-py",
2859-
"installed_version": "4.0",
2859+
"installed_version": "5.0",
28602860
"dependencies": []
28612861
}
28622862
]

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

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -879,12 +879,12 @@
879879
"type": "pypi",
880880
"namespace": null,
881881
"name": "boolean-py",
882-
"version": "4.0",
882+
"version": "5.0",
883883
"qualifiers": {},
884884
"subpath": null,
885885
"primary_language": "Python",
886886
"description": "Define boolean algebras, create and parse boolean expressions and create custom boolean DSL.\nThis library helps you deal with boolean expressions and algebra with variables\nand the boolean functions AND, OR, NOT.\n\nYou can parse expressions from strings and simplify and compare expressions.\nYou can also easily create your custom algreba and mini DSL and create custom\ntokenizers to handle custom expressions.\n\nFor extensive documentation look either into the docs directory or view it online, at\nhttps://booleanpy.readthedocs.org/en/latest/\n\nhttps://github.com/bastikr/boolean.py\n\nCopyright (c) 2009-2020 Sebastian Kraemer, [email protected] and others\nSPDX-License-Identifier: BSD-2-Clause",
887-
"release_date": "2022-05-05T08:18:58",
887+
"release_date": "2025-04-03T10:39:48",
888888
"parties": [
889889
{
890890
"type": "person",
@@ -910,11 +910,11 @@
910910
"Topic :: Utilities"
911911
],
912912
"homepage_url": "https://github.com/bastikr/boolean.py",
913-
"download_url": "https://files.pythonhosted.org/packages/3f/02/6389ef0529af6da0b913374dedb9bbde8eabfe45767ceec38cc37801b0bd/boolean.py-4.0-py3-none-any.whl",
914-
"size": 25909,
913+
"download_url": "https://files.pythonhosted.org/packages/e5/ca/78d423b324b8d77900030fa59c4aa9054261ef0925631cd2501dd015b7b7/boolean_py-5.0-py3-none-any.whl",
914+
"size": 26577,
915915
"sha1": null,
916-
"md5": "73208a6fc38d6904a1d7e793e8da1292",
917-
"sha256": "2876f2051d7d6394a531d82dc6eb407faa0b01a0a0b3083817ccd7323b8d96bd",
916+
"md5": "df9060a88bfb6ba3b9314783b16a0faa",
917+
"sha256": "ef28a70bd43115208441b53a045d1549e2f0ec6e3d08a9d142cbc41c1938e8d9",
918918
"sha512": null,
919919
"bug_tracking_url": null,
920920
"code_view_url": null,
@@ -931,9 +931,9 @@
931931
"dependencies": [],
932932
"repository_homepage_url": null,
933933
"repository_download_url": null,
934-
"api_data_url": "https://pypi.org/pypi/boolean-py/4.0/json",
934+
"api_data_url": "https://pypi.org/pypi/boolean-py/5.0/json",
935935
"datasource_id": null,
936-
"purl": "pkg:pypi/boolean-py@4.0"
936+
"purl": "pkg:pypi/boolean-py@5.0"
937937
},
938938
{
939939
"type": "pypi",
@@ -2810,7 +2810,7 @@
28102810
"package": "pkg:pypi/[email protected]",
28112811
"dependencies": [
28122812
"pkg:pypi/[email protected]",
2813-
"pkg:pypi/boolean-py@4.0",
2813+
"pkg:pypi/boolean-py@5.0",
28142814
"pkg:pypi/[email protected]",
28152815
"pkg:pypi/[email protected]",
28162816
"pkg:pypi/[email protected]",
@@ -2831,7 +2831,7 @@
28312831
]
28322832
},
28332833
{
2834-
"package": "pkg:pypi/boolean-py@4.0",
2834+
"package": "pkg:pypi/boolean-py@5.0",
28352835
"dependencies": []
28362836
},
28372837
{
@@ -2897,7 +2897,7 @@
28972897
{
28982898
"package": "pkg:pypi/[email protected]",
28992899
"dependencies": [
2900-
"pkg:pypi/boolean-py@4.0"
2900+
"pkg:pypi/boolean-py@5.0"
29012901
]
29022902
},
29032903
{

tests/data/test-api-with-requirement-file.json

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3727,12 +3727,12 @@
37273727
"type": "pypi",
37283728
"namespace": null,
37293729
"name": "pip",
3730-
"version": "25.0.1",
3730+
"version": "25.1",
37313731
"qualifiers": {},
37323732
"subpath": null,
37333733
"primary_language": "Python",
37343734
"description": "The PyPA recommended tool for installing Python packages.\npip - The Python Package Installer\n==================================\n\n.. |pypi-version| image:: https://img.shields.io/pypi/v/pip.svg\n :target: https://pypi.org/project/pip/\n :alt: PyPI\n\n.. |python-versions| image:: https://img.shields.io/pypi/pyversions/pip\n :target: https://pypi.org/project/pip\n :alt: PyPI - Python Version\n\n.. |docs-badge| image:: https://readthedocs.org/projects/pip/badge/?version=latest\n :target: https://pip.pypa.io/en/latest\n :alt: Documentation\n\n|pypi-version| |python-versions| |docs-badge|\n\npip is the `package installer`_ for Python. You can use pip to install packages from the `Python Package Index`_ and other indexes.\n\nPlease take a look at our documentation for how to install and use pip:\n\n* `Installation`_\n* `Usage`_\n\nWe release updates regularly, with a new version every 3 months. Find more details in our documentation:\n\n* `Release notes`_\n* `Release process`_\n\nIf you find bugs, need help, or want to talk to the developers, please use our mailing lists or chat rooms:\n\n* `Issue tracking`_\n* `Discourse channel`_\n* `User IRC`_\n\nIf you want to get involved head over to GitHub to get the source code, look at our development documentation and feel free to jump on the developer mailing lists and chat rooms:\n\n* `GitHub page`_\n* `Development documentation`_\n* `Development IRC`_\n\nCode of Conduct\n---------------\n\nEveryone interacting in the pip project's codebases, issue trackers, chat\nrooms, and mailing lists is expected to follow the `PSF Code of Conduct`_.\n\n.. _package installer: https://packaging.python.org/guides/tool-recommendations/\n.. _Python Package Index: https://pypi.org\n.. _Installation: https://pip.pypa.io/en/stable/installation/\n.. _Usage: https://pip.pypa.io/en/stable/\n.. _Release notes: https://pip.pypa.io/en/stable/news.html\n.. _Release process: https://pip.pypa.io/en/latest/development/release-process/\n.. _GitHub page: https://github.com/pypa/pip\n.. _Development documentation: https://pip.pypa.io/en/latest/development\n.. _Issue tracking: https://github.com/pypa/pip/issues\n.. _Discourse channel: https://discuss.python.org/c/packaging\n.. _User IRC: https://kiwiirc.com/nextclient/#ircs://irc.libera.chat:+6697/pypa\n.. _Development IRC: https://kiwiirc.com/nextclient/#ircs://irc.libera.chat:+6697/pypa-dev\n.. _PSF Code of Conduct: https://github.com/pypa/.github/blob/main/CODE_OF_CONDUCT.md",
3735-
"release_date": "2025-02-09T17:14:01",
3735+
"release_date": "2025-04-26T09:45:33",
37363736
"parties": [
37373737
{
37383738
"type": "person",
@@ -3752,18 +3752,17 @@
37523752
"Programming Language :: Python :: 3.11",
37533753
"Programming Language :: Python :: 3.12",
37543754
"Programming Language :: Python :: 3.13",
3755-
"Programming Language :: Python :: 3.8",
37563755
"Programming Language :: Python :: 3.9",
37573756
"Programming Language :: Python :: Implementation :: CPython",
37583757
"Programming Language :: Python :: Implementation :: PyPy",
37593758
"Topic :: Software Development :: Build Tools"
37603759
],
37613760
"homepage_url": null,
3762-
"download_url": "https://files.pythonhosted.org/packages/c9/bc/b7db44f5f39f9d0494071bddae6880eb645970366d0a200022a1a93d57f5/pip-25.0.1-py3-none-any.whl",
3763-
"size": 1841526,
3761+
"download_url": "https://files.pythonhosted.org/packages/e0/f0/8a2806114cd36e282823fd4d8e88e3b94dc943c2569c350d0c826a49db38/pip-25.1-py3-none-any.whl",
3762+
"size": 1824948,
37643763
"sha1": null,
3765-
"md5": "99f43f22d5321305507b804a2be662c0",
3766-
"sha256": "c46efd13b6aa8279f33f2864459c8ce587ea6a1a59ee20de055868d8f7688f7f",
3764+
"md5": "4eb2baef792e6841cfcd4c24c808421a",
3765+
"sha256": "13b4aa0aaad055020a11bec8a1c2a70a2b2d080e12d89b962266029fff0a16ba",
37673766
"sha512": null,
37683767
"bug_tracking_url": null,
37693768
"code_view_url": "https://github.com/pypa/pip",
@@ -3783,9 +3782,9 @@
37833782
"dependencies": [],
37843783
"repository_homepage_url": null,
37853784
"repository_download_url": null,
3786-
"api_data_url": "https://pypi.org/pypi/pip/25.0.1/json",
3785+
"api_data_url": "https://pypi.org/pypi/pip/25.1/json",
37873786
"datasource_id": null,
3788-
"purl": "pkg:pypi/pip@25.0.1"
3787+
"purl": "pkg:pypi/[email protected]"
37893788
},
37903789
{
37913790
"type": "pypi",
@@ -6163,13 +6162,13 @@
61636162
]
61646163
},
61656164
{
6166-
"package": "pkg:pypi/pip@25.0.1",
6165+
"package": "pkg:pypi/[email protected]",
61676166
"dependencies": []
61686167
},
61696168
{
61706169
"package": "pkg:pypi/[email protected]",
61716170
"dependencies": [
6172-
"pkg:pypi/pip@25.0.1"
6171+
"pkg:pypi/[email protected]"
61736172
]
61746173
},
61756174
{

tests/test_api.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from commoncode.testcase import FileDrivenTesting
1616
from test_cli import check_data_results
1717

18+
from python_inspector.api import get_index_urls
1819
from python_inspector.api import resolver_api
1920

2021
test_env = FileDrivenTesting()
@@ -128,3 +129,31 @@ def test_api_with_partial_setup_py():
128129
analyze_setup_py_insecurely=True,
129130
)
130131
check_data_results(results=results.to_dict(generic_paths=True), expected_file=expected_file)
132+
133+
134+
def test_get_index_urls():
135+
136+
# pass as a tuple
137+
index_urls = get_index_urls(
138+
index_urls=("https://pypi.org/simple",),
139+
extra_data={"extra_index_urls": ["https://pypi.org/simple", "https://example.com/simple"]},
140+
)
141+
142+
expected = ["https://example.com/simple", "https://pypi.org/simple"]
143+
144+
assert sorted(list(index_urls)) == expected
145+
146+
# pass as a string
147+
index_urls = get_index_urls(
148+
index_urls=("https://pypi.org/simple"),
149+
extra_data={"extra_index_urls": ["https://pypi.org/simple", "https://example.com/simple"]},
150+
)
151+
152+
assert sorted(list(index_urls)) == expected
153+
154+
index_urls = get_index_urls(
155+
index_urls=("https://pypi.org/simple",),
156+
extra_data={"index_url": "https://pypi.org/simple"},
157+
)
158+
159+
assert index_urls == ("https://pypi.org/simple",)

tests/test_resolution.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ def test_get_resolved_dependencies_with_tilde_requirement_using_json_api():
123123
assert plist == [
124124
"pkg:pypi/[email protected]",
125125
"pkg:pypi/[email protected]",
126-
"pkg:pypi/importlib-metadata@8.6.1",
126+
"pkg:pypi/importlib-metadata@8.7.0",
127127
"pkg:pypi/[email protected]",
128128
"pkg:pypi/[email protected]",
129129
"pkg:pypi/[email protected]",
@@ -155,7 +155,7 @@ def test_get_resolved_dependencies_for_version_containing_local_version_identifi
155155
"pkg:pypi/[email protected]",
156156
"pkg:pypi/[email protected]",
157157
"pkg:pypi/[email protected]",
158-
"pkg:pypi/[email protected].1",
158+
"pkg:pypi/[email protected].3",
159159
"pkg:pypi/[email protected]%2Bcpu",
160160
"pkg:pypi/[email protected]",
161161
]

0 commit comments

Comments
 (0)