Commit cff1baa1 by Arun Babu Neelicattu

deprecate plugin commands and route to self

parent c88f5b52
......@@ -278,6 +278,14 @@ The add command adds required packages to your <comment>pyproject.toml</> and in
return existing_packages
@property
def _hint_update_packages(self) -> str:
return (
"\nIf you want to update it to the latest compatible version, you can use"
" `poetry update package`.\nIf you prefer to upgrade it to the latest"
" available version, you can use `poetry add package@latest`.\n"
)
def notify_about_existing_packages(self, existing_packages: list[str]) -> None:
self.line(
"The following packages are already present in the pyproject.toml and will"
......@@ -285,8 +293,4 @@ The add command adds required packages to your <comment>pyproject.toml</> and in
)
for name in existing_packages:
self.line(f" • <c1>{name}</c1>")
self.line(
"\nIf you want to update it to the latest compatible version, you can use"
" `poetry update package`.\nIf you prefer to upgrade it to the latest"
" available version, you can use `poetry add package@latest`.\n"
)
self.line(self._hint_update_packages)
from __future__ import annotations
import os
from typing import Any
from typing import cast
from cleo.helpers import argument
from cleo.helpers import option
from cleo.io.inputs.string_input import StringInput
from cleo.io.io import IO
from poetry.console.application import Application
from poetry.console.commands.init import InitCommand
from poetry.console.commands.update import UpdateCommand
from poetry.console.commands.self.add import SelfAddCommand
class PluginAddCommand(InitCommand):
......@@ -31,146 +30,33 @@ class PluginAddCommand(InitCommand):
" --verbose).",
)
]
help = """
deprecation = (
"<warning>This command is deprecated. Use <c2>self add</> command instead."
"</warning>"
)
help = f"""
The <c1>plugin add</c1> command installs Poetry plugins globally.
It works similarly to the <c1>add</c1> command:
If you do not specify a version constraint, poetry will choose a suitable one based on\
the available package versions.
You can specify a package in the following forms:
- A single name (<b>requests</b>)
- A name and a constraint (<b>requests@^2.23.0</b>)
- A git url (<b>git+https://github.com/python-poetry/poetry.git</b>)
- A git url with a revision\
(<b>git+https://github.com/python-poetry/poetry.git#develop</b>)
- A git SSH url (<b>git+ssh://github.com/python-poetry/poetry.git</b>)
- A git SSH url with a revision\
(<b>git+ssh://github.com/python-poetry/poetry.git#develop</b>)
- A file path (<b>../my-package/my-package.whl</b>)
- A directory (<b>../my-package/</b>)
- A url (<b>https://example.com/packages/my-package-0.1.0.tar.gz</b>)\
{SelfAddCommand.examples}
{deprecation}
"""
def handle(self) -> int:
from pathlib import Path
import tomlkit
from cleo.io.inputs.string_input import StringInput
from cleo.io.io import IO
from poetry.core.packages.project_package import ProjectPackage
from poetry.core.pyproject.toml import PyProjectTOML
from poetry.core.semver.helpers import parse_constraint
from poetry.factory import Factory
from poetry.repositories.installed_repository import InstalledRepository
from poetry.utils.env import EnvManager
plugins = self.argument("plugins")
# Plugins should be installed in the system env to be globally available
system_env = EnvManager.get_system_env(naive=True)
env_dir = Path(os.getenv("POETRY_HOME") or system_env.path)
# We check for the plugins existence first.
if env_dir.joinpath("pyproject.toml").exists():
pyproject: dict[str, Any] = tomlkit.loads(
env_dir.joinpath("pyproject.toml").read_text(encoding="utf-8")
)
poetry_content = pyproject["tool"]["poetry"]
existing_packages = self.get_existing_packages_from_input(
plugins, poetry_content, "dependencies"
)
if existing_packages:
self.notify_about_existing_packages(existing_packages)
plugins = [plugin for plugin in plugins if plugin not in existing_packages]
if not plugins:
return 0
plugins = self._determine_requirements(plugins)
# We retrieve the packages installed in the system environment.
# We assume that this environment will be a self contained virtual environment
# built by the official installer or by pipx.
# If not, it might lead to side effects since other installed packages might not
# be required by Poetry but still be taken into account when resolving
# dependencies.
installed_repository = InstalledRepository.load(
system_env, with_dependencies=True
)
self.line_error(self.deprecation)
root_package = None
for package in installed_repository.packages:
if package.name == "poetry":
root_package = ProjectPackage(package.name, package.version)
for dependency in package.requires:
root_package.add_dependency(dependency)
break
assert root_package is not None
root_package.python_versions = ".".join(
str(v) for v in system_env.version_info[:3]
)
# We create a `pyproject.toml` file based on all the information
# we have about the current environment.
if not env_dir.joinpath("pyproject.toml").exists():
Factory.create_pyproject_from_package(
root_package,
env_dir,
)
# We add the plugins to the dependencies section of the previously
# created `pyproject.toml` file
pyproject_toml = PyProjectTOML(env_dir.joinpath("pyproject.toml"))
poetry_content = pyproject_toml.poetry_config
poetry_dependency_section = poetry_content["dependencies"]
plugin_names = []
for plugin in plugins:
if "version" in plugin:
# Validate version constraint
parse_constraint(plugin["version"])
constraint: dict[str, Any] = tomlkit.inline_table()
for name, value in plugin.items():
if name == "name":
continue
constraint[name] = value
if len(constraint) == 1 and "version" in constraint:
constraint = constraint["version"]
poetry_dependency_section[plugin["name"]] = constraint
plugin_names.append(plugin["name"])
application = cast(Application, self.application)
command: SelfAddCommand = cast(SelfAddCommand, application.find("self add"))
application._configure_installer(command, self.io)
pyproject_toml.save()
argv: list[str] = ["add", *self.argument("plugins")]
# From this point forward, all the logic will be deferred to
# the update command, by using the previously created `pyproject.toml`
# file.
application = cast(Application, self.application)
update_command: UpdateCommand = cast(UpdateCommand, application.find("update"))
# We won't go through the event dispatching done by the application
# so we need to configure the command manually
update_command.set_poetry(Factory().create_poetry(env_dir))
update_command.set_env(system_env)
application._configure_installer(update_command, self._io)
argv = ["update"] + plugin_names
if self.option("dry-run"):
if self.option("--dry-run"):
argv.append("--dry-run")
exit_code: int = update_command.run(
exit_code: int = command.run(
IO(
StringInput(" ".join(argv)),
self._io.output,
......@@ -178,30 +64,3 @@ You can specify a package in the following forms:
)
)
return exit_code
def get_existing_packages_from_input(
self, packages: list[str], poetry_content: dict[str, Any], target_section: str
) -> list[str]:
existing_packages = []
for name in packages:
for key in poetry_content[target_section]:
if key.lower() == name.lower():
existing_packages.append(name)
return existing_packages
def notify_about_existing_packages(self, existing_packages: list[str]) -> None:
self.line(
"The following plugins are already present in the "
"<c2>pyproject.toml</c2> file and will be skipped:\n"
)
for name in existing_packages:
self.line(f" • <c1>{name}</c1>")
self.line(
"\nIf you want to update it to the latest compatible version, "
"you can use `<c2>poetry plugin update package</c2>`.\n"
"If you prefer to upgrade it to the latest available version, "
"you can use `<c2>poetry plugin add package@latest</c2>`.\n"
)
from __future__ import annotations
import os
from typing import cast
from cleo.helpers import argument
from cleo.helpers import option
from cleo.io.inputs.string_input import StringInput
from cleo.io.io import IO
from poetry.console.application import Application
from poetry.console.commands.command import Command
from poetry.console.commands.remove import RemoveCommand
from poetry.console.commands.self.remove import SelfRemoveCommand
class PluginRemoveCommand(Command):
......@@ -31,35 +31,26 @@ class PluginRemoveCommand(Command):
)
]
def handle(self) -> int:
from pathlib import Path
from cleo.io.inputs.string_input import StringInput
from cleo.io.io import IO
from poetry.factory import Factory
from poetry.utils.env import EnvManager
plugins = self.argument("plugins")
help = (
"<warning>This command is deprecated. Use <c2>self remove</> command instead."
"</warning>"
)
system_env = EnvManager.get_system_env(naive=True)
env_dir = Path(os.getenv("POETRY_HOME") or system_env.path)
def handle(self) -> int:
self.line_error(self.help)
# From this point forward, all the logic will be deferred to
# the remove command, by using the global `pyproject.toml` file.
application = cast(Application, self.application)
remove_command: RemoveCommand = cast(RemoveCommand, application.find("remove"))
# We won't go through the event dispatching done by the application
# so we need to configure the command manually
remove_command.set_poetry(Factory().create_poetry(env_dir))
remove_command.set_env(system_env)
application._configure_installer(remove_command, self._io)
command: SelfRemoveCommand = cast(
SelfRemoveCommand, application.find("self remove")
)
application._configure_installer(command, self.io)
argv: list[str] = ["remove", *self.argument("plugins")]
argv = ["remove"] + plugins
if self.option("dry-run"):
if self.option("--dry-run"):
argv.append("--dry-run")
exit_code: int = remove_command.run(
exit_code: int = command.run(
IO(
StringInput(" ".join(argv)),
self._io.output,
......
from __future__ import annotations
from poetry.core.semver.version import Version
from poetry.__version__ import __version__
from poetry.console.commands.add import AddCommand
from poetry.console.commands.self.self_command import SelfCommand
......@@ -21,3 +24,17 @@ file.
{AddCommand.examples}
"""
@property
def _hint_update_packages(self) -> str:
version = Version.parse(__version__)
flags = ""
if not version.is_stable():
flags = " --preview"
return (
"\nIf you want to update it to the latest compatible version, you can use"
f" `poetry self update{flags}`.\nIf you prefer to upgrade it to the latest"
" available version, you can use `poetry self add package@latest`.\n"
)
from __future__ import annotations
from typing import TYPE_CHECKING
import pytest
from poetry.core.packages.package import Package
from poetry.__version__ import __version__
from poetry.factory import Factory
from poetry.repositories.installed_repository import InstalledRepository
from poetry.repositories.pool import Pool
from poetry.utils.env import EnvManager
if TYPE_CHECKING:
from cleo.io.io import IO
from pytest_mock import MockerFixture
from poetry.config.config import Config
from poetry.config.source import Source
from poetry.poetry import Poetry
from poetry.repositories import Repository
from poetry.utils.env import MockEnv
from tests.helpers import TestRepository
from tests.types import SourcesFactory
@pytest.fixture()
def installed() -> InstalledRepository:
repository = InstalledRepository()
repository.add_package(Package("poetry", __version__))
return repository
def configure_sources_factory(repo: TestRepository) -> SourcesFactory:
def _configure_sources(
poetry: Poetry,
sources: Source,
config: Config,
io: IO,
disable_cache: bool = False,
) -> None:
pool = Pool()
pool.add_repository(repo)
poetry.set_pool(pool)
return _configure_sources
@pytest.fixture(autouse=True)
def setup_mocks(
mocker: MockerFixture,
env: MockEnv,
repo: TestRepository,
installed: Repository,
) -> None:
mocker.patch.object(EnvManager, "get_system_env", return_value=env)
mocker.patch.object(InstalledRepository, "load", return_value=installed)
mocker.patch.object(
Factory, "configure_sources", side_effect=configure_sources_factory(repo)
)
from __future__ import annotations
from typing import TYPE_CHECKING
import pytest
from poetry.core.packages.package import Package
from poetry.__version__ import __version__
from poetry.repositories import Pool
from poetry.utils.env import EnvManager
if TYPE_CHECKING:
import httpretty
from pytest_mock import MockerFixture
from poetry.repositories.repository import Repository
from poetry.utils.env import VirtualEnv
from tests.helpers import TestRepository
@pytest.fixture(autouse=True)
def _patch_repos(repo: TestRepository, installed: Repository) -> None:
poetry = Package("poetry", __version__)
repo.add_package(poetry)
installed.add_package(poetry)
@pytest.fixture(autouse=True)
def save_environ(environ: None) -> Repository:
yield
@pytest.fixture()
def pool(repo: TestRepository) -> Pool:
return Pool([repo])
@pytest.fixture(autouse=True)
def setup_mocks(
mocker: MockerFixture,
tmp_venv: VirtualEnv,
installed: Repository,
pool: Pool,
http: type[httpretty.httpretty],
) -> None:
mocker.patch.object(EnvManager, "get_system_env", return_value=tmp_venv)
mocker.patch("poetry.repositories.pool.Pool.find_packages", pool.find_packages)
mocker.patch("poetry.repositories.pool.Pool.package", pool.package)
mocker.patch("poetry.installation.executor.pip_install")
mocker.patch(
"poetry.installation.installer.Installer._get_installed",
return_value=installed,
)
from __future__ import annotations
from typing import TYPE_CHECKING
import pytest
from poetry.core.packages.package import Package
from poetry.__version__ import __version__
if TYPE_CHECKING:
from cleo.testers.command_tester import CommandTester
from tests.helpers import TestRepository
from tests.types import CommandTesterFactory
@pytest.fixture()
def tester(command_tester_factory: CommandTesterFactory) -> CommandTester:
return command_tester_factory("plugin add")
def test_deprecation_warning(tester: CommandTester, repo: TestRepository) -> None:
repo.add_package(Package("poetry", __version__))
repo.add_package(Package("poetry-plugin", "1.0"))
tester.execute("poetry-plugin")
assert (
tester.io.fetch_error()
== "This command is deprecated. Use self add command instead.\n"
)
from __future__ import annotations
from typing import TYPE_CHECKING
import pytest
from poetry.core.packages.dependency import Dependency
from poetry.core.packages.package import Package
from poetry.core.packages.project_package import ProjectPackage
from poetry.__version__ import __version__
from poetry.console.commands.self.self_command import SelfCommand
from poetry.factory import Factory
from tests.console.commands.self.utils import get_self_command_dependencies
if TYPE_CHECKING:
from cleo.testers.command_tester import CommandTester
from tests.helpers import TestRepository
from tests.types import CommandTesterFactory
@pytest.fixture()
def tester(command_tester_factory: CommandTesterFactory) -> CommandTester:
return command_tester_factory("plugin remove")
def test_deprecation_warning(tester: CommandTester, repo: TestRepository) -> None:
plugin = Package("poetry-plugin", "1.2.3")
repo.add_package(Package("poetry", __version__))
repo.add_package(plugin)
package = ProjectPackage("poetry-instance", __version__)
package.add_dependency(
Dependency(plugin.name, "^1.2.3", groups=[SelfCommand.ADDITIONAL_PACKAGE_GROUP])
)
content = Factory.create_pyproject_from_package(package)
system_pyproject_file = SelfCommand.get_default_system_pyproject_file()
system_pyproject_file.write_text(content.as_string(), encoding="utf-8")
dependencies = get_self_command_dependencies(locked=False)
assert "poetry-plugin" in dependencies
tester.execute("poetry-plugin")
assert (
tester.io.fetch_error()
== "This command is deprecated. Use self remove command instead.\n"
)
dependencies = get_self_command_dependencies()
assert "poetry-plugin" not in dependencies
assert not dependencies
......@@ -6,51 +6,38 @@ import pytest
from poetry.core.packages.package import Package
from poetry.console.commands.self.self_command import SelfCommand
from poetry.factory import Factory
from tests.console.commands.self.utils import get_self_command_dependencies
if TYPE_CHECKING:
from cleo.testers.command_tester import CommandTester
from pytest_mock import MockerFixture
from poetry.console.commands.update import UpdateCommand
from poetry.repositories import Repository
from poetry.utils.env import MockEnv
from tests.helpers import PoetryTestApplication
from tests.helpers import TestRepository
from tests.types import CommandTesterFactory
@pytest.fixture()
def tester(command_tester_factory: CommandTesterFactory) -> CommandTester:
return command_tester_factory("plugin add")
return command_tester_factory("self add")
def assert_plugin_add_result(
tester: CommandTester,
app: PoetryTestApplication,
env: MockEnv,
expected: str,
constraint: str | dict[str, str],
) -> None:
assert tester.io.fetch_output() == expected
dependencies = get_self_command_dependencies()
update_command: UpdateCommand = app.find("update")
assert update_command.poetry.file.parent == env.path
assert update_command.poetry.locker.lock.parent == env.path
assert update_command.poetry.locker.lock.exists()
content = update_command.poetry.file.read()["tool"]["poetry"]
assert "poetry-plugin" in content["dependencies"]
assert content["dependencies"]["poetry-plugin"] == constraint
assert "poetry-plugin" in dependencies
assert dependencies["poetry-plugin"] == constraint
def test_add_no_constraint(
app: PoetryTestApplication,
repo: TestRepository,
tester: CommandTester,
env: MockEnv,
installed: Repository,
repo: TestRepository,
):
repo.add_package(Package("poetry-plugin", "0.1.0"))
......@@ -58,6 +45,7 @@ def test_add_no_constraint(
expected = """\
Using version ^0.1.0 for poetry-plugin
Updating dependencies
Resolving dependencies...
......@@ -67,22 +55,19 @@ Package operations: 1 install, 0 updates, 0 removals
• Installing poetry-plugin (0.1.0)
"""
assert_plugin_add_result(tester, app, env, expected, "^0.1.0")
assert_plugin_add_result(tester, expected, "^0.1.0")
def test_add_with_constraint(
app: PoetryTestApplication,
repo: TestRepository,
tester: CommandTester,
env: MockEnv,
installed: Repository,
repo: TestRepository,
):
repo.add_package(Package("poetry-plugin", "0.1.0"))
repo.add_package(Package("poetry-plugin", "0.2.0"))
tester.execute("poetry-plugin@^0.2.0")
expected = """\
expected = """
Updating dependencies
Resolving dependencies...
......@@ -93,21 +78,18 @@ Package operations: 1 install, 0 updates, 0 removals
• Installing poetry-plugin (0.2.0)
"""
assert_plugin_add_result(tester, app, env, expected, "^0.2.0")
assert_plugin_add_result(tester, expected, "^0.2.0")
def test_add_with_git_constraint(
app: PoetryTestApplication,
repo: TestRepository,
tester: CommandTester,
env: MockEnv,
installed: Repository,
repo: TestRepository,
):
repo.add_package(Package("pendulum", "2.0.5"))
tester.execute("git+https://github.com/demo/poetry-plugin.git")
expected = """\
expected = """
Updating dependencies
Resolving dependencies...
......@@ -120,23 +102,20 @@ Package operations: 2 installs, 0 updates, 0 removals
"""
assert_plugin_add_result(
tester, app, env, expected, {"git": "https://github.com/demo/poetry-plugin.git"}
tester, expected, {"git": "https://github.com/demo/poetry-plugin.git"}
)
def test_add_with_git_constraint_with_extras(
app: PoetryTestApplication,
repo: TestRepository,
tester: CommandTester,
env: MockEnv,
installed: Repository,
repo: TestRepository,
):
repo.add_package(Package("pendulum", "2.0.5"))
repo.add_package(Package("tomlkit", "0.7.0"))
tester.execute("git+https://github.com/demo/poetry-plugin.git[foo]")
expected = """\
expected = """
Updating dependencies
Resolving dependencies...
......@@ -151,8 +130,6 @@ Package operations: 3 installs, 0 updates, 0 removals
assert_plugin_add_result(
tester,
app,
env,
expected,
{
"git": "https://github.com/demo/poetry-plugin.git",
......@@ -162,24 +139,22 @@ Package operations: 3 installs, 0 updates, 0 removals
def test_add_existing_plugin_warns_about_no_operation(
app: PoetryTestApplication,
repo: TestRepository,
tester: CommandTester,
env: MockEnv,
installed: Repository,
repo: TestRepository,
installed: TestRepository,
):
env.path.joinpath("pyproject.toml").write_text(
"""\
SelfCommand.get_default_system_pyproject_file().write_text(
f"""\
[tool.poetry]
name = "poetry"
name = "poetry-instance"
version = "1.2.0"
description = "Python dependency management and packaging made easy."
authors = [
"Sébastien Eustace <sebastien@eustace.io>"
]
authors = []
[tool.poetry.dependencies]
python = "^3.6"
[tool.poetry.group.{SelfCommand.ADDITIONAL_PACKAGE_GROUP}.dependencies]
poetry-plugin = "^1.2.3"
""",
encoding="utf-8",
......@@ -191,46 +166,35 @@ poetry-plugin = "^1.2.3"
tester.execute("poetry-plugin")
expected = """\
The following plugins are already present in the pyproject.toml file and will be\
expected = f"""\
The following packages are already present in the pyproject.toml and will be\
skipped:
• poetry-plugin
If you want to update it to the latest compatible version,\
you can use `poetry plugin update package`.
If you prefer to upgrade it to the latest available version,\
you can use `poetry plugin add package@latest`.
{tester.command._hint_update_packages}
Nothing to add.
"""
assert tester.io.fetch_output() == expected
update_command: UpdateCommand = app.find("update")
# The update command should not have been called
assert update_command.poetry.file.parent != env.path
def test_add_existing_plugin_updates_if_requested(
app: PoetryTestApplication,
repo: TestRepository,
tester: CommandTester,
env: MockEnv,
installed: Repository,
mocker: MockerFixture,
repo: TestRepository,
installed: TestRepository,
):
env.path.joinpath("pyproject.toml").write_text(
"""\
SelfCommand.get_default_system_pyproject_file().write_text(
f"""\
[tool.poetry]
name = "poetry"
name = "poetry-instance"
version = "1.2.0"
description = "Python dependency management and packaging made easy."
authors = [
"Sébastien Eustace <sebastien@eustace.io>"
]
authors = []
[tool.poetry.dependencies]
python = "^3.6"
[tool.poetry.group.{SelfCommand.ADDITIONAL_PACKAGE_GROUP}.dependencies]
poetry-plugin = "^1.2.3"
""",
encoding="utf-8",
......@@ -245,6 +209,7 @@ poetry-plugin = "^1.2.3"
expected = """\
Using version ^2.3.4 for poetry-plugin
Updating dependencies
Resolving dependencies...
......@@ -255,15 +220,13 @@ Package operations: 0 installs, 1 update, 0 removals
• Updating poetry-plugin (1.2.3 -> 2.3.4)
"""
assert_plugin_add_result(tester, app, env, expected, "^2.3.4")
assert_plugin_add_result(tester, expected, "^2.3.4")
def test_adding_a_plugin_can_update_poetry_dependencies_if_needed(
app: PoetryTestApplication,
repo: TestRepository,
tester: CommandTester,
env: MockEnv,
installed: Repository,
repo: TestRepository,
installed: TestRepository,
):
poetry_package = Package("poetry", "1.2.0")
poetry_package.add_dependency(Factory.create_dependency("tomlkit", "^0.7.0"))
......@@ -282,6 +245,7 @@ def test_adding_a_plugin_can_update_poetry_dependencies_if_needed(
expected = """\
Using version ^1.2.3 for poetry-plugin
Updating dependencies
Resolving dependencies...
......@@ -293,4 +257,4 @@ Package operations: 1 install, 1 update, 0 removals
• Installing poetry-plugin (1.2.3)
"""
assert_plugin_add_result(tester, app, env, expected, "^1.2.3")
assert_plugin_add_result(tester, expected, "^1.2.3")
......@@ -5,47 +5,40 @@ from typing import TYPE_CHECKING
import pytest
import tomlkit
from poetry.core.packages.dependency import Dependency
from poetry.core.packages.package import Package
from poetry.core.packages.project_package import ProjectPackage
from poetry.__version__ import __version__
from poetry.layouts.layout import POETRY_DEFAULT
from poetry.console.commands.self.self_command import SelfCommand
from poetry.factory import Factory
from tests.console.commands.self.utils import get_self_command_dependencies
if TYPE_CHECKING:
from cleo.testers.command_tester import CommandTester
from poetry.console.commands.remove import RemoveCommand
from poetry.repositories import Repository
from poetry.utils.env import MockEnv
from tests.helpers import PoetryTestApplication
from tests.types import CommandTesterFactory
@pytest.fixture()
def tester(command_tester_factory: CommandTesterFactory) -> CommandTester:
return command_tester_factory("plugin remove")
return command_tester_factory("self remove")
@pytest.fixture()
def pyproject(env: MockEnv) -> None:
pyproject = tomlkit.loads(POETRY_DEFAULT)
content = pyproject["tool"]["poetry"]
content["name"] = "poetry"
content["version"] = __version__
content["description"] = ""
content["authors"] = ["Sébastien Eustace <sebastien@eustace.io>"]
dependency_section = content["dependencies"]
dependency_section["python"] = "^3.6"
@pytest.fixture(autouse=True)
def install_plugin(installed: Repository) -> None:
package = ProjectPackage("poetry-instance", __version__)
plugin = Package("poetry-plugin", "1.2.3")
env.path.joinpath("pyproject.toml").write_text(
tomlkit.dumps(pyproject), encoding="utf-8"
package.add_dependency(
Dependency(plugin.name, "^1.2.3", groups=[SelfCommand.ADDITIONAL_PACKAGE_GROUP])
)
content = Factory.create_pyproject_from_package(package)
system_pyproject_file = SelfCommand.get_default_system_pyproject_file()
system_pyproject_file.write_text(content.as_string(), encoding="utf-8")
@pytest.fixture(autouse=True)
def install_plugin(env: MockEnv, installed: Repository, pyproject: None) -> None:
lock_content = {
"package": [
{
......@@ -65,29 +58,14 @@ def install_plugin(env: MockEnv, installed: Repository, pyproject: None) -> None
"hashes": {"poetry-plugin": []},
},
}
env.path.joinpath("poetry.lock").write_text(
system_pyproject_file.parent.joinpath("poetry.lock").write_text(
tomlkit.dumps(lock_content), encoding="utf-8"
)
pyproject_toml = tomlkit.loads(
env.path.joinpath("pyproject.toml").read_text(encoding="utf-8")
)
content = pyproject_toml["tool"]["poetry"]
installed.add_package(plugin)
dependency_section = content["dependencies"]
dependency_section["poetry-plugin"] = "^1.2.3"
env.path.joinpath("pyproject.toml").write_text(
tomlkit.dumps(pyproject_toml), encoding="utf-8"
)
installed.add_package(Package("poetry-plugin", "1.2.3"))
def test_remove_installed_package(
app: PoetryTestApplication, tester: CommandTester, env: MockEnv
):
def test_remove_installed_package(tester: CommandTester):
tester.execute("poetry-plugin")
expected = """\
......@@ -100,41 +78,31 @@ Package operations: 0 installs, 0 updates, 1 removal
• Removing poetry-plugin (1.2.3)
"""
assert tester.io.fetch_output() == expected
remove_command: RemoveCommand = app.find("remove")
assert remove_command.poetry.file.parent == env.path
assert remove_command.poetry.locker.lock.parent == env.path
assert remove_command.poetry.locker.lock.exists()
assert not remove_command.installer.executor._dry_run
dependencies = get_self_command_dependencies()
content = remove_command.poetry.file.read()["tool"]["poetry"]
assert "poetry-plugin" not in content["dependencies"]
assert "poetry-plugin" not in dependencies
assert not dependencies
def test_remove_installed_package_dry_run(
app: PoetryTestApplication, tester: CommandTester, env: MockEnv
):
def test_remove_installed_package_dry_run(tester: CommandTester):
tester.execute("poetry-plugin --dry-run")
expected = """\
expected = f"""\
Updating dependencies
Resolving dependencies...
Package operations: 0 installs, 0 updates, 1 removal
Package operations: 0 installs, 0 updates, 1 removal, 1 skipped
• Removing poetry-plugin (1.2.3)
• Removing poetry-plugin (1.2.3)
• Installing poetry ({__version__}): Skipped for the following reason: Already \
installed
"""
assert tester.io.fetch_output() == expected
remove_command: RemoveCommand = app.find("remove")
assert remove_command.poetry.file.parent == env.path
assert remove_command.poetry.locker.lock.parent == env.path
assert remove_command.poetry.locker.lock.exists()
assert remove_command.installer.executor._dry_run
dependencies = get_self_command_dependencies()
content = remove_command.poetry.file.read()["tool"]["poetry"]
assert "poetry-plugin" in content["dependencies"]
assert "poetry-plugin" in dependencies
......@@ -10,48 +10,17 @@ from poetry.core.semver.version import Version
from poetry.__version__ import __version__
from poetry.factory import Factory
from poetry.repositories.repository import Repository
from poetry.utils.env import EnvManager
if TYPE_CHECKING:
import httpretty
from cleo.testers.command_tester import CommandTester
from pytest_mock import MockerFixture
from poetry.utils.env import VirtualEnv
from tests.helpers import TestRepository
from tests.types import CommandTesterFactory
FIXTURES = Path(__file__).parent.joinpath("fixtures")
@pytest.fixture
def installed_repository() -> Repository:
return Repository()
@pytest.fixture(autouse=True)
def save_environ(environ: None) -> Repository:
yield
@pytest.fixture(autouse=True)
def setup_mocks(
mocker: MockerFixture,
tmp_venv: VirtualEnv,
installed_repository: Repository,
http: type[httpretty.httpretty],
):
mocker.patch.object(EnvManager, "get_system_env", return_value=tmp_venv)
mocker.patch("poetry.installation.executor.pip_install")
mocker.patch(
"poetry.installation.installer.Installer._get_installed",
return_value=installed_repository,
)
@pytest.fixture()
def tester(command_tester_factory: CommandTesterFactory) -> CommandTester:
return command_tester_factory("self update")
......@@ -60,7 +29,7 @@ def tester(command_tester_factory: CommandTesterFactory) -> CommandTester:
def test_self_update_can_update_from_recommended_installation(
tester: CommandTester,
repo: TestRepository,
installed_repository: TestRepository,
installed: TestRepository,
):
new_version = Version.parse(__version__).next_minor().text
......@@ -70,8 +39,8 @@ def test_self_update_can_update_from_recommended_installation(
new_poetry = Package("poetry", new_version)
new_poetry.add_dependency(Factory.create_dependency("cleo", "^1.0.0"))
installed_repository.add_package(old_poetry)
installed_repository.add_package(Package("cleo", "0.8.2"))
installed.add_package(old_poetry)
installed.add_package(Package("cleo", "0.8.2"))
repo.add_package(new_poetry)
repo.add_package(Package("cleo", "1.0.0"))
......
from __future__ import annotations
from pathlib import Path
from typing import TYPE_CHECKING
from poetry.factory import Factory
if TYPE_CHECKING:
from tomlkit.container import Table as TOMLTable
def get_self_command_dependencies(locked: bool = True) -> TOMLTable:
from poetry.console.commands.self.self_command import SelfCommand
from poetry.locations import CONFIG_DIR
system_pyproject_file = SelfCommand.get_default_system_pyproject_file()
assert system_pyproject_file.exists()
assert system_pyproject_file.parent == Path(CONFIG_DIR)
if locked:
assert system_pyproject_file.parent.joinpath("poetry.lock").exists()
poetry = Factory().create_poetry(system_pyproject_file.parent, disable_plugins=True)
content = poetry.file.read()["tool"]["poetry"]
assert "group" in content
assert SelfCommand.ADDITIONAL_PACKAGE_GROUP in content["group"]
assert "dependencies" in content["group"][SelfCommand.ADDITIONAL_PACKAGE_GROUP]
return content["group"][SelfCommand.ADDITIONAL_PACKAGE_GROUP]["dependencies"]
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment