Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Step:15
salt
set-default-target-for-pip-from-venv_pip_target...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File set-default-target-for-pip-from-venv_pip_target-envi.patch of Package salt
From 003266fc86c1364a41ac4bd35207290c036151a0 Mon Sep 17 00:00:00 2001 From: Victor Zhestkov <vzhestkov@suse.com> Date: Mon, 27 Jun 2022 18:02:31 +0300 Subject: [PATCH] Set default target for pip from VENV_PIP_TARGET environment variable * Use VENV_PIP_TARGET as a target for pkg.install if set and no target specified on the call * Add test for VENV_PIP_TARGET environment variable * Changelog entry --- changelog/62089.changed | 1 + salt/modules/pip.py | 6 + tests/pytests/unit/modules/test_pip.py | 1806 ++++++++++++++++++++++++ 3 files changed, 1813 insertions(+) create mode 100644 changelog/62089.changed create mode 100644 tests/pytests/unit/modules/test_pip.py diff --git a/changelog/62089.changed b/changelog/62089.changed new file mode 100644 index 0000000000..09feb2e922 --- /dev/null +++ b/changelog/62089.changed @@ -0,0 +1 @@ +Use VENV_PIP_TARGET environment variable as a default target for pip if present. diff --git a/salt/modules/pip.py b/salt/modules/pip.py index da26416662..9410024fd5 100644 --- a/salt/modules/pip.py +++ b/salt/modules/pip.py @@ -858,6 +858,12 @@ def install( if build: cmd.extend(["--build", build]) + # Use VENV_PIP_TARGET environment variable value as target + # if set and no target specified on the function call + target_env = os.environ.get("VENV_PIP_TARGET", None) + if target is None and target_env is not None: + target = target_env + if target: cmd.extend(["--target", target]) diff --git a/tests/pytests/unit/modules/test_pip.py b/tests/pytests/unit/modules/test_pip.py new file mode 100644 index 0000000000..ae9005d806 --- /dev/null +++ b/tests/pytests/unit/modules/test_pip.py @@ -0,0 +1,1806 @@ +import os +import sys + +import pytest +import salt.modules.pip as pip +import salt.utils.files +import salt.utils.platform +from salt.exceptions import CommandExecutionError +from tests.support.mock import MagicMock, patch + + +class FakeFopen: + def __init__(self, filename): + d = { + "requirements-0.txt": ( + b"--index-url http://fake.com/simple\n\n" + b"one # -r wrong.txt, other\n" + b"two # --requirement wrong.exe;some\n" + b"three\n" + b"-r requirements-1.txt\n" + b"# nothing\n" + ), + "requirements-1.txt": ( + "four\n" + "five\n" + "--requirement=requirements-2.txt\t# --requirements-2.txt\n\n" + ), + "requirements-2.txt": b"""six""", + "requirements-3.txt": ( + b"# some comment\n" + b"-e git+ssh://git.example.com/MyProject#egg=MyProject # the project\n" + b"seven\n" + b"-e git+ssh://git.example.com/Example#egg=example\n" + b"eight # -e something#or other\n" + b"--requirement requirements-4.txt\n\n" + ), + "requirements-4.txt": "", + } + self.val = d[filename] + + def __enter__(self): + return self + + def __exit__(self, *args, **kwargs): + pass + + def read(self): + return self.val + + +@pytest.fixture +def expected_user(): + return "fnord" + + +@pytest.fixture +def configure_loader_modules(): + return {pip: {"__salt__": {"cmd.which_bin": lambda _: "pip"}}} + + +def test__pip_bin_env(): + ret = pip._pip_bin_env(None, "C:/Users/ch44d/Documents/salt/tests/pip.exe") + if salt.utils.platform.is_windows(): + assert ret == "C:/Users/ch44d/Documents/salt/tests" + else: + assert ret is None + + +def test__pip_bin_env_no_change(): + cwd = "C:/Users/ch44d/Desktop" + ret = pip._pip_bin_env(cwd, "C:/Users/ch44d/Documents/salt/tests/pip.exe") + assert ret == cwd + + +def test__pip_bin_env_no_bin_env(): + ret = pip._pip_bin_env(None, None) + assert ret is None + + +def test_install_frozen_app(): + pkg = "pep8" + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch("sys.frozen", True, create=True): + with patch("sys._MEIPASS", True, create=True): + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(pkg) + expected = [ + sys.executable, + "pip", + "install", + pkg, + ] + mock.assert_called_with( + expected, + python_shell=False, + saltenv="base", + use_vt=False, + runas=None, + ) + + +def test_install_source_app(): + pkg = "pep8" + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch("sys.frozen", False, create=True): + with patch("sys._MEIPASS", False, create=True): + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(pkg) + expected = [ + sys.executable, + "-m", + "pip", + "install", + pkg, + ] + mock.assert_called_with( + expected, + python_shell=False, + saltenv="base", + use_vt=False, + runas=None, + ) + + +def test_fix4361(): + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(requirements="requirements.txt") + expected_cmd = [ + sys.executable, + "-m", + "pip", + "install", + "--requirement", + "requirements.txt", + ] + mock.assert_called_with( + expected_cmd, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + +def test_install_editable_without_egg_fails(): + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pytest.raises( + CommandExecutionError, + pip.install, + editable="git+https://github.com/saltstack/salt-testing.git", + ) + + +def test_install_multiple_editable(): + editables = [ + "git+https://github.com/jek/blinker.git#egg=Blinker", + "git+https://github.com/saltstack/salt-testing.git#egg=SaltTesting", + ] + + expected = [sys.executable, "-m", "pip", "install"] + for item in editables: + expected.extend(["--editable", item]) + + # Passing editables as a list + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(editable=editables) + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + # Passing editables as a comma separated list + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(editable=",".join(editables)) + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + +def test_install_multiple_pkgs_and_editables(): + pkgs = ["pep8", "salt"] + editables = [ + "git+https://github.com/jek/blinker.git#egg=Blinker", + "git+https://github.com/saltstack/salt-testing.git#egg=SaltTesting", + ] + + expected = [sys.executable, "-m", "pip", "install"] + expected.extend(pkgs) + for item in editables: + expected.extend(["--editable", item]) + + # Passing editables as a list + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(pkgs=pkgs, editable=editables) + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + # Passing editables as a comma separated list + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(pkgs=",".join(pkgs), editable=",".join(editables)) + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + # As single string (just use the first element from pkgs and editables) + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(pkgs=pkgs[0], editable=editables[0]) + expected = [ + sys.executable, + "-m", + "pip", + "install", + pkgs[0], + "--editable", + editables[0], + ] + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + +def test_issue5940_install_multiple_pip_mirrors(): + """ + test multiple pip mirrors. This test only works with pip < 7.0.0 + """ + with patch.object(pip, "version", MagicMock(return_value="1.4")): + mirrors = [ + "http://g.pypi.python.org", + "http://c.pypi.python.org", + "http://pypi.crate.io", + ] + + expected = [sys.executable, "-m", "pip", "install", "--use-mirrors"] + for item in mirrors: + expected.extend(["--mirrors", item]) + expected.append("pep8") + + # Passing mirrors as a list + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(pkgs=["pep8"], mirrors=mirrors) + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + # Passing mirrors as a comma separated list + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(pkgs=["pep8"], mirrors=",".join(mirrors)) + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + expected = [ + sys.executable, + "-m", + "pip", + "install", + "--use-mirrors", + "--mirrors", + mirrors[0], + "pep8", + ] + + # As single string (just use the first element from mirrors) + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(pkgs=["pep8"], mirrors=mirrors[0]) + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + +def test_install_with_multiple_find_links(): + find_links = [ + "http://g.pypi.python.org", + "http://c.pypi.python.org", + "http://pypi.crate.io", + ] + pkg = "pep8" + + expected = [sys.executable, "-m", "pip", "install"] + for item in find_links: + expected.extend(["--find-links", item]) + expected.append(pkg) + + # Passing mirrors as a list + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(pkg, find_links=find_links) + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + # Passing mirrors as a comma separated list + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(pkg, find_links=",".join(find_links)) + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + # Valid protos work? + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(pkg, find_links=find_links) + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + expected = [ + sys.executable, + "-m", + "pip", + "install", + "--find-links", + find_links[0], + pkg, + ] + + # As single string (just use the first element from find_links) + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(pkg, find_links=find_links[0]) + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + # Invalid proto raises exception + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pytest.raises( + CommandExecutionError, + pip.install, + "'" + pkg + "'", + find_links="sftp://pypi.crate.io", + ) + + +def test_install_no_index_with_index_url_or_extra_index_url_raises(): + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pytest.raises( + CommandExecutionError, + pip.install, + no_index=True, + index_url="http://foo.tld", + ) + + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pytest.raises( + CommandExecutionError, + pip.install, + no_index=True, + extra_index_url="http://foo.tld", + ) + + +def test_install_failed_cached_requirements(): + with patch("salt.modules.pip._get_cached_requirements") as get_cached_requirements: + get_cached_requirements.return_value = False + ret = pip.install(requirements="salt://my_test_reqs") + assert False is ret["result"] + assert "my_test_reqs" in ret["comment"] + + +def test_install_cached_requirements_used(): + with patch("salt.modules.pip._get_cached_requirements") as get_cached_requirements: + get_cached_requirements.return_value = "my_cached_reqs" + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(requirements="salt://requirements.txt") + expected = [ + sys.executable, + "-m", + "pip", + "install", + "--requirement", + "my_cached_reqs", + ] + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + +def test_install_venv(): + with patch("os.path") as mock_path: + + def join(*args): + return os.path.normpath(os.sep.join(args)) + + mock_path.is_file.return_value = True + mock_path.isdir.return_value = True + mock_path.join = join + + if salt.utils.platform.is_windows(): + venv_path = "C:\\test_env" + bin_path = os.path.join(venv_path, "python.exe") + else: + venv_path = "/test_env" + bin_path = os.path.join(venv_path, "python") + + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + pip_bin = MagicMock(return_value=[bin_path, "-m", "pip"]) + + with patch.dict(pip.__salt__, {"cmd.run_all": mock}), patch.object( + pip, "_get_pip_bin", pip_bin + ): + pip.install("mock", bin_env=venv_path) + mock.assert_called_with( + [bin_path, "-m", "pip", "install", "mock"], + env={"VIRTUAL_ENV": venv_path}, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + +def test_install_log_argument_in_resulting_command(): + with patch("os.access") as mock_path: + pkg = "pep8" + log_path = "/tmp/pip-install.log" + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(pkg, log=log_path) + expected = [ + sys.executable, + "-m", + "pip", + "install", + "--log", + log_path, + pkg, + ] + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + +def test_non_writeable_log(): + with patch("os.path") as mock_path: + # Let's fake a non-writable log file + pkg = "pep8" + log_path = "/tmp/pip-install.log" + mock_path.exists.side_effect = IOError("Fooo!") + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pytest.raises(IOError, pip.install, pkg, log=log_path) + + +def test_install_timeout_argument_in_resulting_command(): + # Passing an int + pkg = "pep8" + expected = [sys.executable, "-m", "pip", "install", "--timeout"] + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(pkg, timeout=10) + mock.assert_called_with( + expected + [10, pkg], + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + # Passing an int as a string + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(pkg, timeout="10") + mock.assert_called_with( + expected + ["10", pkg], + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + # Passing a non-int to timeout + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pytest.raises(ValueError, pip.install, pkg, timeout="a") + + +def test_install_index_url_argument_in_resulting_command(): + pkg = "pep8" + index_url = "http://foo.tld" + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(pkg, index_url=index_url) + expected = [ + sys.executable, + "-m", + "pip", + "install", + "--index-url", + index_url, + pkg, + ] + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + +def test_install_extra_index_url_argument_in_resulting_command(): + pkg = "pep8" + extra_index_url = "http://foo.tld" + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(pkg, extra_index_url=extra_index_url) + expected = [ + sys.executable, + "-m", + "pip", + "install", + "--extra-index-url", + extra_index_url, + pkg, + ] + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + +def test_install_no_index_argument_in_resulting_command(): + pkg = "pep8" + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(pkg, no_index=True) + expected = [sys.executable, "-m", "pip", "install", "--no-index", pkg] + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + +def test_install_build_argument_in_resulting_command(): + pkg = "pep8" + build = "/tmp/foo" + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(pkg, build=build) + expected = [sys.executable, "-m", "pip", "install", "--build", build, pkg] + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + +def test_install_target_argument_in_resulting_command(): + pkg = "pep8" + target = "/tmp/foo" + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(pkg, target=target) + expected = [sys.executable, "-m", "pip", "install", "--target", target, pkg] + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + +def test_install_download_argument_in_resulting_command(): + pkg = "pep8" + download = "/tmp/foo" + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(pkg, download=download) + expected = [ + sys.executable, + "-m", + "pip", + "install", + "--download", + download, + pkg, + ] + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + +def test_install_no_download_argument_in_resulting_command(): + pkg = "pep8" + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(pkg, no_download=True) + expected = [sys.executable, "-m", "pip", "install", "--no-download", pkg] + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + +def test_install_download_cache_dir_arguments_in_resulting_command(): + pkg = "pep8" + cache_dir_arg_mapping = { + "1.5.6": "--download-cache", + "6.0": "--cache-dir", + } + download_cache = "/tmp/foo" + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + for pip_version, cmd_arg in cache_dir_arg_mapping.items(): + with patch("salt.modules.pip.version", MagicMock(return_value=pip_version)): + # test `download_cache` kwarg + pip.install(pkg, download_cache="/tmp/foo") + expected = [ + sys.executable, + "-m", + "pip", + "install", + cmd_arg, + download_cache, + pkg, + ] + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + # test `cache_dir` kwarg + pip.install(pkg, cache_dir="/tmp/foo") + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + +def test_install_source_argument_in_resulting_command(): + pkg = "pep8" + source = "/tmp/foo" + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(pkg, source=source) + expected = [sys.executable, "-m", "pip", "install", "--source", source, pkg] + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + +def test_install_exists_action_argument_in_resulting_command(): + pkg = "pep8" + for action in ("s", "i", "w", "b"): + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(pkg, exists_action=action) + expected = [ + sys.executable, + "-m", + "pip", + "install", + "--exists-action", + action, + pkg, + ] + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + # Test for invalid action + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pytest.raises(CommandExecutionError, pip.install, pkg, exists_action="d") + + +def test_install_install_options_argument_in_resulting_command(): + install_options = ["--exec-prefix=/foo/bar", "--install-scripts=/foo/bar/bin"] + pkg = "pep8" + + expected = [sys.executable, "-m", "pip", "install"] + for item in install_options: + expected.extend(["--install-option", item]) + expected.append(pkg) + + # Passing options as a list + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(pkg, install_options=install_options) + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + # Passing mirrors as a comma separated list + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(pkg, install_options=",".join(install_options)) + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + # Passing mirrors as a single string entry + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(pkg, install_options=install_options[0]) + expected = [ + sys.executable, + "-m", + "pip", + "install", + "--install-option", + install_options[0], + pkg, + ] + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + +def test_install_global_options_argument_in_resulting_command(): + global_options = ["--quiet", "--no-user-cfg"] + pkg = "pep8" + + expected = [sys.executable, "-m", "pip", "install"] + for item in global_options: + expected.extend(["--global-option", item]) + expected.append(pkg) + + # Passing options as a list + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(pkg, global_options=global_options) + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + # Passing mirrors as a comma separated list + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(pkg, global_options=",".join(global_options)) + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + # Passing mirrors as a single string entry + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(pkg, global_options=global_options[0]) + expected = [ + sys.executable, + "-m", + "pip", + "install", + "--global-option", + global_options[0], + pkg, + ] + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + +def test_install_upgrade_argument_in_resulting_command(): + pkg = "pep8" + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(pkg, upgrade=True) + expected = [sys.executable, "-m", "pip", "install", "--upgrade", pkg] + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + +def test_install_force_reinstall_argument_in_resulting_command(): + pkg = "pep8" + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(pkg, force_reinstall=True) + expected = [ + sys.executable, + "-m", + "pip", + "install", + "--force-reinstall", + pkg, + ] + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + +def test_install_ignore_installed_argument_in_resulting_command(): + pkg = "pep8" + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(pkg, ignore_installed=True) + expected = [ + sys.executable, + "-m", + "pip", + "install", + "--ignore-installed", + pkg, + ] + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + +def test_install_no_deps_argument_in_resulting_command(): + pkg = "pep8" + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(pkg, no_deps=True) + expected = [sys.executable, "-m", "pip", "install", "--no-deps", pkg] + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + +def test_install_no_install_argument_in_resulting_command(): + pkg = "pep8" + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(pkg, no_install=True) + expected = [sys.executable, "-m", "pip", "install", "--no-install", pkg] + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + +def test_install_proxy_argument_in_resulting_command(): + pkg = "pep8" + proxy = "salt-user:salt-passwd@salt-proxy:3128" + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(pkg, proxy=proxy) + expected = [sys.executable, "-m", "pip", "install", "--proxy", proxy, pkg] + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + +def test_install_proxy_false_argument_in_resulting_command(): + """ + Checking that there is no proxy set if proxy arg is set to False + even if the global proxy is set. + """ + pkg = "pep8" + proxy = False + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + config_mock = { + "proxy_host": "salt-proxy", + "proxy_port": "3128", + "proxy_username": "salt-user", + "proxy_password": "salt-passwd", + } + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + with patch.dict(pip.__opts__, config_mock): + pip.install(pkg, proxy=proxy) + expected = [sys.executable, "-m", "pip", "install", pkg] + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + +def test_install_global_proxy_in_resulting_command(): + """ + Checking that there is proxy set if global proxy is set. + """ + pkg = "pep8" + proxy = "http://salt-user:salt-passwd@salt-proxy:3128" + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + config_mock = { + "proxy_host": "salt-proxy", + "proxy_port": "3128", + "proxy_username": "salt-user", + "proxy_password": "salt-passwd", + } + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + with patch.dict(pip.__opts__, config_mock): + pip.install(pkg) + expected = [ + sys.executable, + "-m", + "pip", + "install", + "--proxy", + proxy, + pkg, + ] + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + +def test_install_multiple_requirements_arguments_in_resulting_command(): + with patch("salt.modules.pip._get_cached_requirements") as get_cached_requirements: + cached_reqs = ["my_cached_reqs-1", "my_cached_reqs-2"] + get_cached_requirements.side_effect = cached_reqs + requirements = ["salt://requirements-1.txt", "salt://requirements-2.txt"] + + expected = [sys.executable, "-m", "pip", "install"] + for item in cached_reqs: + expected.extend(["--requirement", item]) + + # Passing option as a list + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(requirements=requirements) + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + # Passing option as a comma separated list + get_cached_requirements.side_effect = cached_reqs + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(requirements=",".join(requirements)) + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + # Passing option as a single string entry + get_cached_requirements.side_effect = [cached_reqs[0]] + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install(requirements=requirements[0]) + expected = [ + sys.executable, + "-m", + "pip", + "install", + "--requirement", + cached_reqs[0], + ] + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + +def test_install_extra_args_arguments_in_resulting_command(): + pkg = "pep8" + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.install( + pkg, extra_args=[{"--latest-pip-kwarg": "param"}, "--latest-pip-arg"] + ) + expected = [ + sys.executable, + "-m", + "pip", + "install", + pkg, + "--latest-pip-kwarg", + "param", + "--latest-pip-arg", + ] + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + +def test_install_extra_args_arguments_recursion_error(): + pkg = "pep8" + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + + pytest.raises( + TypeError, + lambda: pip.install( + pkg, extra_args=[{"--latest-pip-kwarg": ["param1", "param2"]}] + ), + ) + + pytest.raises( + TypeError, + lambda: pip.install( + pkg, extra_args=[{"--latest-pip-kwarg": [{"--too-deep": dict()}]}] + ), + ) + + +def test_uninstall_multiple_requirements_arguments_in_resulting_command(): + with patch("salt.modules.pip._get_cached_requirements") as get_cached_requirements: + cached_reqs = ["my_cached_reqs-1", "my_cached_reqs-2"] + get_cached_requirements.side_effect = cached_reqs + requirements = ["salt://requirements-1.txt", "salt://requirements-2.txt"] + + expected = [sys.executable, "-m", "pip", "uninstall", "-y"] + for item in cached_reqs: + expected.extend(["--requirement", item]) + + # Passing option as a list + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.uninstall(requirements=requirements) + mock.assert_called_with( + expected, + cwd=None, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + # Passing option as a comma separated list + get_cached_requirements.side_effect = cached_reqs + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.uninstall(requirements=",".join(requirements)) + mock.assert_called_with( + expected, + cwd=None, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + # Passing option as a single string entry + get_cached_requirements.side_effect = [cached_reqs[0]] + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.uninstall(requirements=requirements[0]) + expected = [ + sys.executable, + "-m", + "pip", + "uninstall", + "-y", + "--requirement", + cached_reqs[0], + ] + mock.assert_called_with( + expected, + cwd=None, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + +def test_uninstall_global_proxy_in_resulting_command(): + """ + Checking that there is proxy set if global proxy is set. + """ + pkg = "pep8" + proxy = "http://salt-user:salt-passwd@salt-proxy:3128" + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + config_mock = { + "proxy_host": "salt-proxy", + "proxy_port": "3128", + "proxy_username": "salt-user", + "proxy_password": "salt-passwd", + } + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + with patch.dict(pip.__opts__, config_mock): + pip.uninstall(pkg) + expected = [ + sys.executable, + "-m", + "pip", + "uninstall", + "-y", + "--proxy", + proxy, + pkg, + ] + mock.assert_called_with( + expected, + saltenv="base", + cwd=None, + runas=None, + use_vt=False, + python_shell=False, + ) + + +def test_uninstall_proxy_false_argument_in_resulting_command(): + """ + Checking that there is no proxy set if proxy arg is set to False + even if the global proxy is set. + """ + pkg = "pep8" + proxy = False + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + config_mock = { + "proxy_host": "salt-proxy", + "proxy_port": "3128", + "proxy_username": "salt-user", + "proxy_password": "salt-passwd", + } + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + with patch.dict(pip.__opts__, config_mock): + pip.uninstall(pkg, proxy=proxy) + expected = [sys.executable, "-m", "pip", "uninstall", "-y", pkg] + mock.assert_called_with( + expected, + saltenv="base", + cwd=None, + runas=None, + use_vt=False, + python_shell=False, + ) + + +def test_uninstall_log_argument_in_resulting_command(): + pkg = "pep8" + log_path = "/tmp/pip-install.log" + + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.uninstall(pkg, log=log_path) + expected = [ + sys.executable, + "-m", + "pip", + "uninstall", + "-y", + "--log", + log_path, + pkg, + ] + mock.assert_called_with( + expected, + saltenv="base", + cwd=None, + runas=None, + use_vt=False, + python_shell=False, + ) + + # Let's fake a non-writable log file + with patch("os.path") as mock_path: + mock_path.exists.side_effect = IOError("Fooo!") + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pytest.raises(IOError, pip.uninstall, pkg, log=log_path) + + +def test_uninstall_timeout_argument_in_resulting_command(): + pkg = "pep8" + expected = [sys.executable, "-m", "pip", "uninstall", "-y", "--timeout"] + # Passing an int + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.uninstall(pkg, timeout=10) + mock.assert_called_with( + expected + [10, pkg], + cwd=None, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + # Passing an int as a string + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pip.uninstall(pkg, timeout="10") + mock.assert_called_with( + expected + ["10", pkg], + cwd=None, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + # Passing a non-int to timeout + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + pytest.raises(ValueError, pip.uninstall, pkg, timeout="a") + + +def test_freeze_command(): + expected = [sys.executable, "-m", "pip", "freeze"] + eggs = [ + "M2Crypto==0.21.1", + "-e git+git@github.com:s0undt3ch/salt-testing.git@9ed81aa2f918d59d3706e56b18f0782d1ea43bf8#egg=SaltTesting-dev", + "bbfreeze==1.1.0", + "bbfreeze-loader==1.1.0", + "pycrypto==2.6", + ] + mock = MagicMock(return_value={"retcode": 0, "stdout": "\n".join(eggs)}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + with patch("salt.modules.pip.version", MagicMock(return_value="6.1.1")): + ret = pip.freeze() + mock.assert_called_with( + expected, + cwd=None, + runas=None, + use_vt=False, + python_shell=False, + ) + assert ret == eggs + + mock = MagicMock(return_value={"retcode": 0, "stdout": "\n".join(eggs)}) + # Passing env_vars passes them to underlying command? + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + with patch("salt.modules.pip.version", MagicMock(return_value="6.1.1")): + ret = pip.freeze(env_vars={"foo": "bar"}) + mock.assert_called_with( + expected, + cwd=None, + runas=None, + use_vt=False, + python_shell=False, + env={"foo": "bar"}, + ) + assert ret == eggs + + # Non zero returncode raises exception? + mock = MagicMock(return_value={"retcode": 1, "stderr": "CABOOOOMMM!"}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + with patch("salt.modules.pip.version", MagicMock(return_value="6.1.1")): + pytest.raises( + CommandExecutionError, + pip.freeze, + ) + + +def test_freeze_command_with_all(): + eggs = [ + "M2Crypto==0.21.1", + "-e git+git@github.com:s0undt3ch/salt-testing.git@9ed81aa2f918d59d3706e56b18f0782d1ea43bf8#egg=SaltTesting-dev", + "bbfreeze==1.1.0", + "bbfreeze-loader==1.1.0", + "pip==0.9.1", + "pycrypto==2.6", + "setuptools==20.10.1", + ] + mock = MagicMock(return_value={"retcode": 0, "stdout": "\n".join(eggs)}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + with patch("salt.modules.pip.version", MagicMock(return_value="9.0.1")): + ret = pip.freeze() + expected = [sys.executable, "-m", "pip", "freeze", "--all"] + mock.assert_called_with( + expected, + cwd=None, + runas=None, + use_vt=False, + python_shell=False, + ) + assert ret == eggs + + # Non zero returncode raises exception? + mock = MagicMock(return_value={"retcode": 1, "stderr": "CABOOOOMMM!"}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + with patch("salt.modules.pip.version", MagicMock(return_value="9.0.1")): + pytest.raises( + CommandExecutionError, + pip.freeze, + ) + + +def test_list_command(): + eggs = [ + "M2Crypto==0.21.1", + "-e git+git@github.com:s0undt3ch/salt-testing.git@9ed81aa2f918d59d3706e56b18f0782d1ea43bf8#egg=SaltTesting-dev", + "bbfreeze==1.1.0", + "bbfreeze-loader==1.1.0", + "pycrypto==2.6", + ] + mock_version = "6.1.1" + mock = MagicMock(return_value={"retcode": 0, "stdout": "\n".join(eggs)}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + with patch("salt.modules.pip.version", MagicMock(return_value=mock_version)): + ret = pip.list_() + expected = [sys.executable, "-m", "pip", "freeze"] + mock.assert_called_with( + expected, + cwd=None, + runas=None, + python_shell=False, + use_vt=False, + ) + assert ret == { + "SaltTesting-dev": "git+git@github.com:s0undt3ch/salt-testing.git@9ed81aa2f918d59d3706e56b18f0782d1ea43bf8", + "M2Crypto": "0.21.1", + "bbfreeze-loader": "1.1.0", + "bbfreeze": "1.1.0", + "pip": mock_version, + "pycrypto": "2.6", + } + + # Non zero returncode raises exception? + mock = MagicMock(return_value={"retcode": 1, "stderr": "CABOOOOMMM!"}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + with patch("salt.modules.pip.version", MagicMock(return_value="6.1.1")): + pytest.raises( + CommandExecutionError, + pip.list_, + ) + + +def test_list_command_with_all(): + eggs = [ + "M2Crypto==0.21.1", + "-e git+git@github.com:s0undt3ch/salt-testing.git@9ed81aa2f918d59d3706e56b18f0782d1ea43bf8#egg=SaltTesting-dev", + "bbfreeze==1.1.0", + "bbfreeze-loader==1.1.0", + "pip==9.0.1", + "pycrypto==2.6", + "setuptools==20.10.1", + ] + # N.B.: this is deliberately different from the "output" of pip freeze. + # This is to demonstrate that the version reported comes from freeze + # instead of from the pip.version function. + mock_version = "9.0.0" + mock = MagicMock(return_value={"retcode": 0, "stdout": "\n".join(eggs)}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + with patch("salt.modules.pip.version", MagicMock(return_value=mock_version)): + ret = pip.list_() + expected = [sys.executable, "-m", "pip", "freeze", "--all"] + mock.assert_called_with( + expected, + cwd=None, + runas=None, + python_shell=False, + use_vt=False, + ) + assert ret == { + "SaltTesting-dev": "git+git@github.com:s0undt3ch/salt-testing.git@9ed81aa2f918d59d3706e56b18f0782d1ea43bf8", + "M2Crypto": "0.21.1", + "bbfreeze-loader": "1.1.0", + "bbfreeze": "1.1.0", + "pip": "9.0.1", + "pycrypto": "2.6", + "setuptools": "20.10.1", + } + + # Non zero returncode raises exception? + mock = MagicMock(return_value={"retcode": 1, "stderr": "CABOOOOMMM!"}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + with patch("salt.modules.pip.version", MagicMock(return_value="6.1.1")): + pytest.raises( + CommandExecutionError, + pip.list_, + ) + + +def test_list_command_with_prefix(): + eggs = [ + "M2Crypto==0.21.1", + "-e git+git@github.com:s0undt3ch/salt-testing.git@9ed81aa2f918d59d3706e56b18f0782d1ea43bf8#egg=SaltTesting-dev", + "bbfreeze==1.1.0", + "bbfreeze-loader==1.1.0", + "pycrypto==2.6", + ] + mock = MagicMock(return_value={"retcode": 0, "stdout": "\n".join(eggs)}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + with patch("salt.modules.pip.version", MagicMock(return_value="6.1.1")): + ret = pip.list_(prefix="bb") + expected = [sys.executable, "-m", "pip", "freeze"] + mock.assert_called_with( + expected, + cwd=None, + runas=None, + python_shell=False, + use_vt=False, + ) + assert ret == {"bbfreeze-loader": "1.1.0", "bbfreeze": "1.1.0"} + + +def test_list_upgrades_legacy(): + eggs = [ + "apache-libcloud (Current: 1.1.0 Latest: 2.2.1 [wheel])", + "appdirs (Current: 1.4.1 Latest: 1.4.3 [wheel])", + "awscli (Current: 1.11.63 Latest: 1.12.1 [sdist])", + ] + mock = MagicMock(return_value={"retcode": 0, "stdout": "\n".join(eggs)}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + with patch("salt.modules.pip.version", MagicMock(return_value="6.1.1")): + ret = pip.list_upgrades() + mock.assert_called_with( + [sys.executable, "-m", "pip", "list", "--outdated"], + cwd=None, + runas=None, + ) + assert ret == { + "apache-libcloud": "2.2.1 [wheel]", + "appdirs": "1.4.3 [wheel]", + "awscli": "1.12.1 [sdist]", + } + + +def test_list_upgrades_gt9(): + eggs = """[{"latest_filetype": "wheel", "version": "1.1.0", "name": "apache-libcloud", "latest_version": "2.2.1"}, + {"latest_filetype": "wheel", "version": "1.4.1", "name": "appdirs", "latest_version": "1.4.3"}, + {"latest_filetype": "sdist", "version": "1.11.63", "name": "awscli", "latest_version": "1.12.1"} + ]""" + mock = MagicMock(return_value={"retcode": 0, "stdout": "{}".format(eggs)}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + with patch("salt.modules.pip.version", MagicMock(return_value="9.1.1")): + ret = pip.list_upgrades() + mock.assert_called_with( + [ + sys.executable, + "-m", + "pip", + "list", + "--outdated", + "--format=json", + ], + cwd=None, + runas=None, + ) + assert ret == { + "apache-libcloud": "2.2.1 [wheel]", + "appdirs": "1.4.3 [wheel]", + "awscli": "1.12.1 [sdist]", + } + + +def test_is_installed_true(): + eggs = [ + "M2Crypto==0.21.1", + "-e git+git@github.com:s0undt3ch/salt-testing.git@9ed81aa2f918d59d3706e56b18f0782d1ea43bf8#egg=SaltTesting-dev", + "bbfreeze==1.1.0", + "bbfreeze-loader==1.1.0", + "pycrypto==2.6", + ] + mock = MagicMock(return_value={"retcode": 0, "stdout": "\n".join(eggs)}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + with patch("salt.modules.pip.version", MagicMock(return_value="6.1.1")): + ret = pip.is_installed(pkgname="bbfreeze") + mock.assert_called_with( + [sys.executable, "-m", "pip", "freeze"], + cwd=None, + runas=None, + python_shell=False, + use_vt=False, + ) + assert ret + + +def test_is_installed_false(): + eggs = [ + "M2Crypto==0.21.1", + "-e git+git@github.com:s0undt3ch/salt-testing.git@9ed81aa2f918d59d3706e56b18f0782d1ea43bf8#egg=SaltTesting-dev", + "bbfreeze==1.1.0", + "bbfreeze-loader==1.1.0", + "pycrypto==2.6", + ] + mock = MagicMock(return_value={"retcode": 0, "stdout": "\n".join(eggs)}) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + with patch("salt.modules.pip.version", MagicMock(return_value="6.1.1")): + ret = pip.is_installed(pkgname="notexist") + mock.assert_called_with( + [sys.executable, "-m", "pip", "freeze"], + cwd=None, + runas=None, + python_shell=False, + use_vt=False, + ) + assert not ret + + +def test_install_pre_argument_in_resulting_command(): + pkg = "pep8" + # Lower than 1.4 versions don't end up with `--pre` in the resulting output + mock = MagicMock( + side_effect=[ + {"retcode": 0, "stdout": "pip 1.2.0 /path/to/site-packages/pip"}, + {"retcode": 0, "stdout": ""}, + ] + ) + with patch.dict(pip.__salt__, {"cmd.run_all": mock}): + with patch("salt.modules.pip.version", MagicMock(return_value="1.3")): + pip.install(pkg, pre_releases=True) + expected = [sys.executable, "-m", "pip", "install", pkg] + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + mock_run = MagicMock(return_value="pip 1.4.1 /path/to/site-packages/pip") + mock_run_all = MagicMock(return_value={"retcode": 0, "stdout": ""}) + with patch.dict( + pip.__salt__, {"cmd.run_stdout": mock_run, "cmd.run_all": mock_run_all} + ): + with patch("salt.modules.pip._get_pip_bin", MagicMock(return_value=["pip"])): + pip.install(pkg, pre_releases=True) + expected = ["pip", "install", "--pre", pkg] + mock_run_all.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + + +def test_resolve_requirements_chain_function(): + with patch("salt.utils.files.fopen", FakeFopen): + chain = pip._resolve_requirements_chain( + ["requirements-0.txt", "requirements-3.txt"] + ) + assert chain == [ + "requirements-0.txt", + "requirements-1.txt", + "requirements-2.txt", + "requirements-3.txt", + "requirements-4.txt", + ] + + +def test_when_upgrade_is_called_and_there_are_available_upgrades_it_should_call_correct_command( + expected_user, +): + fake_run_all = MagicMock(return_value={"retcode": 0, "stdout": ""}) + pip_user = expected_user + with patch.dict(pip.__salt__, {"cmd.run_all": fake_run_all}), patch( + "salt.modules.pip.list_upgrades", autospec=True, return_value=[pip_user] + ), patch( + "salt.modules.pip._get_pip_bin", + autospec=True, + return_value=["some-other-pip"], + ): + pip.upgrade(user=pip_user) + + fake_run_all.assert_any_call( + ["some-other-pip", "install", "-U", "freeze", "--all", pip_user], + runas=pip_user, + cwd=None, + use_vt=False, + ) + + +def test_when_list_upgrades_is_provided_a_user_it_should_be_passed_to_the_version_command( + expected_user, +): + fake_run_all = MagicMock(return_value={"retcode": 0, "stdout": "{}"}) + pip_user = expected_user + + def all_new_commands(*args, **kwargs): + """ + Without this, mutating the return value mutates the return value + for EVERYTHING. + """ + return ["some-other-pip"] + + with patch.dict(pip.__salt__, {"cmd.run_all": fake_run_all}), patch( + "salt.modules.pip._get_pip_bin", + autospec=True, + side_effect=all_new_commands, + ): + pip._clear_context() + pip.list_upgrades(user=pip_user) + fake_run_all.assert_any_call( + ["some-other-pip", "--version"], + runas=expected_user, + cwd=None, + python_shell=False, + ) + + +def test_when_install_is_provided_a_user_it_should_be_passed_to_the_version_command( + expected_user, +): + fake_run_all = MagicMock(return_value={"retcode": 0, "stdout": "{}"}) + pip_user = expected_user + + def all_new_commands(*args, **kwargs): + """ + Without this, mutating the return value mutates the return value + for EVERYTHING. + """ + return ["some-other-pip"] + + with patch.dict(pip.__salt__, {"cmd.run_all": fake_run_all}), patch( + "salt.modules.pip._get_pip_bin", + autospec=True, + side_effect=all_new_commands, + ): + pip._clear_context() + pip.install(user=pip_user) + fake_run_all.assert_any_call( + ["some-other-pip", "--version"], + runas=pip_user, + cwd=None, + python_shell=False, + ) + + +def test_when_version_is_called_with_a_user_it_should_be_passed_to_undelying_runas( + expected_user, +): + fake_run_all = MagicMock(return_value={"retcode": 0, "stdout": ""}) + pip_user = expected_user + with patch.dict(pip.__salt__, {"cmd.run_all": fake_run_all}), patch( + "salt.modules.pip.list_upgrades", autospec=True, return_value=[pip_user] + ), patch( + "salt.modules.pip._get_pip_bin", + autospec=True, + return_value=["some-new-pip"], + ): + pip.version(user=pip_user) + fake_run_all.assert_called_with( + ["some-new-pip", "--version"], + runas=pip_user, + cwd=None, + python_shell=False, + ) + + +def test_install_target_from_VENV_PIP_TARGET_in_resulting_command(): + pkg = "pep8" + target = "/tmp/foo" + target_env = "/tmp/bar" + mock = MagicMock(return_value={"retcode": 0, "stdout": ""}) + environment = os.environ.copy() + environment["VENV_PIP_TARGET"] = target_env + with patch.dict(pip.__salt__, {"cmd.run_all": mock}), patch.object( + os, "environ", environment + ): + pip.install(pkg) + expected = [sys.executable, "-m", "pip", "install", "--target", target_env, pkg] + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) + mock.reset_mock() + pip.install(pkg, target=target) + expected = [sys.executable, "-m", "pip", "install", "--target", target, pkg] + mock.assert_called_with( + expected, + saltenv="base", + runas=None, + use_vt=False, + python_shell=False, + ) -- 2.36.1
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor