11import math
2- from typing import TYPE_CHECKING , Dict , Iterable , Optional , Sequence
2+ from typing import TYPE_CHECKING , Dict , Iterable , List , Optional , Sequence
33
44import pytest
55
@@ -36,61 +36,53 @@ def build_req_info(
3636@pytest .mark .parametrize (
3737 "identifier, information, backtrack_causes, user_requested, expected" ,
3838 [
39- # Test case for REQUIRES_PYTHON_IDENTIFIER
40- (
41- REQUIRES_PYTHON_IDENTIFIER ,
42- {REQUIRES_PYTHON_IDENTIFIER : [build_req_info ("python" )]},
43- [],
44- {},
45- (False , False , True , True , math .inf , True , REQUIRES_PYTHON_IDENTIFIER ),
46- ),
4739 # Pinned package with "=="
4840 (
4941 "pinned-package" ,
5042 {"pinned-package" : [build_req_info ("pinned-package==1.0" )]},
5143 [],
5244 {},
53- (True , False , False , True , math .inf , False , "pinned-package" ),
45+ (False , False , math .inf , False , "pinned-package" ),
5446 ),
5547 # Star-specified package, i.e. with "*"
5648 (
5749 "star-specified-package" ,
5850 {"star-specified-package" : [build_req_info ("star-specified-package==1.*" )]},
5951 [],
6052 {},
61- (True , False , True , True , math .inf , False , "star-specified-package" ),
53+ (False , True , math .inf , False , "star-specified-package" ),
6254 ),
6355 # Package that caused backtracking
6456 (
6557 "backtrack-package" ,
6658 {"backtrack-package" : [build_req_info ("backtrack-package" )]},
6759 [build_req_info ("backtrack-package" )],
6860 {},
69- (True , False , True , False , math .inf , True , "backtrack-package" ),
61+ (False , True , math .inf , True , "backtrack-package" ),
7062 ),
7163 # Root package requested by user
7264 (
7365 "root-package" ,
7466 {"root-package" : [build_req_info ("root-package" )]},
7567 [],
7668 {"root-package" : 1 },
77- (True , False , True , True , 1 , True , "root-package" ),
69+ (False , True , 1 , True , "root-package" ),
7870 ),
7971 # Unfree package (with specifier operator)
8072 (
8173 "unfree-package" ,
8274 {"unfree-package" : [build_req_info ("unfree-package<1" )]},
8375 [],
8476 {},
85- (True , False , True , True , math .inf , False , "unfree-package" ),
77+ (False , True , math .inf , False , "unfree-package" ),
8678 ),
8779 # Free package (no operator)
8880 (
8981 "free-package" ,
9082 {"free-package" : [build_req_info ("free-package" )]},
9183 [],
9284 {},
93- (True , False , True , True , math .inf , True , "free-package" ),
85+ (False , True , math .inf , True , "free-package" ),
9486 ),
9587 ],
9688)
@@ -115,3 +107,70 @@ def test_get_preference(
115107 )
116108
117109 assert preference == expected , f"Expected { expected } , got { preference } "
110+
111+
112+ @pytest .mark .parametrize (
113+ "identifiers, backtrack_causes, expected" ,
114+ [
115+ # REQUIRES_PYTHON_IDENTIFIER is present
116+ (
117+ [REQUIRES_PYTHON_IDENTIFIER , "package1" , "package2" , "backtrack-package" ],
118+ [build_req_info ("backtrack-package" )],
119+ [REQUIRES_PYTHON_IDENTIFIER ],
120+ ),
121+ # REQUIRES_PYTHON_IDENTIFIER is present after backtrack causes
122+ (
123+ ["package1" , "package2" , "backtrack-package" , REQUIRES_PYTHON_IDENTIFIER ],
124+ [build_req_info ("backtrack-package" )],
125+ [REQUIRES_PYTHON_IDENTIFIER ],
126+ ),
127+ # Backtrack causes present (direct requirement)
128+ (
129+ ["package1" , "package2" , "backtrack-package" ],
130+ [build_req_info ("backtrack-package" )],
131+ ["backtrack-package" ],
132+ ),
133+ # Multiple backtrack causes
134+ (
135+ ["package1" , "backtrack1" , "backtrack2" , "package2" ],
136+ [build_req_info ("backtrack1" ), build_req_info ("backtrack2" )],
137+ ["backtrack1" , "backtrack2" ],
138+ ),
139+ # No special identifiers - return all
140+ (
141+ ["package1" , "package2" ],
142+ [],
143+ ["package1" , "package2" ],
144+ ),
145+ # Empty list of identifiers
146+ (
147+ [],
148+ [],
149+ [],
150+ ),
151+ ],
152+ )
153+ def test_narrow_requirement_selection (
154+ identifiers : List [str ],
155+ backtrack_causes : Sequence ["PreferenceInformation" ],
156+ expected : List [str ],
157+ factory : Factory ,
158+ ) -> None :
159+ """Test that narrow_requirement_selection correctly prioritizes identifiers:
160+ 1. REQUIRES_PYTHON_IDENTIFIER (if present)
161+ 2. Backtrack causes (if present)
162+ 3. All other identifiers (as-is)
163+ """
164+ provider = PipProvider (
165+ factory = factory ,
166+ constraints = {},
167+ ignore_dependencies = False ,
168+ upgrade_strategy = "to-satisfy-only" ,
169+ user_requested = {},
170+ )
171+
172+ result = provider .narrow_requirement_selection (
173+ identifiers , {}, {}, {}, backtrack_causes
174+ )
175+
176+ assert list (result ) == expected , f"Expected { expected } , got { list (result )} "
0 commit comments