1
1
Fork 0
mirror of https://github.com/pypa/pip synced 2023-12-13 21:30:23 +01:00
pip/tests/unit/test_wheel.py

555 lines
18 KiB
Python
Raw Normal View History

2013-05-28 23:58:08 +02:00
"""Tests for wheel binary packages and .dist-info."""
2019-01-24 03:44:54 +01:00
import csv
2018-06-23 23:07:39 +02:00
import logging
2018-06-23 23:10:40 +02:00
import os
2019-01-24 03:44:54 +01:00
import textwrap
2014-04-25 23:42:14 +02:00
2017-05-16 12:16:30 +02:00
import pytest
from mock import patch
from pip._vendor.packaging.requirements import Requirement
2019-12-01 23:07:00 +01:00
from pip._internal import wheel
from pip._internal.commands.wheel import WheelCommand
2019-12-01 23:07:00 +01:00
from pip._internal.exceptions import UnsupportedWheel
from pip._internal.locations import get_scheme
from pip._internal.models.scheme import Scheme
from pip._internal.utils.compat import WINDOWS
from pip._internal.utils.misc import hash_file
from pip._internal.utils.unpacking import unpack_file
2019-09-07 15:59:41 +02:00
from pip._internal.wheel import (
MissingCallableSuffix,
_raise_for_invalid_entrypoint,
)
from pip._internal.wheel_builder import get_legacy_build_wheel_path
from tests.lib import DATA_DIR, assert_paths_equal
def call_get_legacy_build_wheel_path(caplog, names):
wheel_path = get_legacy_build_wheel_path(
names=names,
temp_dir='/tmp/abcd',
name='pendulum',
command_args=['arg1', 'arg2'],
command_output='output line 1\noutput line 2\n',
)
return wheel_path
def test_get_legacy_build_wheel_path(caplog):
actual = call_get_legacy_build_wheel_path(caplog, names=['name'])
assert_paths_equal(actual, '/tmp/abcd/name')
assert not caplog.records
def test_get_legacy_build_wheel_path__no_names(caplog):
caplog.set_level(logging.INFO)
actual = call_get_legacy_build_wheel_path(caplog, names=[])
assert actual is None
assert len(caplog.records) == 1
record = caplog.records[0]
assert record.levelname == 'WARNING'
assert record.message.splitlines() == [
"Legacy build of wheel for 'pendulum' created no files.",
"Command arguments: arg1 arg2",
'Command output: [use --verbose to show]',
]
def test_get_legacy_build_wheel_path__multiple_names(caplog):
caplog.set_level(logging.INFO)
# Deliberately pass the names in non-sorted order.
actual = call_get_legacy_build_wheel_path(
caplog, names=['name2', 'name1'],
)
assert_paths_equal(actual, '/tmp/abcd/name1')
assert len(caplog.records) == 1
record = caplog.records[0]
assert record.levelname == 'WARNING'
assert record.message.splitlines() == [
"Legacy build of wheel for 'pendulum' created more than one file.",
"Filenames (choosing first): ['name1', 'name2']",
"Command arguments: arg1 arg2",
'Command output: [use --verbose to show]',
]
@pytest.mark.parametrize("console_scripts",
["pip = pip._internal.main:pip",
"pip:pip = pip._internal.main:pip"])
def test_get_entrypoints(tmpdir, console_scripts):
entry_points = tmpdir.joinpath("entry_points.txt")
with open(str(entry_points), "w") as fp:
2013-11-19 14:32:58 +01:00
fp.write("""
[console_scripts]
{}
[section]
common:one = module:func
common:two = module:other_func
""".format(console_scripts))
2013-11-19 14:32:58 +01:00
assert wheel.get_entrypoints(str(entry_points)) == (
dict([console_scripts.split(' = ')]),
2013-11-19 14:32:58 +01:00
{},
)
2019-09-07 15:59:41 +02:00
def test_raise_for_invalid_entrypoint_ok():
_raise_for_invalid_entrypoint("hello = hello:main")
@pytest.mark.parametrize("entrypoint", [
"hello = hello",
"hello = hello:",
])
2019-09-07 15:59:41 +02:00
def test_raise_for_invalid_entrypoint_fail(entrypoint):
with pytest.raises(MissingCallableSuffix):
2019-09-07 15:59:41 +02:00
_raise_for_invalid_entrypoint(entrypoint)
@pytest.mark.parametrize("outrows, expected", [
([
('', '', 'a'),
('', '', ''),
], [
('', '', ''),
('', '', 'a'),
]),
([
# Include an int to check avoiding the following error:
# > TypeError: '<' not supported between instances of 'str' and 'int'
('', '', 1),
('', '', ''),
], [
('', '', ''),
('', '', 1),
]),
])
def test_sorted_outrows(outrows, expected):
actual = wheel.sorted_outrows(outrows)
assert actual == expected
2019-01-24 03:44:54 +01:00
def call_get_csv_rows_for_installed(tmpdir, text):
path = tmpdir.joinpath('temp.txt')
path.write_text(text)
2019-01-24 03:44:54 +01:00
# Test that an installed file appearing in RECORD has its filename
# updated in the new RECORD file.
installed = {'a': 'z'}
2019-01-24 03:44:54 +01:00
changed = set()
generated = []
lib_dir = '/lib/dir'
with wheel.open_for_csv(path, 'r') as f:
reader = csv.reader(f)
outrows = wheel.get_csv_rows_for_installed(
reader, installed=installed, changed=changed,
generated=generated, lib_dir=lib_dir,
)
return outrows
def test_get_csv_rows_for_installed(tmpdir, caplog):
2019-01-24 03:44:54 +01:00
text = textwrap.dedent("""\
a,b,c
d,e,f
""")
outrows = call_get_csv_rows_for_installed(tmpdir, text)
expected = [
('z', 'b', 'c'),
2019-01-24 03:44:54 +01:00
('d', 'e', 'f'),
]
assert outrows == expected
# Check there were no warnings.
assert len(caplog.records) == 0
2019-01-24 03:44:54 +01:00
def test_get_csv_rows_for_installed__long_lines(tmpdir, caplog):
2019-01-24 03:44:54 +01:00
text = textwrap.dedent("""\
a,b,c,d
e,f,g
h,i,j,k
2019-01-24 03:44:54 +01:00
""")
outrows = call_get_csv_rows_for_installed(tmpdir, text)
expected = [
('z', 'b', 'c', 'd'),
('e', 'f', 'g'),
('h', 'i', 'j', 'k'),
]
assert outrows == expected
messages = [rec.message for rec in caplog.records]
expected = [
"RECORD line has more than three elements: ['a', 'b', 'c', 'd']",
"RECORD line has more than three elements: ['h', 'i', 'j', 'k']"
]
assert messages == expected
2019-01-24 03:44:54 +01:00
2014-02-18 05:20:12 +01:00
def test_wheel_version(tmpdir, data):
future_wheel = 'futurewheel-1.9-py2.py3-none-any.whl'
broken_wheel = 'brokenwheel-1.0-py2.py3-none-any.whl'
future_version = (1, 9)
unpack_file(data.packages.joinpath(future_wheel), tmpdir + 'future')
unpack_file(data.packages.joinpath(broken_wheel), tmpdir + 'broken')
assert wheel.wheel_version(tmpdir + 'future') == future_version
assert not wheel.wheel_version(tmpdir + 'broken')
2014-02-18 05:20:12 +01:00
def test_check_compatibility():
name = 'test'
vc = wheel.VERSION_COMPATIBLE
2014-02-18 05:20:12 +01:00
# Major version is higher - should be incompatible
higher_v = (vc[0] + 1, vc[1])
2014-02-18 05:20:12 +01:00
# test raises with correct error
with pytest.raises(UnsupportedWheel) as e:
2014-02-18 05:20:12 +01:00
wheel.check_compatibility(higher_v, name)
assert 'is not compatible' in str(e)
2014-02-18 05:20:12 +01:00
# Should only log.warning - minor version is greater
higher_v = (vc[0], vc[1] + 1)
wheel.check_compatibility(higher_v, name)
2014-02-18 05:20:12 +01:00
# These should work fine
wheel.check_compatibility(wheel.VERSION_COMPATIBLE, name)
# E.g if wheel to install is 1.0 and we support up to 1.2
lower_v = (vc[0], max(0, vc[1] - 1))
2014-02-18 05:20:12 +01:00
wheel.check_compatibility(lower_v, name)
2013-05-28 23:58:08 +02:00
class TestWheelFile(object):
2019-09-18 02:18:52 +02:00
def test_unpack_wheel_no_flatten(self, tmpdir):
filepath = os.path.join(DATA_DIR, 'packages',
'meta-1.0-py2.py3-none-any.whl')
unpack_file(filepath, tmpdir)
2019-09-18 02:18:52 +02:00
assert os.path.isdir(os.path.join(tmpdir, 'meta-1.0.dist-info'))
def test_purelib_platlib(self, data):
"""
Test the "wheel is purelib/platlib" code.
"""
packages = [
("pure_wheel", data.packages.joinpath("pure_wheel-1.7"), True),
("plat_wheel", data.packages.joinpath("plat_wheel-1.7"), False),
("pure_wheel", data.packages.joinpath(
"pure_wheel-_invalidversion_"), True),
("plat_wheel", data.packages.joinpath(
"plat_wheel-_invalidversion_"), False),
]
for name, path, expected in packages:
assert wheel.root_is_purelib(name, path) == expected
2019-10-12 03:31:35 +02:00
class TestInstallUnpackedWheel(object):
"""
Tests for moving files from wheel src to scheme paths
"""
def prep(self, data, tmpdir):
self.name = 'sample'
self.wheelpath = data.packages.joinpath(
2014-04-25 23:42:14 +02:00
'sample-1.2.0-py2.py3-none-any.whl')
self.req = Requirement('sample')
2014-04-25 23:42:14 +02:00
self.src = os.path.join(tmpdir, 'src')
self.dest = os.path.join(tmpdir, 'dest')
unpack_file(self.wheelpath, self.src)
self.scheme = Scheme(
purelib=os.path.join(self.dest, 'lib'),
platlib=os.path.join(self.dest, 'lib'),
headers=os.path.join(self.dest, 'headers'),
scripts=os.path.join(self.dest, 'bin'),
data=os.path.join(self.dest, 'data'),
)
self.src_dist_info = os.path.join(
self.src, 'sample-1.2.0.dist-info')
self.dest_dist_info = os.path.join(
self.scheme.purelib, 'sample-1.2.0.dist-info')
def assert_installed(self):
# lib
assert os.path.isdir(
os.path.join(self.scheme.purelib, 'sample'))
# dist-info
metadata = os.path.join(self.dest_dist_info, 'METADATA')
assert os.path.isfile(metadata)
# data files
data_file = os.path.join(self.scheme.data, 'my_data', 'data_file')
assert os.path.isfile(data_file)
# package data
2014-04-25 23:42:14 +02:00
pkg_data = os.path.join(
self.scheme.purelib, 'sample', 'package_data.dat')
2014-04-25 23:42:14 +02:00
assert os.path.isfile(pkg_data)
def test_std_install(self, data, tmpdir):
self.prep(data, tmpdir)
2019-10-12 03:31:35 +02:00
wheel.install_unpacked_wheel(
2019-10-12 04:24:50 +02:00
self.name,
self.src,
scheme=self.scheme,
req_description=str(self.req),
)
self.assert_installed()
def test_install_prefix(self, data, tmpdir):
prefix = os.path.join(os.path.sep, 'some', 'path')
self.prep(data, tmpdir)
scheme = get_scheme(
self.name,
user=False,
home=None,
root=tmpdir,
isolated=False,
prefix=prefix,
)
2019-10-12 03:31:35 +02:00
wheel.install_unpacked_wheel(
self.name,
self.src,
scheme=scheme,
2019-10-12 04:24:50 +02:00
req_description=str(self.req),
)
2015-12-05 18:13:31 +01:00
bin_dir = 'Scripts' if WINDOWS else 'bin'
assert os.path.exists(os.path.join(tmpdir, 'some', 'path', bin_dir))
assert os.path.exists(os.path.join(tmpdir, 'some', 'path', 'my_data'))
def test_dist_info_contains_empty_dir(self, data, tmpdir):
"""
Test that empty dirs are not installed
"""
# e.g. https://github.com/pypa/pip/issues/1632#issuecomment-38027275
self.prep(data, tmpdir)
2014-04-25 23:42:14 +02:00
src_empty_dir = os.path.join(
self.src_dist_info, 'empty_dir', 'empty_dir')
os.makedirs(src_empty_dir)
assert os.path.isdir(src_empty_dir)
2019-10-12 03:31:35 +02:00
wheel.install_unpacked_wheel(
2019-10-12 04:24:50 +02:00
self.name,
self.src,
scheme=self.scheme,
req_description=str(self.req),
)
self.assert_installed()
2014-04-25 23:42:14 +02:00
assert not os.path.isdir(
os.path.join(self.dest_dist_info, 'empty_dir'))
class TestMessageAboutScriptsNotOnPATH(object):
tilde_warning_msg = (
"NOTE: The current PATH contains path(s) starting with `~`, "
"which may not be expanded by all applications."
)
def _template(self, paths, scripts):
with patch.dict('os.environ', {'PATH': os.pathsep.join(paths)}):
return wheel.message_about_scripts_not_on_PATH(scripts)
def test_no_script(self):
retval = self._template(
paths=['/a/b', '/c/d/bin'],
scripts=[]
)
assert retval is None
def test_single_script__single_dir_not_on_PATH(self):
retval = self._template(
paths=['/a/b', '/c/d/bin'],
scripts=['/c/d/foo']
)
assert retval is not None
assert "--no-warn-script-location" in retval
assert "foo is installed in '/c/d'" in retval
assert self.tilde_warning_msg not in retval
def test_two_script__single_dir_not_on_PATH(self):
retval = self._template(
paths=['/a/b', '/c/d/bin'],
scripts=['/c/d/foo', '/c/d/baz']
)
assert retval is not None
assert "--no-warn-script-location" in retval
assert "baz and foo are installed in '/c/d'" in retval
assert self.tilde_warning_msg not in retval
def test_multi_script__multi_dir_not_on_PATH(self):
retval = self._template(
paths=['/a/b', '/c/d/bin'],
scripts=['/c/d/foo', '/c/d/bar', '/c/d/baz', '/a/b/c/spam']
)
assert retval is not None
assert "--no-warn-script-location" in retval
assert "bar, baz and foo are installed in '/c/d'" in retval
assert "spam is installed in '/a/b/c'" in retval
assert self.tilde_warning_msg not in retval
def test_multi_script_all__multi_dir_not_on_PATH(self):
retval = self._template(
paths=['/a/b', '/c/d/bin'],
scripts=[
'/c/d/foo', '/c/d/bar', '/c/d/baz',
'/a/b/c/spam', '/a/b/c/eggs'
]
)
assert retval is not None
assert "--no-warn-script-location" in retval
assert "bar, baz and foo are installed in '/c/d'" in retval
assert "eggs and spam are installed in '/a/b/c'" in retval
assert self.tilde_warning_msg not in retval
def test_two_script__single_dir_on_PATH(self):
retval = self._template(
paths=['/a/b', '/c/d/bin'],
scripts=['/a/b/foo', '/a/b/baz']
)
assert retval is None
def test_multi_script__multi_dir_on_PATH(self):
retval = self._template(
paths=['/a/b', '/c/d/bin'],
scripts=['/a/b/foo', '/a/b/bar', '/a/b/baz', '/c/d/bin/spam']
)
assert retval is None
def test_multi_script__single_dir_on_PATH(self):
retval = self._template(
paths=['/a/b', '/c/d/bin'],
scripts=['/a/b/foo', '/a/b/bar', '/a/b/baz']
)
assert retval is None
def test_single_script__single_dir_on_PATH(self):
retval = self._template(
paths=['/a/b', '/c/d/bin'],
scripts=['/a/b/foo']
)
assert retval is None
def test_PATH_check_case_insensitive_on_windows(self):
retval = self._template(
paths=['C:\\A\\b'],
scripts=['c:\\a\\b\\c', 'C:/A/b/d']
)
if WINDOWS:
assert retval is None
else:
assert retval is not None
assert self.tilde_warning_msg not in retval
def test_trailing_ossep_removal(self):
retval = self._template(
paths=[os.path.join('a', 'b', '')],
scripts=[os.path.join('a', 'b', 'c')]
)
assert retval is None
def test_missing_PATH_env_treated_as_empty_PATH_env(self):
scripts = ['a/b/foo']
env = os.environ.copy()
del env['PATH']
with patch.dict('os.environ', env, clear=True):
retval_missing = wheel.message_about_scripts_not_on_PATH(scripts)
with patch.dict('os.environ', {'PATH': ''}):
retval_empty = wheel.message_about_scripts_not_on_PATH(scripts)
assert retval_missing == retval_empty
Add SHA256 hash of .whl as info output (#5908) * Add SHA256 hash of .whl as info output Currently I'm trying to debug some issues with what appear to be corrupt wheels. It would be very useful to see what pip thought the state of things was as it wrote the wheel output; if a final corrupt distributed file is then different to what pip has saved in its build logs, you know the problem is somewhere after pip but before distribution. Currently we get a log of the initial creation, then the stamp when it gets moved in the final output location, e.g.: creating '/tmp/pip-wheel-71CpBe/foo-1.2.3-py2.py3-none-any.whl ... Stored in directory: /opt/wheel/workspace A lot happens in between this, so my suggestion is we add the final output file and it's hash before the "Stored in directory:", e.g. you now see: Building wheels for collected packages: simple Running setup.py bdist_wheel for simple: started Running setup.py bdist_wheel for simple: finished with status 'done' Finished: simple-3.0-py3-none-any.whl sha256=39005a57a6327972575072af82e11d0817439fe6a069381f6f2a123a8c0bf1cf Stored in directory: /tmp/pytest-of-iwienand/pytest-18/test_pip_wheel_success0/workspace/scratch Successfully built simple Despite the hash being fairly important for things like --require-hashes, AFAICS the final hash is not put in the logs at all currently, so I think this is generically helpful. * Reword wheel hash details output This rewords the output to be more like the form of the preceding messages. Additionally the size is added, since we have calculated it anyway. The output will now look like: Collecting simple==3.0 Building wheels for collected packages: simple Building wheel for simple (setup.py): started Building wheel for simple (setup.py): finished with status 'done' Created wheel for simple: filename=simple-3.0-py3-none-any.whl size=1138 sha256=2a980a802c9d38a24d29aded2dc2df2b080e58370902e5fdf950090ff67aec10 Stored in directory: /tmp/pytest-of-iwienand/pytest-0/test_pip_wheel_success0/workspace/scratch Successfully built simple
2019-06-26 11:44:43 +02:00
def test_no_script_tilde_in_path(self):
retval = self._template(
paths=['/a/b', '/c/d/bin', '~/e', '/f/g~g'],
scripts=[]
)
assert retval is None
def test_multi_script_all_tilde__multi_dir_not_on_PATH(self):
retval = self._template(
paths=['/a/b', '/c/d/bin', '~e/f'],
scripts=[
'/c/d/foo', '/c/d/bar', '/c/d/baz',
'/a/b/c/spam', '/a/b/c/eggs', '/e/f/tilde'
]
)
assert retval is not None
assert "--no-warn-script-location" in retval
assert "bar, baz and foo are installed in '/c/d'" in retval
assert "eggs and spam are installed in '/a/b/c'" in retval
assert "tilde is installed in '/e/f'" in retval
assert self.tilde_warning_msg in retval
def test_multi_script_all_tilde_not_at_start__multi_dir_not_on_PATH(self):
retval = self._template(
paths=['/e/f~f', '/c/d/bin'],
scripts=[
'/c/d/foo', '/c/d/bar', '/c/d/baz',
'/e/f~f/c/spam', '/e/f~f/c/eggs'
]
)
assert retval is not None
assert "--no-warn-script-location" in retval
assert "bar, baz and foo are installed in '/c/d'" in retval
assert "eggs and spam are installed in '/e/f~f/c'" in retval
assert self.tilde_warning_msg not in retval
Add SHA256 hash of .whl as info output (#5908) * Add SHA256 hash of .whl as info output Currently I'm trying to debug some issues with what appear to be corrupt wheels. It would be very useful to see what pip thought the state of things was as it wrote the wheel output; if a final corrupt distributed file is then different to what pip has saved in its build logs, you know the problem is somewhere after pip but before distribution. Currently we get a log of the initial creation, then the stamp when it gets moved in the final output location, e.g.: creating '/tmp/pip-wheel-71CpBe/foo-1.2.3-py2.py3-none-any.whl ... Stored in directory: /opt/wheel/workspace A lot happens in between this, so my suggestion is we add the final output file and it's hash before the "Stored in directory:", e.g. you now see: Building wheels for collected packages: simple Running setup.py bdist_wheel for simple: started Running setup.py bdist_wheel for simple: finished with status 'done' Finished: simple-3.0-py3-none-any.whl sha256=39005a57a6327972575072af82e11d0817439fe6a069381f6f2a123a8c0bf1cf Stored in directory: /tmp/pytest-of-iwienand/pytest-18/test_pip_wheel_success0/workspace/scratch Successfully built simple Despite the hash being fairly important for things like --require-hashes, AFAICS the final hash is not put in the logs at all currently, so I think this is generically helpful. * Reword wheel hash details output This rewords the output to be more like the form of the preceding messages. Additionally the size is added, since we have calculated it anyway. The output will now look like: Collecting simple==3.0 Building wheels for collected packages: simple Building wheel for simple (setup.py): started Building wheel for simple (setup.py): finished with status 'done' Created wheel for simple: filename=simple-3.0-py3-none-any.whl size=1138 sha256=2a980a802c9d38a24d29aded2dc2df2b080e58370902e5fdf950090ff67aec10 Stored in directory: /tmp/pytest-of-iwienand/pytest-0/test_pip_wheel_success0/workspace/scratch Successfully built simple
2019-06-26 11:44:43 +02:00
class TestWheelHashCalculators(object):
def prep(self, tmpdir):
self.test_file = tmpdir.joinpath("hash.file")
Add SHA256 hash of .whl as info output (#5908) * Add SHA256 hash of .whl as info output Currently I'm trying to debug some issues with what appear to be corrupt wheels. It would be very useful to see what pip thought the state of things was as it wrote the wheel output; if a final corrupt distributed file is then different to what pip has saved in its build logs, you know the problem is somewhere after pip but before distribution. Currently we get a log of the initial creation, then the stamp when it gets moved in the final output location, e.g.: creating '/tmp/pip-wheel-71CpBe/foo-1.2.3-py2.py3-none-any.whl ... Stored in directory: /opt/wheel/workspace A lot happens in between this, so my suggestion is we add the final output file and it's hash before the "Stored in directory:", e.g. you now see: Building wheels for collected packages: simple Running setup.py bdist_wheel for simple: started Running setup.py bdist_wheel for simple: finished with status 'done' Finished: simple-3.0-py3-none-any.whl sha256=39005a57a6327972575072af82e11d0817439fe6a069381f6f2a123a8c0bf1cf Stored in directory: /tmp/pytest-of-iwienand/pytest-18/test_pip_wheel_success0/workspace/scratch Successfully built simple Despite the hash being fairly important for things like --require-hashes, AFAICS the final hash is not put in the logs at all currently, so I think this is generically helpful. * Reword wheel hash details output This rewords the output to be more like the form of the preceding messages. Additionally the size is added, since we have calculated it anyway. The output will now look like: Collecting simple==3.0 Building wheels for collected packages: simple Building wheel for simple (setup.py): started Building wheel for simple (setup.py): finished with status 'done' Created wheel for simple: filename=simple-3.0-py3-none-any.whl size=1138 sha256=2a980a802c9d38a24d29aded2dc2df2b080e58370902e5fdf950090ff67aec10 Stored in directory: /tmp/pytest-of-iwienand/pytest-0/test_pip_wheel_success0/workspace/scratch Successfully built simple
2019-06-26 11:44:43 +02:00
# Want this big enough to trigger the internal read loops.
self.test_file_len = 2 * 1024 * 1024
with open(str(self.test_file), "w") as fp:
fp.truncate(self.test_file_len)
self.test_file_hash = \
'5647f05ec18958947d32874eeb788fa396a05d0bab7c1b71f112ceb7e9b31eee'
self.test_file_hash_encoded = \
'sha256=VkfwXsGJWJR9ModO63iPo5agXQurfBtx8RLOt-mzHu4'
def test_hash_file(self, tmpdir):
self.prep(tmpdir)
h, length = hash_file(self.test_file)
Add SHA256 hash of .whl as info output (#5908) * Add SHA256 hash of .whl as info output Currently I'm trying to debug some issues with what appear to be corrupt wheels. It would be very useful to see what pip thought the state of things was as it wrote the wheel output; if a final corrupt distributed file is then different to what pip has saved in its build logs, you know the problem is somewhere after pip but before distribution. Currently we get a log of the initial creation, then the stamp when it gets moved in the final output location, e.g.: creating '/tmp/pip-wheel-71CpBe/foo-1.2.3-py2.py3-none-any.whl ... Stored in directory: /opt/wheel/workspace A lot happens in between this, so my suggestion is we add the final output file and it's hash before the "Stored in directory:", e.g. you now see: Building wheels for collected packages: simple Running setup.py bdist_wheel for simple: started Running setup.py bdist_wheel for simple: finished with status 'done' Finished: simple-3.0-py3-none-any.whl sha256=39005a57a6327972575072af82e11d0817439fe6a069381f6f2a123a8c0bf1cf Stored in directory: /tmp/pytest-of-iwienand/pytest-18/test_pip_wheel_success0/workspace/scratch Successfully built simple Despite the hash being fairly important for things like --require-hashes, AFAICS the final hash is not put in the logs at all currently, so I think this is generically helpful. * Reword wheel hash details output This rewords the output to be more like the form of the preceding messages. Additionally the size is added, since we have calculated it anyway. The output will now look like: Collecting simple==3.0 Building wheels for collected packages: simple Building wheel for simple (setup.py): started Building wheel for simple (setup.py): finished with status 'done' Created wheel for simple: filename=simple-3.0-py3-none-any.whl size=1138 sha256=2a980a802c9d38a24d29aded2dc2df2b080e58370902e5fdf950090ff67aec10 Stored in directory: /tmp/pytest-of-iwienand/pytest-0/test_pip_wheel_success0/workspace/scratch Successfully built simple
2019-06-26 11:44:43 +02:00
assert length == self.test_file_len
assert h.hexdigest() == self.test_file_hash
def test_rehash(self, tmpdir):
self.prep(tmpdir)
h, length = wheel.rehash(self.test_file)
assert length == str(self.test_file_len)
assert h == self.test_file_hash_encoded
class TestWheelCommand(object):
def test_save_wheelnames(self, tmpdir):
wheel_filenames = ['Flask-1.1.dev0-py2.py3-none-any.whl']
links_filenames = [
'flask',
'Werkzeug-0.15.4-py2.py3-none-any.whl',
'Jinja2-2.10.1-py2.py3-none-any.whl',
'itsdangerous-1.1.0-py2.py3-none-any.whl',
'Click-7.0-py2.py3-none-any.whl'
]
expected = wheel_filenames + links_filenames[1:]
expected = [filename + '\n' for filename in expected]
temp_file = tmpdir.joinpath('wheelfiles')
WheelCommand('name', 'summary').save_wheelnames(
links_filenames,
temp_file,
wheel_filenames
)
with open(temp_file, 'r') as f:
test_content = f.readlines()
assert test_content == expected