Fix requirements-txt-fixer reordering pip options like --index-url

The requirements-txt-fixer was alphabetically sorting all lines, including
pip options like --index-url and --extra-index-url. This caused
--extra-index-url to be sorted above --index-url, breaking pip's index
resolution order since --index-url must come first.

Fix by preserving the original relative order of lines that start with
`--` (pip options), while still sorting regular package requirements
alphabetically.

Closes #612

Bahtya
This commit is contained in:
Bahtya 2026-04-10 00:13:44 +08:00
parent d1283494cb
commit dfac6b321e
2 changed files with 41 additions and 0 deletions

View file

@ -45,6 +45,14 @@ class Requirement:
elif requirement.value == b'\n':
return False
else:
# if both are pip options (start with --), maintain original
# order to avoid breaking semantic ordering
# (e.g. --index-url must come before --extra-index-url)
if (
self.name.startswith(b'--') and
requirement.name.startswith(b'--')
):
return False
# if 2 requirements have the same name, the one with comments
# needs to go first (so that when removing duplicates, the one
# with comments is kept)

View file

@ -107,6 +107,39 @@ from pre_commit_hooks.requirements_txt_fixer import Requirement
PASS,
b'a=2.0.0 \\\n --hash=sha256:abcd\nb==1.0.0\n',
),
# --index-url and --extra-index-url should maintain original order
# see: https://github.com/pre-commit/pre-commit-hooks/issues/612
(
b'--index-url https://example.com/simple\n'
b'--extra-index-url https://example.com/extra\n'
b'foo\n',
PASS,
b'--index-url https://example.com/simple\n'
b'--extra-index-url https://example.com/extra\n'
b'foo\n',
),
# pip options should not be reordered even if out of alpha order
(
b'--extra-index-url https://example.com/extra\n'
b'--index-url https://example.com/simple\n'
b'foo\n',
PASS,
b'--extra-index-url https://example.com/extra\n'
b'--index-url https://example.com/simple\n'
b'foo\n',
),
# packages should still be sorted while pip options stay in place
(
b'--index-url https://example.com/simple\n'
b'--extra-index-url https://example.com/extra\n'
b'foo\n'
b'bar\n',
FAIL,
b'--index-url https://example.com/simple\n'
b'--extra-index-url https://example.com/extra\n'
b'bar\n'
b'foo\n',
),
),
)
def test_integration(input_s, expected_retval, output, tmpdir):