Skip to content

Commit 07f8981

Browse files
authored
fix --index-url handling for Poetry 1.8 - second try (#270)
- if PyPI is disabled the highest prio source get `--index-url`, others get `--extra-index-url` - if PyPI is enabled we just do not use `--index-url`, all other source get `--extra-index-url` - put `--index-url` before `--extra-index-url` to work around a pip bug
1 parent bce7f70 commit 07f8981

File tree

2 files changed

+138
-19
lines changed

2 files changed

+138
-19
lines changed

src/poetry_plugin_export/exporter.py

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ def _export_generic_txt(
143143
and not is_direct_local_reference
144144
and package.source_url
145145
):
146-
indexes.add(package.source_url)
146+
indexes.add(package.source_url.rstrip("/"))
147147

148148
if package.files and self._with_hashes:
149149
hashes = []
@@ -171,22 +171,16 @@ def _export_generic_txt(
171171
if indexes and self._with_urls:
172172
# If we have extra indexes, we add them to the beginning of the output
173173
indexes_header = ""
174-
for index in sorted(indexes):
175-
repositories = [
176-
r
177-
for r in self._poetry.pool.all_repositories
178-
if isinstance(r, HTTPRepository) and r.url == index.rstrip("/")
179-
]
180-
if not repositories:
181-
continue
182-
repository = repositories[0]
183-
if repository is self._poetry.pool.repositories[0]:
184-
url = (
185-
repository.authenticated_url
186-
if self._with_credentials
187-
else repository.url
188-
)
189-
indexes_header += f"--index-url {url}\n"
174+
has_pypi_repository = any(
175+
r.name.lower() == "pypi" for r in self._poetry.pool.all_repositories
176+
)
177+
# Iterate over repositories so that we get the repository with the highest
178+
# priority first so that --index-url comes before --extra-index-url
179+
for repository in self._poetry.pool.all_repositories:
180+
if (
181+
not isinstance(repository, HTTPRepository)
182+
or repository.url not in indexes
183+
):
190184
continue
191185

192186
url = (
@@ -197,7 +191,13 @@ def _export_generic_txt(
197191
parsed_url = urllib.parse.urlsplit(url)
198192
if parsed_url.scheme == "http":
199193
indexes_header += f"--trusted-host {parsed_url.netloc}\n"
200-
indexes_header += f"--extra-index-url {url}\n"
194+
if (
195+
not has_pypi_repository
196+
and repository is self._poetry.pool.repositories[0]
197+
):
198+
indexes_header += f"--index-url {url}\n"
199+
else:
200+
indexes_header += f"--extra-index-url {url}\n"
201201

202202
content = indexes_header + "\n" + content
203203

tests/test_exporter.py

Lines changed: 120 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1878,8 +1878,8 @@ def test_exporter_exports_requirements_txt_with_two_primary_sources(
18781878
content = f.read()
18791879

18801880
expected = f"""\
1881-
--extra-index-url https://foo:[email protected]/simple
18821881
--index-url https://baz:[email protected]/simple
1882+
--extra-index-url https://foo:[email protected]/simple
18831883
18841884
bar==4.5.6 ; {MARKER_PY} \\
18851885
--hash=sha256:67890
@@ -2795,3 +2795,122 @@ def test_exporter_not_confused_by_extras_in_sub_dependencies(
27952795
typer[all]==0.9.0 ; python_version >= "3.11" and python_version < "4.0"
27962796
"""
27972797
assert io.fetch_output() == expected
2798+
2799+
2800+
@pytest.mark.parametrize(
2801+
("priorities", "expected"),
2802+
[
2803+
([("custom-a", Priority.PRIMARY), ("custom-b", Priority.PRIMARY)], ("a", "b")),
2804+
([("custom-b", Priority.PRIMARY), ("custom-a", Priority.PRIMARY)], ("b", "a")),
2805+
(
2806+
[("custom-b", Priority.SUPPLEMENTAL), ("custom-a", Priority.PRIMARY)],
2807+
("a", "b"),
2808+
),
2809+
([("custom-b", Priority.EXPLICIT), ("custom-a", Priority.PRIMARY)], ("a", "b")),
2810+
(
2811+
[
2812+
("PyPI", Priority.PRIMARY),
2813+
("custom-a", Priority.PRIMARY),
2814+
("custom-b", Priority.PRIMARY),
2815+
],
2816+
("", "a", "b"),
2817+
),
2818+
(
2819+
[
2820+
("PyPI", Priority.EXPLICIT),
2821+
("custom-a", Priority.PRIMARY),
2822+
("custom-b", Priority.PRIMARY),
2823+
],
2824+
("", "a", "b"),
2825+
),
2826+
(
2827+
[
2828+
("custom-a", Priority.PRIMARY),
2829+
("custom-b", Priority.PRIMARY),
2830+
("PyPI", Priority.SUPPLEMENTAL),
2831+
],
2832+
("", "a", "b"),
2833+
),
2834+
],
2835+
)
2836+
def test_exporter_index_urls(
2837+
tmp_path: Path,
2838+
poetry: Poetry,
2839+
priorities: list[tuple[str, Priority]],
2840+
expected: tuple[str, ...],
2841+
) -> None:
2842+
pypi = poetry.pool.repository("PyPI")
2843+
poetry.pool.remove_repository("PyPI")
2844+
for name, prio in priorities:
2845+
if name.lower() == "pypi":
2846+
repo = pypi
2847+
else:
2848+
repo = LegacyRepository(name, f"https://{name[-1]}.example.com/simple")
2849+
poetry.pool.add_repository(repo, priority=prio)
2850+
2851+
poetry.locker.mock_lock_data( # type: ignore[attr-defined]
2852+
{
2853+
"package": [
2854+
{
2855+
"name": "foo",
2856+
"version": "1.2.3",
2857+
"optional": False,
2858+
"python-versions": "*",
2859+
"source": {
2860+
"type": "legacy",
2861+
"url": "https://a.example.com/simple",
2862+
"reference": "",
2863+
},
2864+
},
2865+
{
2866+
"name": "bar",
2867+
"version": "4.5.6",
2868+
"optional": False,
2869+
"python-versions": "*",
2870+
"source": {
2871+
"type": "legacy",
2872+
"url": "https://b.example.com/simple",
2873+
"reference": "",
2874+
},
2875+
},
2876+
],
2877+
"metadata": {
2878+
"python-versions": "*",
2879+
"content-hash": "123456789",
2880+
"files": {
2881+
"foo": [{"name": "foo.whl", "hash": "12345"}],
2882+
"bar": [{"name": "bar.whl", "hash": "67890"}],
2883+
},
2884+
},
2885+
}
2886+
)
2887+
set_package_requires(poetry, dev={"bar"})
2888+
2889+
exporter = Exporter(poetry, NullIO())
2890+
exporter.only_groups([MAIN_GROUP, "dev"])
2891+
exporter.export("requirements.txt", tmp_path, "requirements.txt")
2892+
2893+
with (tmp_path / "requirements.txt").open(encoding="utf-8") as f:
2894+
content = f.read()
2895+
2896+
expected_urls = [
2897+
f"--extra-index-url https://{name[-1]}.example.com/simple"
2898+
for name in expected[1:]
2899+
]
2900+
if expected[0]:
2901+
expected_urls = [
2902+
f"--index-url https://{expected[0]}.example.com/simple",
2903+
*expected_urls,
2904+
]
2905+
url_string = "\n".join(expected_urls)
2906+
2907+
expected_content = f"""\
2908+
{url_string}
2909+
2910+
bar==4.5.6 ; {MARKER_PY} \\
2911+
--hash=sha256:67890
2912+
foo==1.2.3 ; {MARKER_PY} \\
2913+
--hash=sha256:12345
2914+
"""
2915+
2916+
assert content == expected_content

0 commit comments

Comments
 (0)