def test_sync_with_editable(from_editable): with mock.patch('piptools.sync.check_call') as check_call: path_to_package = os.path.join(os.path.dirname(__file__), 'fixtures', 'small_fake_package') to_install = {from_editable(path_to_package)} sync(to_install, set()) check_call.assert_called_once_with(['pip', 'install', '-q', '-e', _get_file_url(path_to_package)])
def test_sync_install(from_line, lines): with mock.patch('piptools.sync.check_call') as check_call: to_install = {from_line(line) for line in lines} sync(to_install, set()) check_call.assert_called_once_with(['pip', 'install', '-q'] + sorted(lines))
def test_sync_uninstall_pip_command(check_call): to_uninstall = ["six", "django", "pytz", "click"] sync(set(), to_uninstall) check_call.assert_called_once_with( [sys.executable, "-m", "pip", "uninstall", "-y", "-q"] + sorted(to_uninstall))
def test_sync_uninstall_pip_command(check_call): to_uninstall = ['six', 'django', 'pytz', 'click'] sync(set(), to_uninstall) check_call.assert_called_once_with( [sys.executable, '-m', 'pip', 'uninstall', '-y', '-q'] + sorted(to_uninstall) )
def test_sync_install_temporary_requirement_file(from_line, from_editable, mocked_tmp_req_file): with mock.patch('piptools.sync.check_call') as check_call: to_install = {from_line('django==1.8')} sync(to_install, set()) check_call.assert_called_once_with( ['pip', 'install', '-r', mocked_tmp_req_file.name, '-q'])
def test_sync_uninstall_pip_command(check_call): to_uninstall = ["six", "django", "pytz", "click"] sync(set(), to_uninstall) check_call.assert_called_once_with( [sys.executable, "-m", "pip", "uninstall", "-y", "-q"] + sorted(to_uninstall) )
def test_sync_up_to_date(runner): """ Everything up-to-date should be printed. """ with runner.isolation() as (stdout, _): sync(set(), set(), verbose=True) assert stdout.getvalue().decode().splitlines() == ["Everything up-to-date"]
def test_sync_with_editable(from_editable): with mock.patch('piptools.sync.check_call') as check_call: path_to_package = os.path.join(os.path.dirname(__file__), 'test_data', 'small_fake_package') to_install = {from_editable(path_to_package)} sync(to_install, set()) check_call.assert_called_once_with(['pip', 'install', '-q', '-e', _get_file_url(path_to_package)])
def test_sync_up_to_date(capsys, runner): """ Everything up-to-date should be printed. """ sync(set(), set()) captured = capsys.readouterr() assert captured.out.splitlines() == ["Everything up-to-date"] assert captured.err == ""
def test_sync_verbose(check_call, from_line): """ The -q option has to be passed to every pip calls. """ sync({from_line('django==1.8')}, set(), verbose=True) for call in check_call.call_args_list: check_call_args = call[0][0] assert '-q' not in check_call_args
def test_temporary_requirement_file_deleted(from_line, from_editable, mocked_tmp_file): with mock.patch('piptools.sync.check_call'): to_install = {from_line('django==1.8')} with mock.patch('os.unlink') as unlink: sync(to_install, set()) unlink.assert_called_once_with(mocked_tmp_file.name)
def test_temporary_requirement_file_deleted(from_line, from_editable, mocked_tmp_file): with mock.patch("piptools.sync.check_call"): to_install = {from_line("django==1.8")} with mock.patch("os.unlink") as unlink: sync(to_install, set()) unlink.assert_called_once_with(mocked_tmp_file.name)
def test_sync_requirement_file_with_hashes( from_line, from_editable, mocked_tmp_req_file ): with mock.patch("piptools.sync.check_call"): to_install = { from_line( "django==1.8", options={ "hashes": { "sha256": [ "6a03ce2feafdd193a0ba8a26dbd9773e" "757d2e5d5e7933a62eac129813bd381a" ] } }, ), from_line( "click==4.0", options={ "hashes": { "sha256": [ "9ab1d313f99b209f8f71a629f3683303" "0c8d7c72282cf7756834baf567dca662" ] } }, ), from_line( "pytz==2017.2", options={ "hashes": { "sha256": [ "d1d6729c85acea542367138286862712" "9432fba9a89ecbb248d8d1c7a9f01c67", "f5c056e8f62d45ba8215e5cb8f50dfcc" "b198b4b9fbea8500674f3443e4689589", ] } }, ), } sync(to_install, set()) expected = ( "click==4.0 \\\n" " --hash=sha256:9ab1d313f99b209f8f71a629" "f36833030c8d7c72282cf7756834baf567dca662\n" "django==1.8 \\\n" " --hash=sha256:6a03ce2feafdd193a0ba8a26" "dbd9773e757d2e5d5e7933a62eac129813bd381a\n" "pytz==2017.2 \\\n" " --hash=sha256:d1d6729c85acea542367138286" "8627129432fba9a89ecbb248d8d1c7a9f01c67 \\\n" " --hash=sha256:f5c056e8f62d45ba8215e5cb8f" "50dfccb198b4b9fbea8500674f3443e4689589" ) mocked_tmp_req_file.write.assert_called_once_with(expected)
def test_sync_verbose(check_call, from_line): """ The -q option has to be passed to every pip calls. """ sync({from_line("django==1.8")}, {from_line("click==4.0")}, verbose=True) assert check_call.call_count == 2 for call in check_call.call_args_list: check_call_args = call[0][0] assert "-q" not in check_call_args
def test_sync_install_temporary_requirement_file(from_line, from_editable, mocked_tmp_req_file): with mock.patch("piptools.sync.check_call") as check_call: to_install = {from_line("django==1.8")} sync(to_install, set()) check_call.assert_called_once_with([ sys.executable, "-m", "pip", "install", "-r", mocked_tmp_req_file.name ])
def test_sync_verbose(run, from_line): """ The -q option has to be passed to every pip calls. """ sync({from_line("django==1.8")}, {from_line("click==4.0")}) assert run.call_count == 2 for call in run.call_args_list: run_args = call[0][0] assert "-q" not in run_args
def test_sync_uninstall_pip_command(run): to_uninstall = ["six", "django", "pytz", "click"] sync(set(), to_uninstall) run.assert_called_once_with( [ sys.executable, "-m", "pip", "uninstall", "-y", *sorted(to_uninstall) ], check=True, )
def test_sync_ask_accepted(check_call, confirm, from_line, dry_run): """ pip should be called as normal when the user confirms, even with dry_run """ confirm.return_value = True sync( {from_line("django==1.8")}, {from_line("click==4.0")}, ask=True, dry_run=dry_run ) assert check_call.call_count == 2 confirm.assert_called_once_with("Would you like to proceed with these changes?")
def test_sync_dry_run_would_uninstall(echo, from_line): """ Sync with --dry-run option prints what is going to be uninstalled. """ to_uninstall = {from_line("django==1.8"), from_line("click==4.0")} sync(set(), to_uninstall, dry_run=True) expected_calls = [ mock.call("Would uninstall:"), mock.call(" django==1.8"), mock.call(" click==4.0"), ] echo.assert_has_calls(expected_calls, any_order=True)
def test_sync_dry_run(capsys, runner, from_line, to_install, to_uninstall, expected_message): """ Sync with --dry-run option prints what's is going to be installed/uninstalled. """ to_install = {from_line(pkg) for pkg in to_install} sync(to_install, to_uninstall, dry_run=True) captured = capsys.readouterr() assert captured.out.splitlines() == [ expected_message, " click==4.0", " django==1.8", ] assert captured.err == ""
def test_sync_dry_run(echo, from_line, to_install, to_uninstall, expected_message): """ Sync with --dry-run option prints what's is going to be installed/uninstalled. """ to_install = set(from_line(pkg) for pkg in to_install) to_uninstall = set(from_line(pkg) for pkg in to_uninstall) sync(to_install, to_uninstall, dry_run=True) expected_calls = [ mock.call(expected_message), mock.call(" django==1.8"), mock.call(" click==4.0"), ] echo.assert_has_calls(expected_calls, any_order=True)
def test_sync_dry_run(runner, from_line, to_install, to_uninstall, expected_message): """ Sync with --dry-run option prints what's is going to be installed/uninstalled. """ to_install = set(from_line(pkg) for pkg in to_install) with runner.isolation() as (stdout, _): sync(to_install, to_uninstall, dry_run=True) assert stdout.getvalue().decode().splitlines() == [ expected_message, " click==4.0", " django==1.8", ]
def test_sync_install_temporary_requirement_file( from_line, from_editable, mocked_tmp_req_file ): with mock.patch("piptools.sync.check_call") as check_call: to_install = {from_line("django==1.8")} sync(to_install, set()) check_call.assert_called_once_with( [ sys.executable, "-m", "pip", "install", "-r", mocked_tmp_req_file.name, "-q", ] )
def test_sync_uninstall_pip_command(check_call): to_uninstall = ["six", "django", "pytz", "click"] sync(set(), to_uninstall) if not os.environ.get("VIRTUAL_ENV"): # Safer way of using pip pip = [sys.executable, "-m", "pip"] # Note: pip is a standalone program installed in python scripts directory, When # python installation directories are copied pip.exe is broken, hence need to # call 'pip -m' to run pip module. else: # find pip via PATH pip = ["pip"] check_call.assert_called_once_with(pip + ["uninstall", "-y", "-q"] + sorted(to_uninstall))
def main(requirements): """ Get installed pip packages, compare them to the passed packages `requirements` file, install missing packages, uninstall packages not needed anymore """ install_command = create_command("install") options, _ = install_command.parse_args([]) session = install_command._build_session(options) finder = install_command._build_package_finder(options=options, session=session) requirements = parse_requirements(requirements, finder=finder, session=session) installed_dists = get_installed_distributions() to_install, to_uninstall = sync.diff(requirements, installed_dists) sync.sync(to_install, to_uninstall, verbose=True)
def test_sync_dry_run_would_install(echo, from_line): """ Sync with --dry-run option prints what's is going to be installed. """ to_install = { from_line('django==1.8'), from_line('click==4.0'), } sync(to_install, set(), dry_run=True) expected_calls = [ mock.call('Would install:'), mock.call(' django==1.8'), mock.call(' click==4.0'), ] echo.assert_has_calls(expected_calls, any_order=True)
def test_sync_requirement_file_with_hashes(from_line, from_editable, mocked_tmp_req_file): with mock.patch('piptools.sync.check_call'): to_install = { from_line( 'django==1.8', options={ 'hashes': { 'sha256': [ '6a03ce2feafdd193a0ba8a26dbd9773e757d2e5d5e7933a62eac129813bd381a', ] } }), from_line( 'click==4.0', options={ 'hashes': { 'sha256': [ '9ab1d313f99b209f8f71a629f36833030c8d7c72282cf7756834baf567dca662', ] } }), from_line( 'pytz==2017.2', options={ 'hashes': { 'sha256': [ 'd1d6729c85acea5423671382868627129432fba9a89ecbb248d8d1c7a9f01c67', 'f5c056e8f62d45ba8215e5cb8f50dfccb198b4b9fbea8500674f3443e4689589' ] } }) } sync(to_install, set()) expected = ( 'click==4.0 \\\n' ' --hash=sha256:9ab1d313f99b209f8f71a629f36833030c8d7c72282cf7756834baf567dca662\n' 'django==1.8 \\\n' ' --hash=sha256:6a03ce2feafdd193a0ba8a26dbd9773e757d2e5d5e7933a62eac129813bd381a\n' 'pytz==2017.2 \\\n' ' --hash=sha256:d1d6729c85acea5423671382868627129432fba9a89ecbb248d8d1c7a9f01c67 \\\n' ' --hash=sha256:f5c056e8f62d45ba8215e5cb8f50dfccb198b4b9fbea8500674f3443e4689589' ) mocked_tmp_req_file.write.assert_called_once_with(expected)
def test_sync_requirement_file(from_line, from_editable, mocked_tmp_req_file): with mock.patch('piptools.sync.check_call'): to_install = { from_line('django==1.8'), from_editable('git+git://fake.org/x/y.git#egg=y'), from_line('click==4.0'), from_editable('git+git://fake.org/i/j.git#egg=j'), from_line('pytz==2017.2'), } sync(to_install, set()) expected = ('click==4.0\n' 'django==1.8\n' '-e git+git://fake.org/i/j.git#egg=j\n' 'pytz==2017.2\n' '-e git+git://fake.org/x/y.git#egg=y') mocked_tmp_req_file.write.assert_called_once_with(expected)
def test_sync_ask_declined(check_call, runner, from_line, to_install, to_uninstall, expected_message): """ Sync with --ask option does a dry run if the user declines """ to_install = set(from_line(pkg) for pkg in to_install) with runner.isolation("n\n") as (stdout, _): sync(to_install, to_uninstall, ask=True) assert stdout.getvalue().decode().splitlines() == [ expected_message, " click==4.0", " django==1.8", "Would you like to proceed with these changes? [y/N]: n", ] check_call.assert_not_called()
def test_sync_requirement_file(from_line, from_editable, mocked_tmp_req_file): with mock.patch("piptools.sync.check_call"): to_install = { from_line("django==1.8"), from_editable("git+git://fake.org/x/y.git#egg=y"), from_line("click==4.0"), from_editable("git+git://fake.org/i/j.git#egg=j"), from_line("pytz==2017.2"), } sync(to_install, set()) expected = ("click==4.0\n" "django==1.8\n" "-e git+git://fake.org/i/j.git#egg=j\n" "pytz==2017.2\n" "-e git+git://fake.org/x/y.git#egg=y") mocked_tmp_req_file.write.assert_called_once_with(expected)
def test_sync_ask_declined(run, monkeypatch, capsys, from_line, to_install, to_uninstall, expected_message): """ Sync with --ask option does a dry run if the user declines """ monkeypatch.setattr("sys.stdin", io.StringIO("n\n")) to_install = {from_line(pkg) for pkg in to_install} sync(to_install, to_uninstall, ask=True) captured = capsys.readouterr() assert captured.out.splitlines() == [ expected_message, " click==4.0", " django==1.8", "Would you like to proceed with these changes? [y/N]: ", ] assert captured.err == "" run.assert_not_called()
def test_sync_requirement_file(from_line, from_editable, mocked_tmp_req_file): with mock.patch("piptools.sync.check_call"): to_install = { from_line("django==1.8"), from_editable("git+git://fake.org/x/y.git#egg=y"), from_line("click==4.0"), from_editable("git+git://fake.org/i/j.git#egg=j"), from_line("pytz==2017.2"), } sync(to_install, set()) expected = ( "click==4.0\n" "django==1.8\n" "-e git+git://fake.org/i/j.git#egg=j\n" "pytz==2017.2\n" "-e git+git://fake.org/x/y.git#egg=y" ) mocked_tmp_req_file.write.assert_called_once_with(expected)
def test_sync_ask_accepted(check_call, runner, from_line, dry_run): """ pip should be called as normal when the user confirms, even with dry_run """ with runner.isolation("y\n") as (stdout, _): sync( {from_line("django==1.8")}, {from_line("click==4.0")}, ask=True, dry_run=dry_run, ) assert check_call.call_count == 2 assert stdout.getvalue().decode().splitlines() == [ "Would uninstall:", " click==4.0", "Would install:", " django==1.8", "Would you like to proceed with these changes? [y/N]: y", ]
def test_sync_ask_declined(echo, confirm, check_call, from_line, to_install, to_uninstall, expected_message): """ Sync with --ask option does a dry run if the user declines """ confirm.return_value = False to_install = set(from_line(pkg) for pkg in to_install) to_uninstall = set(from_line(pkg) for pkg in to_uninstall) sync(to_install, to_uninstall, ask=True) expected_calls = [ mock.call(expected_message), mock.call(" django==1.8"), mock.call(" click==4.0"), ] echo.assert_has_calls(expected_calls, any_order=True) confirm.assert_called_once_with( "Would you like to proceed with these changes?") check_call.assert_not_called()
def test_sync_ask_accepted(run, monkeypatch, capsys, from_line, dry_run): """ pip should be called as normal when the user confirms, even with dry_run """ monkeypatch.setattr("sys.stdin", io.StringIO("y\n")) sync( {from_line("django==1.8")}, {from_line("click==4.0")}, ask=True, dry_run=dry_run, ) assert run.call_count == 2 captured = capsys.readouterr() assert captured.out.splitlines() == [ "Would uninstall:", " click==4.0", "Would install:", " django==1.8", "Would you like to proceed with these changes? [y/N]: ", ] assert captured.err == ""
def test_sync_up_to_date(echo): """ Everything up-to-date should be printed. """ sync(set(), set(), verbose=True) echo.assert_called_once_with("Everything up-to-date")