10
10
from pip ._internal .resolution .resolvelib .candidates import REQUIRES_PYTHON_IDENTIFIER
11
11
from pip ._internal .resolution .resolvelib .factory import Factory
12
12
from pip ._internal .resolution .resolvelib .provider import PipProvider
13
- from pip ._internal .resolution .resolvelib .requirements import SpecifierRequirement
13
+ from pip ._internal .resolution .resolvelib .requirements import (
14
+ ExplicitRequirement ,
15
+ SpecifierRequirement ,
16
+ )
14
17
15
18
if TYPE_CHECKING :
16
19
from pip ._vendor .resolvelib .providers import Preference
20
23
PreferenceInformation = RequirementInformation [Requirement , Candidate ]
21
24
22
25
26
+ class FakeCandidate (Candidate ):
27
+ """A minimal fake candidate for testing purposes."""
28
+
29
+ def __init__ (self , * args : object , ** kwargs : object ) -> None : ...
30
+
31
+
23
32
def build_req_info (
24
33
name : str , parent : Optional [Candidate ] = None
25
34
) -> "PreferenceInformation" :
@@ -33,6 +42,14 @@ def build_req_info(
33
42
return requirement_information
34
43
35
44
45
+ def build_explicit_req_info (
46
+ url : str , parent : Optional [Candidate ] = None
47
+ ) -> "PreferenceInformation" :
48
+ """Build a direct requirement using a minimal FakeCandidate."""
49
+ direct_requirement = ExplicitRequirement (FakeCandidate (url ))
50
+ return RequirementInformation (requirement = direct_requirement , parent = parent )
51
+
52
+
36
53
@pytest .mark .parametrize (
37
54
"identifier, information, backtrack_causes, user_requested, expected" ,
38
55
[
@@ -42,47 +59,55 @@ def build_req_info(
42
59
{"pinned-package" : [build_req_info ("pinned-package==1.0" )]},
43
60
[],
44
61
{},
45
- (False , False , True , math .inf , False , "pinned-package" ),
62
+ (True , False , True , math .inf , False , "pinned-package" ),
46
63
),
47
64
# Star-specified package, i.e. with "*"
48
65
(
49
66
"star-specified-package" ,
50
67
{"star-specified-package" : [build_req_info ("star-specified-package==1.*" )]},
51
68
[],
52
69
{},
53
- (False , True , False , math .inf , False , "star-specified-package" ),
70
+ (True , True , False , math .inf , False , "star-specified-package" ),
54
71
),
55
72
# Package that caused backtracking
56
73
(
57
74
"backtrack-package" ,
58
75
{"backtrack-package" : [build_req_info ("backtrack-package" )]},
59
76
[build_req_info ("backtrack-package" )],
60
77
{},
61
- (False , True , True , math .inf , True , "backtrack-package" ),
78
+ (True , True , True , math .inf , True , "backtrack-package" ),
62
79
),
63
80
# Root package requested by user
64
81
(
65
82
"root-package" ,
66
83
{"root-package" : [build_req_info ("root-package" )]},
67
84
[],
68
85
{"root-package" : 1 },
69
- (False , True , True , 1 , True , "root-package" ),
86
+ (True , True , True , 1 , True , "root-package" ),
70
87
),
71
88
# Unfree package (with specifier operator)
72
89
(
73
90
"unfree-package" ,
74
91
{"unfree-package" : [build_req_info ("unfree-package!=1" )]},
75
92
[],
76
93
{},
77
- (False , True , True , math .inf , False , "unfree-package" ),
94
+ (True , True , True , math .inf , False , "unfree-package" ),
78
95
),
79
96
# Free package (no operator)
80
97
(
81
98
"free-package" ,
82
99
{"free-package" : [build_req_info ("free-package" )]},
83
100
[],
84
101
{},
85
- (False , True , True , math .inf , True , "free-package" ),
102
+ (True , True , True , math .inf , True , "free-package" ),
103
+ ),
104
+ # Test case for "direct" preference (explicit URL)
105
+ (
106
+ "direct-package" ,
107
+ {"direct-package" : [build_explicit_req_info ("direct-package" )]},
108
+ [],
109
+ {},
110
+ (False , True , True , math .inf , True , "direct-package" ),
86
111
),
87
112
# Upper bounded with <= operator
88
113
(
@@ -94,15 +119,15 @@ def build_req_info(
94
119
},
95
120
[],
96
121
{},
97
- (False , True , False , math .inf , False , "upper-bound-lte-package" ),
122
+ (True , True , False , math .inf , False , "upper-bound-lte-package" ),
98
123
),
99
124
# Upper bounded with < operator
100
125
(
101
126
"upper-bound-lt-package" ,
102
127
{"upper-bound-lt-package" : [build_req_info ("upper-bound-lt-package<2.0" )]},
103
128
[],
104
129
{},
105
- (False , True , False , math .inf , False , "upper-bound-lt-package" ),
130
+ (True , True , False , math .inf , False , "upper-bound-lt-package" ),
106
131
),
107
132
# Upper bounded with ~= operator
108
133
(
@@ -114,15 +139,15 @@ def build_req_info(
114
139
},
115
140
[],
116
141
{},
117
- (False , True , False , math .inf , False , "upper-bound-compatible-package" ),
142
+ (True , True , False , math .inf , False , "upper-bound-compatible-package" ),
118
143
),
119
144
# Not upper bounded, using only >= operator
120
145
(
121
146
"lower-bound-package" ,
122
147
{"lower-bound-package" : [build_req_info ("lower-bound-package>=1.0" )]},
123
148
[],
124
149
{},
125
- (False , True , True , math .inf , False , "lower-bound-package" ),
150
+ (True , True , True , math .inf , False , "lower-bound-package" ),
126
151
),
127
152
],
128
153
)
0 commit comments