Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Project plugins and forcing a minimum poetry version #9547

Merged
merged 5 commits into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions docs/plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,28 @@ You can also list all currently installed plugins by running:
poetry self show plugins
```

### Project plugins

You can also specify that a plugin is required for your project
in the `tool.poetry.requires-plugins` section of the pyproject.toml file:

```toml
[tool.poetry.requires-plugins]
my-application-plugin = ">1.0"
```

If the plugin is not installed in Poetry's own environment when running `poetry install`,
it will be installed only for the current project under `.poetry/plugins`
in the project's directory.

The syntax to specify `plugins` is the same as for [dependencies]({{< relref "managing-dependencies" >}}).

{{% warning %}}
You can even overwrite a plugin in Poetry's own environment with another version.
However, if a plugin's dependencies are not compatible with packages in Poetry's own
environment, installation will fail.
{{% /warning %}}


## Maintaining a plugin

Expand Down
23 changes: 23 additions & 0 deletions docs/pyproject.md
Original file line number Diff line number Diff line change
Expand Up @@ -843,6 +843,29 @@ any custom url in the `urls` section.

If you publish your package on PyPI, they will appear in the `Project Links` section.

## `requires-poetry`

A constraint for the Poetry version that is required for this project.
If you are using a Poetry version that is not allowed by this constraint,
an error will be raised.

```toml
[tool.poetry]
requires-poetry = ">=2.0"
```

## `requires-plugins`

In this section, you can specify that certain plugins are required for your project:

```toml
[tool.poetry.requires-plugins]
my-application-plugin = ">=1.0"
my-plugin = ">=1.0,<2.0"
```

See [Project plugins]({{< relref "plugins#project-plugins" >}}) for more information.

## Poetry and PEP-517

[PEP-517](https://www.python.org/dev/peps/pep-0517/) introduces a standard way
Expand Down
18 changes: 10 additions & 8 deletions src/poetry/console/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
import re

from contextlib import suppress
from functools import cached_property
from importlib import import_module
from pathlib import Path
from typing import TYPE_CHECKING
from typing import cast

Expand Down Expand Up @@ -111,20 +113,13 @@ def __init__(self) -> None:

@property
def poetry(self) -> Poetry:
from pathlib import Path

from poetry.factory import Factory

if self._poetry is not None:
return self._poetry

project_path = Path.cwd()

if self._io and self._io.input.option("directory"):
project_path = Path(self._io.input.option("directory")).absolute()

self._poetry = Factory().create_poetry(
cwd=project_path,
cwd=self._directory,
io=self._io,
disable_plugins=self._disable_plugins,
disable_cache=self._disable_cache,
Expand Down Expand Up @@ -340,6 +335,7 @@ def _load_plugins(self, io: IO | None = None) -> None:
from poetry.plugins.application_plugin import ApplicationPlugin
from poetry.plugins.plugin_manager import PluginManager

PluginManager.add_project_plugin_path(self._directory)
manager = PluginManager(ApplicationPlugin.group)
manager.load_plugins()
manager.activate(self)
Expand Down Expand Up @@ -382,6 +378,12 @@ def _default_definition(self) -> Definition:

return definition

@cached_property
def _directory(self) -> Path:
if self._io and self._io.input.option("directory"):
return Path(self._io.input.option("directory")).absolute()
return Path.cwd()


def main() -> int:
exit_code: int = Application().run()
Expand Down
3 changes: 3 additions & 0 deletions src/poetry/console/commands/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from cleo.helpers import option

from poetry.console.commands.installer_command import InstallerCommand
from poetry.plugins.plugin_manager import PluginManager


if TYPE_CHECKING:
Expand Down Expand Up @@ -104,6 +105,8 @@ def handle(self) -> int:

from poetry.masonry.builders.editable import EditableBuilder

PluginManager.ensure_project_plugins(self.poetry, self.io)

if self.option("extras") and self.option("all-extras"):
self.line_error(
"<error>You cannot specify explicit"
Expand Down
4 changes: 1 addition & 3 deletions src/poetry/console/commands/self/show/plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,7 @@ def _system_project_handle(self) -> int:
}

for group in [ApplicationPlugin.group, Plugin.group]:
for entry_point in PluginManager(group).get_plugin_entry_points(
env=system_env
):
for entry_point in PluginManager(group).get_plugin_entry_points():
assert entry_point.dist is not None

package = packages_by_name[canonicalize_name(entry_point.dist.name)]
Expand Down
19 changes: 16 additions & 3 deletions src/poetry/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@

from cleo.io.null_io import NullIO
from packaging.utils import canonicalize_name
from poetry.core.constraints.version import Version
from poetry.core.constraints.version import parse_constraint
from poetry.core.factory import Factory as BaseFactory
from poetry.core.packages.dependency_group import MAIN_GROUP

from poetry.__version__ import __version__
from poetry.config.config import Config
from poetry.exceptions import PoetryError
from poetry.json import validate_object
Expand Down Expand Up @@ -56,6 +59,15 @@ def create_poetry(

base_poetry = super().create_poetry(cwd=cwd, with_groups=with_groups)

if version_str := base_poetry.local_config.get("requires-poetry"):
version_constraint = parse_constraint(version_str)
version = Version.parse(__version__)
if not version_constraint.allows(version):
raise PoetryError(
f"This project requires Poetry {version_constraint},"
f" but you are using Poetry {version}"
)

poetry_file = base_poetry.pyproject_path
locker = Locker(poetry_file.parent / "poetry.lock", base_poetry.pyproject.data)

Expand Down Expand Up @@ -99,9 +111,10 @@ def create_poetry(
)
)

plugin_manager = PluginManager(Plugin.group, disable_plugins=disable_plugins)
plugin_manager.load_plugins()
plugin_manager.activate(poetry, io)
if not disable_plugins:
plugin_manager = PluginManager(Plugin.group)
plugin_manager.load_plugins()
plugin_manager.activate(poetry, io)

return poetry

Expand Down
Loading
Loading