Skip to content

Commit

Permalink
test: uv tests
Browse files Browse the repository at this point in the history
  • Loading branch information
antazoey committed Apr 23, 2024
1 parent 399bf39 commit 15c18a4
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 17 deletions.
21 changes: 19 additions & 2 deletions src/ape/plugins/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,12 @@ class PluginMetadata(BaseInterfaceModel):
version: Optional[str] = None
"""The version requested, if there is one."""

pip_command: List[str] = PIP_COMMAND
"""
The pip base command to use. Is a property to afford
altering during tests.
"""

@model_validator(mode="before")
@classmethod
def validate_name(cls, values):
Expand All @@ -224,6 +230,7 @@ def validate_name(cls, values):
# Just some small validation so you can't put a repo
# that isn't this plugin here. NOTE: Forks should still work.
raise ValueError("Plugin mismatch with remote git version.")

elif not version:
# Only check name for version constraint if not in version.
# NOTE: This happens when using the CLI to provide version constraints.
Expand All @@ -236,7 +243,8 @@ def validate_name(cls, values):
name, version = _split_name_and_version(name)
break

return {"name": clean_plugin_name(name), "version": version}
pip_cmd = values.get("pip_command", PIP_COMMAND)
return {"name": clean_plugin_name(name), "version": version, "pip_command": pip_cmd}

@cached_property
def package_name(self) -> str:
Expand Down Expand Up @@ -373,7 +381,7 @@ def _prepare_install(
logger.warning(f"Plugin '{self.name}' is not an trusted plugin.")

result_handler = ModifyPluginResultHandler(self)
pip_arguments = [*PIP_COMMAND, "install"]
pip_arguments = [*self.pip_command, "install"]

if upgrade:
logger.info(f"Upgrading '{self.name}' plugin ...")
Expand Down Expand Up @@ -406,6 +414,15 @@ def _prepare_install(
)
return None

def _get_uninstall_args(self) -> List[str]:
arguments = [*self.pip_command, "uninstall"]

if self.pip_command[0] != "uv":
arguments.append("-y")

arguments.extend((self.package_name, "--quiet"))
return arguments


class ModifyPluginResultHandler:
def __init__(self, plugin: PluginMetadata):
Expand Down
4 changes: 2 additions & 2 deletions src/ape_plugins/_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,12 +191,12 @@ def uninstall(cli_ctx, plugins, skip_confirmation):
skip_confirmation or click.confirm(f"Remove plugin '{plugin}'?")
):
cli_ctx.logger.info(f"Uninstalling '{plugin.name}'...")
args = [*PIP_COMMAND, "uninstall", "-y", plugin.package_name, "--quiet"]
arguments = plugin._get_uninstall_args()

# NOTE: Be *extremely careful* with this command, as it modifies the user's
# installed packages, to potentially catastrophic results
# NOTE: This is not abstracted into another function *on purpose*
result = subprocess.call(args)
result = subprocess.call(arguments)
failures_occurred = not result_handler.handle_uninstall_result(result)

if failures_occurred:
Expand Down
57 changes: 44 additions & 13 deletions tests/functional/test_plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
"specifier",
(f"<{ape_version[0]}", f">0.1,<{ape_version[0]}", f"==0.{int(ape_version[2]) - 1}"),
)
parametrize_pip_cmd = pytest.mark.parametrize(
"pip_command", [["python", "-m", "pip"], ["uv", "pip"]]
)


@pytest.fixture(autouse=True)
Expand Down Expand Up @@ -163,36 +166,48 @@ def test_is_available(self):
metadata = PluginMetadata(name="foobar")
assert not metadata.is_available

def test_prepare_install(self):
metadata = PluginMetadata(name=list(AVAILABLE_PLUGINS)[0])
@parametrize_pip_cmd
def test_prepare_install(self, pip_command):
metadata = PluginMetadata(name=list(AVAILABLE_PLUGINS)[0], pip_command=pip_command)
actual = metadata._prepare_install(skip_confirmation=True)
assert actual is not None
arguments = actual.get("args", [])
expected = [
"-m",
shared = [
"pip",
"install",
f"ape-available>=0.{ape_version.minor},<0.{ape_version.minor + 1}",
"--quiet",
]
assert "python" in arguments[0]
assert arguments[1:] == expected

def test_prepare_install_upgrade(self):
metadata = PluginMetadata(name=list(AVAILABLE_PLUGINS)[0])
if arguments[0] == "uv":
expected = ["uv", *shared]
assert arguments == expected
else:
expected = ["-m", *shared]
assert "python" in arguments[0]
assert arguments[1:] == expected

@parametrize_pip_cmd
def test_prepare_install_upgrade(self, pip_command):
metadata = PluginMetadata(name=list(AVAILABLE_PLUGINS)[0], pip_command=pip_command)
actual = metadata._prepare_install(upgrade=True, skip_confirmation=True)
assert actual is not None
arguments = actual.get("args", [])
expected = [
"-m",
shared = [
"pip",
"install",
"--upgrade",
f"ape-available>=0.{ape_version.minor},<0.{ape_version.minor + 1}",
"--quiet",
]
assert "python" in arguments[0]
assert arguments[1:] == expected

if pip_command[0].startswith("uv"):
expected = ["uv", *shared]
assert arguments == expected

else:
expected = ["-m", *shared]
assert "python" in arguments[0]
assert arguments[1:] == expected

@mark_specifiers_less_than_ape
def test_prepare_install_version_smaller_than_ape(self, specifier, ape_caplog):
Expand Down Expand Up @@ -223,6 +238,22 @@ def test_check_installed_dist_no_name_attr(self, mocker, get_dists_patch):
# This triggers looping through the dist w/o a name attr.
metadata.check_installed()

@parametrize_pip_cmd
def test_get_uninstall_args(self, pip_command):
metadata = PluginMetadata(name="dontmatter", pip_command=pip_command)
arguments = metadata._get_uninstall_args()
pip_cmd_len = len(metadata.pip_command)

for idx, pip_pt in enumerate(pip_command):
assert arguments[idx] == pip_pt

expected = ["uninstall"]
if pip_command[0] == "python":
expected.append("-y")

expected.extend(("ape-dontmatter", "--quiet"))
assert arguments[pip_cmd_len:] == expected


class TestApePluginsRepr:
def test_str(self, plugin_metadata):
Expand Down

0 comments on commit 15c18a4

Please sign in to comment.