Skip to content

Commit f5f35d6

Browse files
authored
fix(pypi): propagate fails if overrides are passed only one index is used (#3666)
Before this PR there would be confusing failures when downloader config is set to disallow certain values or when the authentication is not setup properly. This is a small fix towards a better goal state where we set `allow_fail = False` in cases where we know that we have to succeed to download metadata from that particular URL. The use-cases covered: - Only one index_url is passed to `pip.parse`. - `index_url_overrides` are passed which means that we should fail if there are insufficient overrides. The downside to this is that it is really hard to return custom error messages telling the user what to do, but on the flip side, the failures coming from bazel itself might be more descriptive in the case of outh-misconfiguration or bazel downloader configuration settings. Work towards #2632 and #3260.
1 parent eb1ae41 commit f5f35d6

File tree

3 files changed

+90
-23
lines changed

3 files changed

+90
-23
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ END_UNRELEASED_TEMPLATE
6767
Other changes:
6868
* (pypi) Update dependencies used for `compile_pip_requirements`, building
6969
sdists in the `whl_library` rule and fetching wheels using `pip`.
70+
* (pypi) We will set `allow_fail` to `False` if the {attr}`experimental_index_url_overrides` is set
71+
to a non-empty value. This means that failures will be no-longer cached in this particular case.
72+
([#3260](https://github.com/bazel-contrib/rules_python/issues/3260) and
73+
[#2632](https://github.com/bazel-contrib/rules_python/issues/2632))
7074

7175
{#v0-0-0-fixed}
7276
### Fixed

python/private/pypi/simpleapi_download.bzl

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,16 +71,21 @@ def simpleapi_download(
7171
for p, i in (attr.index_url_overrides or {}).items()
7272
}
7373

74-
download_kwargs = {}
75-
if bazel_features.external_deps.download_has_block_param:
76-
download_kwargs["block"] = not parallel_download
77-
7874
# NOTE @aignas 2024-03-31: we are not merging results from multiple indexes
7975
# to replicate how `pip` would handle this case.
8076
contents = {}
8177
index_urls = [attr.index_url] + attr.extra_index_urls
8278
read_simpleapi = read_simpleapi or _read_simpleapi
8379

80+
download_kwargs = {}
81+
if bazel_features.external_deps.download_has_block_param:
82+
download_kwargs["block"] = not parallel_download
83+
84+
if len(index_urls) == 1 or index_url_overrides:
85+
download_kwargs["allow_fail"] = False
86+
else:
87+
download_kwargs["allow_fail"] = True
88+
8489
input_sources = attr.sources
8590

8691
found_on_index = {}
@@ -225,7 +230,6 @@ def _read_simpleapi(ctx, url, attr, cache, versions, get_auth = None, **download
225230
url = [real_url],
226231
output = output,
227232
auth = get_auth(ctx, [real_url], ctx_attr = attr),
228-
allow_fail = True,
229233
**download_kwargs
230234
)
231235

tests/pypi/simpleapi_download/simpleapi_download_tests.bzl

Lines changed: 77 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,10 @@ _tests = []
2323
def _test_simple(env):
2424
calls = []
2525

26-
def read_simpleapi(ctx, url, versions, attr, cache, get_auth, block):
27-
_ = ctx # buildifier: disable=unused-variable
28-
_ = attr
29-
_ = cache
30-
_ = get_auth
31-
_ = versions
26+
def read_simpleapi(ctx, url, versions, attr, cache, get_auth, block, allow_fail):
27+
_ = ctx, attr, cache, get_auth, versions # buildifier: disable=unused-variable
3228
env.expect.that_bool(block).equals(False)
29+
env.expect.that_bool(allow_fail).equals(True)
3330
calls.append(url)
3431
if "foo" in url and "main" in url:
3532
return struct(
@@ -96,13 +93,10 @@ def _test_fail(env):
9693
calls = []
9794
fails = []
9895

99-
def read_simpleapi(ctx, url, versions, attr, cache, get_auth, block):
100-
_ = ctx # buildifier: disable=unused-variable
101-
_ = attr
102-
_ = cache
103-
_ = get_auth
104-
_ = versions
96+
def read_simpleapi(ctx, url, versions, attr, cache, get_auth, block, allow_fail):
97+
_ = ctx, attr, cache, get_auth, versions # buildifier: disable=unused-variable
10598
env.expect.that_bool(block).equals(False)
99+
env.expect.that_bool(allow_fail).equals(True)
106100
calls.append(url)
107101
if "foo" in url:
108102
return struct(
@@ -130,9 +124,7 @@ def _test_fail(env):
130124
report_progress = lambda _: None,
131125
),
132126
attr = struct(
133-
index_url_overrides = {
134-
"foo": "invalid",
135-
},
127+
index_url_overrides = {},
136128
index_url = "main",
137129
extra_index_urls = ["extra"],
138130
sources = {"bar": None, "baz": None, "foo": None},
@@ -149,7 +141,7 @@ def _test_fail(env):
149141
Failed to download metadata of the following packages from urls:
150142
{
151143
"bar": ["main", "extra"],
152-
"foo": "invalid",
144+
"foo": ["main", "extra"],
153145
}
154146
155147
If you would like to skip downloading metadata for these packages please add 'simpleapi_skip=[
@@ -159,15 +151,82 @@ If you would like to skip downloading metadata for these packages please add 'si
159151
""",
160152
])
161153
env.expect.that_collection(calls).contains_exactly([
162-
"invalid/foo/",
154+
"main/foo/",
163155
"main/bar/",
164156
"main/baz/",
165-
"invalid/foo/",
157+
"extra/foo/",
166158
"extra/bar/",
167159
])
168160

169161
_tests.append(_test_fail)
170162

163+
def _test_allow_fail_single_index(env):
164+
calls = []
165+
fails = []
166+
167+
def read_simpleapi(ctx, *, url, versions, attr, cache, get_auth, block, allow_fail):
168+
_ = ctx, attr, cache, get_auth, versions # buildifier: disable=unused-variable
169+
env.expect.that_bool(block).equals(False)
170+
env.expect.that_bool(allow_fail).equals(False)
171+
calls.append(url)
172+
return struct(
173+
output = struct(
174+
sdists = {"deadbeef": url.strip("/").split("/")[-1]},
175+
whls = {"deadb33f": url.strip("/").split("/")[-1]},
176+
sha256s_by_version = {"fizz": url.strip("/").split("/")[-1]},
177+
),
178+
success = True,
179+
)
180+
181+
contents = simpleapi_download(
182+
ctx = struct(
183+
getenv = {}.get,
184+
report_progress = lambda _: None,
185+
),
186+
attr = struct(
187+
index_url_overrides = {
188+
"foo": "extra",
189+
},
190+
index_url = "main",
191+
extra_index_urls = [],
192+
sources = {"bar": None, "baz": None, "foo": None},
193+
envsubst = [],
194+
),
195+
cache = pypi_cache(),
196+
parallel_download = True,
197+
read_simpleapi = read_simpleapi,
198+
_fail = fails.append,
199+
)
200+
201+
env.expect.that_collection(fails).contains_exactly([])
202+
env.expect.that_collection(calls).contains_exactly([
203+
"main/bar/",
204+
"main/baz/",
205+
"extra/foo/",
206+
])
207+
env.expect.that_dict(contents).contains_exactly({
208+
"bar": struct(
209+
index_url = "main/bar/",
210+
sdists = {"deadbeef": "bar"},
211+
sha256s_by_version = {"fizz": "bar"},
212+
whls = {"deadb33f": "bar"},
213+
),
214+
"baz": struct(
215+
index_url = "main/baz/",
216+
sdists = {"deadbeef": "baz"},
217+
sha256s_by_version = {"fizz": "baz"},
218+
whls = {"deadb33f": "baz"},
219+
),
220+
"foo": struct(
221+
index_url = "extra/foo/",
222+
sdists = {"deadbeef": "foo"},
223+
sha256s_by_version = {"fizz": "foo"},
224+
whls = {"deadb33f": "foo"},
225+
),
226+
})
227+
228+
_tests.append(_test_allow_fail_single_index)
229+
171230
def _test_download_url(env):
172231
downloads = {}
173232

0 commit comments

Comments
 (0)