From 654efea2aa34a8ecb7b951de295ad4e0ab224a24 Mon Sep 17 00:00:00 2001 From: sudorm-rf0 Date: Mon, 10 Aug 2026 21:23:28 +0800 Subject: [PATCH] Fix requirements-txt-fixer reordering --index-url after --extra-index-url (#612) pip uses the first --index-url as the primary index and treats later --extra-index-url entries as additional indexes. If --extra-index-url sorts before --index-url (alphabetical order), the primary index URL is silently dropped. Keep --index-url ordered first. Fixes #612. --- pre_commit_hooks/requirements_txt_fixer.py | 15 +++++++++++++++ tests/requirements_txt_fixer_test.py | 20 ++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/pre_commit_hooks/requirements_txt_fixer.py b/pre_commit_hooks/requirements_txt_fixer.py index 8ce8ec64..f6e6609f 100644 --- a/pre_commit_hooks/requirements_txt_fixer.py +++ b/pre_commit_hooks/requirements_txt_fixer.py @@ -50,6 +50,21 @@ def __lt__(self, requirement: Requirement) -> bool: # with comments is kept) if self.name == requirement.name: return bool(self.comments) > bool(requirement.comments) + # `--index-url` must be ordered before `--extra-index-url`. pip + # uses the first `--index-url` as the primary index and treats + # subsequent `--extra-index-url` entries as additional indexes; if + # `--extra-index-url` appears first it is silently dropped, so we + # keep the index URL first (see issue #612). + if ( + self.name == b'--index-url' and + requirement.name == b'--extra-index-url' + ): + return True + if ( + self.name == b'--extra-index-url' and + requirement.name == b'--index-url' + ): + return False return self.name < requirement.name def is_complete(self) -> bool: diff --git a/tests/requirements_txt_fixer_test.py b/tests/requirements_txt_fixer_test.py index c0d2c65d..f245253a 100644 --- a/tests/requirements_txt_fixer_test.py +++ b/tests/requirements_txt_fixer_test.py @@ -107,6 +107,26 @@ PASS, b'a=2.0.0 \\\n --hash=sha256:abcd\nb==1.0.0\n', ), + # `--index-url` must be kept before `--extra-index-url` so pip does + # not drop the primary index URL (see issue #612). + ( + b'--index-url https://primary.example.com\n' + b'--extra-index-url https://extra.example.com\n' + b'foo==1.0\n', + PASS, + b'--index-url https://primary.example.com\n' + b'--extra-index-url https://extra.example.com\n' + b'foo==1.0\n', + ), + ( + b'--extra-index-url https://extra.example.com\n' + b'--index-url https://primary.example.com\n' + b'foo==1.0\n', + FAIL, + b'--index-url https://primary.example.com\n' + b'--extra-index-url https://extra.example.com\n' + b'foo==1.0\n', + ), ), ) def test_integration(input_s, expected_retval, output, tmpdir):