Skip to content

Commit

Permalink
Use a temp directory for input and output files (jazzband#1807)
Browse files Browse the repository at this point in the history
* Use a temp directory for input and output files

when testing sync, so the working directory remains clean.

* Fixed some comments in tests
  • Loading branch information
richafrank committed Feb 20, 2023
1 parent 6735e62 commit bce5b24
Showing 1 changed file with 39 additions and 35 deletions.
74 changes: 39 additions & 35 deletions tests/test_cli_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,20 @@
import os
import subprocess
import sys
from pathlib import Path
from unittest import mock

import pytest
from pip._vendor.packaging.version import Version

from piptools.scripts.sync import DEFAULT_REQUIREMENTS_FILE, cli
from piptools.scripts import sync
from piptools.scripts.sync import cli


@pytest.fixture(autouse=True)
def _temp_default_reqs(tmp_path, monkeypatch):
monkeypatch.setattr(
sync, "DEFAULT_REQUIREMENTS_FILE", str(tmp_path / "requirements.txt")
)


def test_run_as_module_sync():
Expand All @@ -21,7 +28,7 @@ def test_run_as_module_sync():
check=True,
)

# Should have run pip-compile successfully.
# Should have run pip-sync successfully.
assert result.stdout.startswith(b"Usage:")
assert b"Synchronize virtual environment with" in result.stdout

Expand All @@ -30,7 +37,7 @@ def test_run_as_module_sync():
def test_quiet_option(run, runner):
"""sync command can be run with `--quiet` or `-q` flag."""

with open("requirements.txt", "w") as req_in:
with open(sync.DEFAULT_REQUIREMENTS_FILE, "w") as req_in:
req_in.write("six==1.10.0")

out = runner.invoke(cli, ["-q"])
Expand All @@ -48,7 +55,7 @@ def test_quiet_option_when_up_to_date(run, runner):
"""
Sync should output nothing when everything is up to date and quiet option is set.
"""
with open("requirements.txt", "w"):
with open(sync.DEFAULT_REQUIREMENTS_FILE, "w"):
pass

with mock.patch("piptools.sync.diff", return_value=(set(), set())):
Expand All @@ -62,38 +69,37 @@ def test_quiet_option_when_up_to_date(run, runner):
def test_no_requirements_file(runner):
"""
It should raise an error if there are no input files
or a requirements.txt file does not exist.
and a requirements.txt file does not exist.
"""
out = runner.invoke(cli)

assert "No requirement files given" in out.stderr
assert out.exit_code == 2


def test_input_files_with_dot_in_extension(runner):
def test_input_files_with_dot_in_extension(runner, tmp_path):
"""
It should raise an error if some of the input files have .in extension.
"""
with open("requirements.in", "w") as req_in:
req_in.write("six==1.10.0")
req_in = tmp_path / "requirements.in"
req_in.write_text("six==1.10.0")

out = runner.invoke(cli, ["requirements.in"])
out = runner.invoke(cli, [str(req_in)])

assert "ERROR: Some input files have the .in extension" in out.stderr
assert out.exit_code == 2


def test_force_files_with_dot_in_extension(runner):
def test_force_files_with_dot_in_extension(runner, tmp_path):
"""
It should print a warning and sync anyway if some of the input files
have .in extension.
"""

with open("requirements.in", "w") as req_in:
req_in.write("six==1.10.0")
req_in = tmp_path / "requirements.in"
req_in.write_text("six==1.10.0")

with mock.patch("piptools.sync.run"):
out = runner.invoke(cli, ["requirements.in", "--force"])
out = runner.invoke(cli, [str(req_in), "--force"])

assert "WARNING: Some input files have the .in extension" in out.stderr
assert out.exit_code == 0
Expand All @@ -115,7 +121,7 @@ def test_merge_error(req_lines, should_raise, runner):
It should not raise an error if otherwise incompatible requirements
are isolated by exclusive environment markers.
"""
with open("requirements.txt", "w") as req_in:
with open(sync.DEFAULT_REQUIREMENTS_FILE, "w") as req_in:
for line in req_lines:
req_in.write(line + "\n")

Expand All @@ -137,17 +143,16 @@ def test_merge_error(req_lines, should_raise, runner):
),
)
@mock.patch("piptools.sync.run")
def test_merge_no_name_urls(run, req_line, runner):
def test_merge_no_name_urls(run, req_line, runner, tmp_path):
"""
Test sync succeeds when merging requirements that lack names.
"""
reqs_paths = [
Path(name).absolute() for name in ("requirements.txt", "dev_requirements.txt")
(tmp_path / name) for name in ("requirements.txt", "dev_requirements.txt")
]

for reqs_path in reqs_paths:
with reqs_path.open("w") as req_out:
req_out.write(f"{req_line} \n")
reqs_path.write_text(f"{req_line} \n")

out = runner.invoke(cli, [str(path) for path in reqs_paths])
assert out.exit_code == 0
Expand Down Expand Up @@ -193,7 +198,7 @@ def test_pip_install_flags(run, cli_flags, expected_install_flags, runner):
"""
Test the cli flags have to be passed to the pip install command.
"""
with open("requirements.txt", "w") as req_in:
with open(sync.DEFAULT_REQUIREMENTS_FILE, "w") as req_in:
req_in.write("six==1.10.0")

runner.invoke(cli, cli_flags)
Expand Down Expand Up @@ -222,7 +227,7 @@ def test_pip_install_flags_in_requirements_file(run, runner, install_flags):
"""
Test the options from requirements.txt file pass to the pip install command.
"""
with open(DEFAULT_REQUIREMENTS_FILE, "w") as reqs:
with open(sync.DEFAULT_REQUIREMENTS_FILE, "w") as reqs:
reqs.write(" ".join(install_flags) + "\n")
reqs.write("six==1.10.0")

Expand All @@ -240,7 +245,7 @@ def test_sync_ask_declined(run, runner):
"""
Make sure nothing is installed if the confirmation is declined
"""
with open("requirements.txt", "w") as req_in:
with open(sync.DEFAULT_REQUIREMENTS_FILE, "w") as req_in:
req_in.write("small-fake-a==1.10.0")

runner.invoke(cli, ["--ask"], input="n\n")
Expand All @@ -254,7 +259,7 @@ def test_sync_ask_accepted(run, runner):
Make sure pip is called when the confirmation is accepted (even if
--dry-run is given)
"""
with open("requirements.txt", "w") as req_in:
with open(sync.DEFAULT_REQUIREMENTS_FILE, "w") as req_in:
req_in.write("small-fake-a==1.10.0")

runner.invoke(cli, ["--ask", "--dry-run"], input="y\n")
Expand All @@ -266,7 +271,7 @@ def test_sync_dry_run_returns_non_zero_exit_code(runner):
"""
Make sure non-zero exit code is returned when --dry-run is given.
"""
with open("requirements.txt", "w") as req_in:
with open(sync.DEFAULT_REQUIREMENTS_FILE, "w") as req_in:
req_in.write("small-fake-a==1.10.0")

out = runner.invoke(cli, ["--dry-run"])
Expand All @@ -283,7 +288,7 @@ def test_python_executable_option(
"""
Make sure sync command can run with `--python-executable` option.
"""
with open("requirements.txt", "w") as req_in:
with open(sync.DEFAULT_REQUIREMENTS_FILE, "w") as req_in:
req_in.write("small-fake-a==1.10.0")

custom_executable = os.path.abspath(sys.executable)
Expand Down Expand Up @@ -312,7 +317,7 @@ def test_python_executable_option(
),
)
def test_invalid_python_executable(runner, python_executable):
with open("requirements.txt", "w") as req_in:
with open(sync.DEFAULT_REQUIREMENTS_FILE, "w") as req_in:
req_in.write("small-fake-a==1.10.0")

out = runner.invoke(cli, ["--python-executable", python_executable])
Expand All @@ -323,20 +328,19 @@ def test_invalid_python_executable(runner, python_executable):

@mock.patch("piptools.scripts.sync.get_pip_version_for_python_executable")
def test_invalid_pip_version_in_python_executable(
get_pip_version_for_python_executable, runner
get_pip_version_for_python_executable, runner, tmp_path
):
with open("requirements.txt", "w") as req_in:
with open(sync.DEFAULT_REQUIREMENTS_FILE, "w") as req_in:
req_in.write("small-fake-a==1.10.0")

custom_executable = os.path.abspath("custom_executable")
with open(custom_executable, "w") as exec_file:
exec_file.write("")
custom_executable = tmp_path / "custom_executable"
custom_executable.write_text("")

os.chmod(custom_executable, 0o700)
custom_executable.chmod(0o700)

get_pip_version_for_python_executable.return_value = Version("19.1")

out = runner.invoke(cli, ["--python-executable", custom_executable])
out = runner.invoke(cli, ["--python-executable", str(custom_executable)])
assert out.exit_code == 2, out
message = (
"Target python executable '{}' has pip version 19.1 installed. "
Expand All @@ -350,7 +354,7 @@ def test_default_python_executable_option(run, runner):
"""
Make sure sys.executable is used when --python-executable is not provided.
"""
with open("requirements.txt", "w") as req_in:
with open(sync.DEFAULT_REQUIREMENTS_FILE, "w") as req_in:
req_in.write("small-fake-a==1.10.0")

runner.invoke(cli)
Expand Down

0 comments on commit bce5b24

Please sign in to comment.