Merge pull request #8656 from chrahunt/gracefully-handle-bad-data-paths

Trace a better error message on installation failure due to invalid .data files in wheels
This commit is contained in:
Pradyun Gedam 2020-08-02 19:55:40 +05:30 committed by GitHub
commit 7e6ff08aae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 57 additions and 2 deletions

2
news/8654.bugfix Normal file
View File

@ -0,0 +1,2 @@
Trace a better error message on installation failure due to invalid ``.data``
files in wheels.

View File

@ -583,8 +583,28 @@ def _install_wheel(
def make_data_scheme_file(record_path):
# type: (RecordPath) -> File
normed_path = os.path.normpath(record_path)
_, scheme_key, dest_subpath = normed_path.split(os.path.sep, 2)
scheme_path = scheme_paths[scheme_key]
try:
_, scheme_key, dest_subpath = normed_path.split(os.path.sep, 2)
except ValueError:
message = (
"Unexpected file in {}: {!r}. .data directory contents"
" should be named like: '<scheme key>/<path>'."
).format(wheel_path, record_path)
raise InstallationError(message)
try:
scheme_path = scheme_paths[scheme_key]
except KeyError:
valid_scheme_keys = ", ".join(sorted(scheme_paths))
message = (
"Unknown scheme key used in {}: {} (for file {!r}). .data"
" directory contents should be in subdirectories named"
" with a valid scheme key ({})"
).format(
wheel_path, scheme_key, record_path, valid_scheme_keys
)
raise InstallationError(message)
dest_path = os.path.join(scheme_path, dest_subpath)
assert_no_path_traversal(scheme_path, dest_path)
return ZipBackedFile(record_path, dest_path, zip_file)

View File

@ -681,3 +681,36 @@ def test_correct_package_name_while_creating_wheel_bug(script, package_name):
package = create_basic_wheel_for_package(script, package_name, '1.0')
wheel_name = os.path.basename(package)
assert wheel_name == 'simple_package-1.0-py2.py3-none-any.whl'
@pytest.mark.parametrize("name", ["purelib", "abc"])
def test_wheel_with_file_in_data_dir_has_reasonable_error(
script, tmpdir, name
):
"""Normally we expect entities in the .data directory to be in a
subdirectory, but if they are not then we should show a reasonable error
message that includes the path.
"""
wheel_path = make_wheel(
"simple", "0.1.0", extra_data_files={name: "hello world"}
).save_to_dir(tmpdir)
result = script.pip(
"install", "--no-index", str(wheel_path), expect_error=True
)
assert "simple-0.1.0.data/{}".format(name) in result.stderr
def test_wheel_with_unknown_subdir_in_data_dir_has_reasonable_error(
script, tmpdir
):
wheel_path = make_wheel(
"simple",
"0.1.0",
extra_data_files={"unknown/hello.txt": "hello world"}
).save_to_dir(tmpdir)
result = script.pip(
"install", "--no-index", str(wheel_path), expect_error=True
)
assert "simple-0.1.0.data/unknown/hello.txt" in result.stderr