"""'pip wheel' tests""" import os import re import sys from os.path import exists import pytest from pip._internal.cli.status_codes import ERROR, PREVIOUS_BUILD_DIR_ERROR from tests.lib import pyversion # noqa: F401 @pytest.fixture(autouse=True) def auto_with_wheel(with_wheel): pass def add_files_to_dist_directory(folder): (folder / 'dist').mkdir(parents=True) (folder / 'dist' / 'a_name-0.0.1.tar.gz').write_text("hello") # Not adding a wheel file since that confuses setuptools' backend. # (folder / 'dist' / 'a_name-0.0.1-py2.py3-none-any.whl').write_text( # "hello" # ) def test_wheel_exit_status_code_when_no_requirements(script): """ Test wheel exit status code when no requirements specified """ result = script.pip('wheel', expect_error=True) assert "You must give at least one requirement to wheel" in result.stderr assert result.returncode == ERROR def test_wheel_exit_status_code_when_blank_requirements_file(script): """ Test wheel exit status code when blank requirements file specified """ script.scratch_path.joinpath("blank.txt").write_text("\n") script.pip('wheel', '-r', 'blank.txt') def test_pip_wheel_success(script, data): """ Test 'pip wheel' success. """ result = script.pip( 'wheel', '--no-index', '-f', data.find_links, 'simple==3.0', ) wheel_file_name = 'simple-3.0-py{pyversion[0]}-none-any.whl' \ .format(**globals()) wheel_file_path = script.scratch / wheel_file_name assert re.search( r"Created wheel for simple: " r"filename={filename} size=\d+ sha256=[A-Fa-f0-9]{{64}}" .format(filename=re.escape(wheel_file_name)), result.stdout) assert re.search( r"^\s+Stored in directory: ", result.stdout, re.M) result.did_create(wheel_file_path) assert "Successfully built simple" in result.stdout, result.stdout def test_pip_wheel_build_cache(script, data): """ Test 'pip wheel' builds and caches. """ result = script.pip( 'wheel', '--no-index', '-f', data.find_links, 'simple==3.0', ) wheel_file_name = 'simple-3.0-py{pyversion[0]}-none-any.whl' \ .format(**globals()) wheel_file_path = script.scratch / wheel_file_name result.did_create(wheel_file_path) assert "Successfully built simple" in result.stdout, result.stdout # remove target file (script.scratch_path / wheel_file_name).unlink() # pip wheel again and test that no build occurs since # we get the wheel from cache result = script.pip( 'wheel', '--no-index', '-f', data.find_links, 'simple==3.0', ) result.did_create(wheel_file_path) assert "Successfully built simple" not in result.stdout, result.stdout def test_basic_pip_wheel_downloads_wheels(script, data): """ Test 'pip wheel' downloads wheels """ result = script.pip( 'wheel', '--no-index', '-f', data.find_links, 'simple.dist', ) wheel_file_name = 'simple.dist-0.1-py2.py3-none-any.whl' wheel_file_path = script.scratch / wheel_file_name result.did_create(wheel_file_path) assert "Saved" in result.stdout, result.stdout def test_pip_wheel_build_relative_cachedir(script, data): """ Test 'pip wheel' builds and caches with a non-absolute cache directory. """ result = script.pip( 'wheel', '--no-index', '-f', data.find_links, '--cache-dir', './cache', 'simple==3.0', ) assert result.returncode == 0 def test_pip_wheel_builds_when_no_binary_set(script, data): data.packages.joinpath('simple-3.0-py2.py3-none-any.whl').touch() # Check that the wheel package is ignored res = script.pip( 'wheel', '--no-index', '--no-binary', ':all:', '-f', data.find_links, 'simple==3.0') assert "Building wheel for simple" in str(res), str(res) @pytest.mark.skipif("sys.platform == 'win32'") def test_pip_wheel_readonly_cache(script, data, tmpdir): cache_dir = tmpdir / "cache" cache_dir.mkdir() os.chmod(cache_dir, 0o400) # read-only cache # Check that the wheel package is ignored res = script.pip( 'wheel', '--no-index', '-f', data.find_links, '--cache-dir', cache_dir, 'simple==3.0', allow_stderr_warning=True, ) assert res.returncode == 0 assert "The cache has been disabled." in str(res), str(res) def test_pip_wheel_builds_editable_deps(script, data): """ Test 'pip wheel' finds and builds dependencies of editables """ editable_path = os.path.join(data.src, 'requires_simple') result = script.pip( 'wheel', '--no-index', '-f', data.find_links, '-e', editable_path ) wheel_file_name = 'simple-1.0-py{pyversion[0]}-none-any.whl' \ .format(**globals()) wheel_file_path = script.scratch / wheel_file_name result.did_create(wheel_file_path) def test_pip_wheel_builds_editable(script, data): """ Test 'pip wheel' builds an editable package """ editable_path = os.path.join(data.src, 'simplewheel-1.0') result = script.pip( 'wheel', '--no-index', '-f', data.find_links, '-e', editable_path ) wheel_file_name = 'simplewheel-1.0-py{pyversion[0]}-none-any.whl' \ .format(**globals()) wheel_file_path = script.scratch / wheel_file_name result.did_create(wheel_file_path) def test_pip_wheel_fail(script, data): """ Test 'pip wheel' failure. """ result = script.pip( 'wheel', '--no-index', '-f', data.find_links, 'wheelbroken==0.1', expect_error=True, ) wheel_file_name = 'wheelbroken-0.1-py{pyversion[0]}-none-any.whl' \ .format(**globals()) wheel_file_path = script.scratch / wheel_file_name result.did_not_create(wheel_file_path) assert "FakeError" in result.stderr, result.stderr assert "Failed to build wheelbroken" in result.stdout, result.stdout assert result.returncode != 0 def test_no_clean_option_blocks_cleaning_after_wheel( script, data, use_new_resolver, ): """ Test --no-clean option blocks cleaning after wheel build """ build = script.venv_path / 'build' result = script.pip( 'wheel', '--no-clean', '--no-index', '--build', build, '--find-links={data.find_links}'.format(**locals()), 'simple', expect_temp=True, # TODO: allow_stderr_warning is used for the --build deprecation, # remove it when removing support for --build allow_stderr_warning=True, ) if not use_new_resolver: build = build / 'simple' message = "build/simple should still exist {}".format(result) assert exists(build), message def test_pip_wheel_source_deps(script, data): """ Test 'pip wheel' finds and builds source archive dependencies of wheels """ # 'requires_source' is a wheel that depends on the 'source' project result = script.pip( 'wheel', '--no-index', '-f', data.find_links, 'requires_source', ) wheel_file_name = 'source-1.0-py{pyversion[0]}-none-any.whl' \ .format(**globals()) wheel_file_path = script.scratch / wheel_file_name result.did_create(wheel_file_path) assert "Successfully built source" in result.stdout, result.stdout def test_pip_wheel_fail_cause_of_previous_build_dir( script, data, use_new_resolver, ): """ Test when 'pip wheel' tries to install a package that has a previous build directory """ # Given that I have a previous build dir of the `simple` package build = script.venv_path / 'build' / 'simple' os.makedirs(build) build.joinpath('setup.py').write_text('#') # When I call pip trying to install things again result = script.pip( 'wheel', '--no-index', '--find-links={data.find_links}'.format(**locals()), '--build', script.venv_path / 'build', 'simple==3.0', expect_error=(not use_new_resolver), expect_temp=(not use_new_resolver), expect_stderr=True, ) assert ( "The -b/--build/--build-dir/--build-directory " "option is deprecated." ) in result.stderr # Then I see that the error code is the right one if not use_new_resolver: assert result.returncode == PREVIOUS_BUILD_DIR_ERROR, result def test_wheel_package_with_latin1_setup(script, data): """Create a wheel from a package with latin-1 encoded setup.py.""" pkg_to_wheel = data.packages.joinpath("SetupPyLatin1") result = script.pip('wheel', pkg_to_wheel) assert 'Successfully built SetupPyUTF8' in result.stdout def test_pip_wheel_with_pep518_build_reqs(script, data, common_wheels): result = script.pip('wheel', '--no-index', '-f', data.find_links, '-f', common_wheels, 'pep518==3.0',) wheel_file_name = 'pep518-3.0-py{pyversion[0]}-none-any.whl' \ .format(**globals()) wheel_file_path = script.scratch / wheel_file_name result.did_create(wheel_file_path) assert "Successfully built pep518" in result.stdout, result.stdout assert "Installing build dependencies" in result.stdout, result.stdout def test_pip_wheel_with_pep518_build_reqs_no_isolation(script, data): script.pip_install_local('simplewheel==2.0') result = script.pip( 'wheel', '--no-index', '-f', data.find_links, '--no-build-isolation', 'pep518==3.0', ) wheel_file_name = 'pep518-3.0-py{pyversion[0]}-none-any.whl' \ .format(**globals()) wheel_file_path = script.scratch / wheel_file_name result.did_create(wheel_file_path) assert "Successfully built pep518" in result.stdout, result.stdout assert "Installing build dependencies" not in result.stdout, result.stdout def test_pip_wheel_with_user_set_in_config(script, data, common_wheels): config_file = script.scratch_path / 'pip.conf' script.environ['PIP_CONFIG_FILE'] = str(config_file) config_file.write_text("[install]\nuser = true") result = script.pip( 'wheel', data.src / 'withpyproject', '--no-index', '-f', common_wheels ) assert "Successfully built withpyproject" in result.stdout, result.stdout @pytest.mark.skipif(sys.platform.startswith('win'), reason='The empty extension module does not work on Win') def test_pip_wheel_ext_module_with_tmpdir_inside(script, data, common_wheels): tmpdir = data.src / 'extension/tmp' tmpdir.mkdir() script.environ['TMPDIR'] = str(tmpdir) # To avoid a test dependency on a C compiler, we set the env vars to "noop" # The .c source is empty anyway script.environ['CC'] = script.environ['LDSHARED'] = str('true') result = script.pip( 'wheel', data.src / 'extension', '--no-index', '-f', common_wheels ) assert "Successfully built extension" in result.stdout, result.stdout @pytest.mark.network def test_pep517_wheels_are_not_confused_with_other_files(script, tmpdir, data): """Check correct wheels are copied. (#6196) """ pkg_to_wheel = data.src / 'withpyproject' add_files_to_dist_directory(pkg_to_wheel) result = script.pip('wheel', pkg_to_wheel, '-w', script.scratch_path) assert "Installing build dependencies" in result.stdout, result.stdout wheel_file_name = 'withpyproject-0.0.1-py{pyversion[0]}-none-any.whl' \ .format(**globals()) wheel_file_path = script.scratch / wheel_file_name result.did_create(wheel_file_path) def test_legacy_wheels_are_not_confused_with_other_files(script, tmpdir, data): """Check correct wheels are copied. (#6196) """ pkg_to_wheel = data.src / 'simplewheel-1.0' add_files_to_dist_directory(pkg_to_wheel) result = script.pip('wheel', pkg_to_wheel, '-w', script.scratch_path) assert "Installing build dependencies" not in result.stdout, result.stdout wheel_file_name = 'simplewheel-1.0-py{pyversion[0]}-none-any.whl' \ .format(**globals()) wheel_file_path = script.scratch / wheel_file_name result.did_create(wheel_file_path)