diff --git a/snapcraft/application.py b/snapcraft/application.py
index df84454fa8..f8fd99f980 100644
--- a/snapcraft/application.py
+++ b/snapcraft/application.py
@@ -135,9 +135,6 @@ def _register_default_plugins(self) -> None:
"""Register per application plugins when initializing."""
super()._register_default_plugins()
- # poetry plugin needs integration work, see #5025
- craft_parts.plugins.unregister("poetry")
-
if self._known_core24:
# dotnet is disabled for core24 and newer because it is pending a rewrite
craft_parts.plugins.unregister("dotnet")
diff --git a/snapcraft/parts/plugins/python_common.py b/snapcraft/parts/plugins/python_common.py
new file mode 100644
index 0000000000..127d896487
--- /dev/null
+++ b/snapcraft/parts/plugins/python_common.py
@@ -0,0 +1,55 @@
+# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
+#
+# Copyright 2023-2024 Canonical Ltd.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 3 as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+"""Common functions for Python-based Snapcraft plugins."""
+import logging
+from pathlib import Path
+
+from craft_parts import StepInfo
+
+logger = logging.getLogger(__name__)
+
+
+def post_prime(step_info: StepInfo) -> None:
+ """Perform Python-specific actions right before packing."""
+ base = step_info.project_base
+
+ if base in ("core20", "core22"):
+ # Only fix pyvenv.cfg on core24+ snaps
+ return
+
+ root_path: Path = step_info.prime_dir
+
+ pyvenv = root_path / "pyvenv.cfg"
+ if not pyvenv.is_file():
+ return
+
+ snap_path = Path(f"/snap/{step_info.project_name}/current")
+ new_home = f"home = {snap_path}"
+
+ candidates = (
+ step_info.part_install_dir,
+ step_info.stage_dir,
+ )
+
+ old_contents = contents = pyvenv.read_text()
+ for candidate in candidates:
+ old_home = f"home = {candidate}"
+ contents = contents.replace(old_home, new_home)
+
+ if old_contents != contents:
+ logger.debug("Updating pyvenv.cfg to:\n%s", contents)
+ pyvenv.write_text(contents)
diff --git a/snapcraft/services/lifecycle.py b/snapcraft/services/lifecycle.py
index 61f8f95472..38a5b8efa1 100644
--- a/snapcraft/services/lifecycle.py
+++ b/snapcraft/services/lifecycle.py
@@ -94,7 +94,7 @@ def post_prime(self, step_info: StepInfo) -> bool:
plugin_name = project.parts[part_name]["plugin"]
# Handle plugin-specific prime fixes
- if plugin_name == "python":
+ if plugin_name in ("python", "poetry"):
plugins.PythonPlugin.post_prime(step_info)
# Handle patch-elf
diff --git a/tests/spread/core24/python-hello/poetry/snap/snapcraft.yaml b/tests/spread/core24/python-hello/poetry/snap/snapcraft.yaml
new file mode 100644
index 0000000000..025dab575a
--- /dev/null
+++ b/tests/spread/core24/python-hello/poetry/snap/snapcraft.yaml
@@ -0,0 +1,14 @@
+name: python-hello-poetry
+version: "1.0"
+summary: simple python application
+description: build a python application using core24
+base: core24
+confinement: strict
+
+apps:
+ python-hello-strict:
+ command: bin/hello
+parts:
+ hello:
+ plugin: poetry
+ source: src
diff --git a/tests/spread/core24/python-hello/poetry/src/pyproject.toml b/tests/spread/core24/python-hello/poetry/src/pyproject.toml
new file mode 100644
index 0000000000..eef363c29b
--- /dev/null
+++ b/tests/spread/core24/python-hello/poetry/src/pyproject.toml
@@ -0,0 +1,18 @@
+[tool.poetry]
+name = "hello"
+version = "0.1.0"
+description = ""
+authors = ["Your Name "]
+
+[tool.poetry.dependencies]
+python = "^3.10"
+black = "^24.8.0"
+
+[tool.poetry.dev-dependencies]
+
+[build-system]
+requires = ["poetry-core>=1.0.0"]
+build-backend = "poetry.core.masonry.api"
+
+[tool.poetry.scripts]
+hello = "hello:main"
diff --git a/tests/spread/core24/python-hello/task.yaml b/tests/spread/core24/python-hello/task.yaml
index 2db4043b9e..47a434462b 100644
--- a/tests/spread/core24/python-hello/task.yaml
+++ b/tests/spread/core24/python-hello/task.yaml
@@ -8,6 +8,7 @@ systems:
environment:
PARAM/strict: ""
PARAM/classic: "--classic"
+ PARAM/poetry: ""
restore: |
cd ./"${SPREAD_VARIANT}"
diff --git a/tests/spread/plugins/craft-parts/build-and-run-hello/poetry-hello/snap/snapcraft.yaml b/tests/spread/plugins/craft-parts/build-and-run-hello/poetry-hello/snap/snapcraft.yaml
new file mode 100644
index 0000000000..e3471b76dc
--- /dev/null
+++ b/tests/spread/plugins/craft-parts/build-and-run-hello/poetry-hello/snap/snapcraft.yaml
@@ -0,0 +1,15 @@
+name: python-hello
+version: "1.0"
+summary: simple python application
+description: build a python application using core22
+base: core22
+confinement: strict
+
+apps:
+ python-hello:
+ command: bin/hello
+
+parts:
+ hello:
+ plugin: poetry
+ source: src
diff --git a/tests/spread/plugins/craft-parts/build-and-run-hello/poetry-hello/src/hello/__init__.py b/tests/spread/plugins/craft-parts/build-and-run-hello/poetry-hello/src/hello/__init__.py
new file mode 100644
index 0000000000..e3095b2229
--- /dev/null
+++ b/tests/spread/plugins/craft-parts/build-and-run-hello/poetry-hello/src/hello/__init__.py
@@ -0,0 +1,2 @@
+def main():
+ print("hello world")
diff --git a/tests/spread/plugins/craft-parts/build-and-run-hello/poetry-hello/src/pyproject.toml b/tests/spread/plugins/craft-parts/build-and-run-hello/poetry-hello/src/pyproject.toml
new file mode 100644
index 0000000000..eef363c29b
--- /dev/null
+++ b/tests/spread/plugins/craft-parts/build-and-run-hello/poetry-hello/src/pyproject.toml
@@ -0,0 +1,18 @@
+[tool.poetry]
+name = "hello"
+version = "0.1.0"
+description = ""
+authors = ["Your Name "]
+
+[tool.poetry.dependencies]
+python = "^3.10"
+black = "^24.8.0"
+
+[tool.poetry.dev-dependencies]
+
+[build-system]
+requires = ["poetry-core>=1.0.0"]
+build-backend = "poetry.core.masonry.api"
+
+[tool.poetry.scripts]
+hello = "hello:main"
diff --git a/tests/spread/plugins/craft-parts/build-and-run-hello/task.yaml b/tests/spread/plugins/craft-parts/build-and-run-hello/task.yaml
index bbb9bbea02..01b9eb9aa2 100644
--- a/tests/spread/plugins/craft-parts/build-and-run-hello/task.yaml
+++ b/tests/spread/plugins/craft-parts/build-and-run-hello/task.yaml
@@ -8,6 +8,7 @@ environment:
SNAP/colcon_ros2_wrapper: colcon-ros2-wrapper
SNAP/flutter: flutter-hello
SNAP/python: python-hello
+ SNAP/poetry: poetry-hello
SNAP/qmake: qmake-hello
SNAP/maven: maven-hello
SNAP/dotnet: dotnet-hello
diff --git a/tests/unit/parts/plugins/test_python_plugin.py b/tests/unit/parts/plugins/test_python_plugin.py
index d41f6d295a..ed357cd3fe 100644
--- a/tests/unit/parts/plugins/test_python_plugin.py
+++ b/tests/unit/parts/plugins/test_python_plugin.py
@@ -19,7 +19,7 @@
import pytest
from craft_parts import Part, PartInfo, ProjectInfo, Step, StepInfo, errors
-from snapcraft.parts.plugins import PythonPlugin
+from snapcraft.parts.plugins import PythonPlugin, python_common
@pytest.fixture
@@ -224,7 +224,7 @@ def test_fix_pyvenv(new_dir, home_attr):
step_info = StepInfo(part_info, Step.PRIME)
- PythonPlugin.post_prime(step_info)
+ python_common.post_prime(step_info)
new_contents = pyvenv.read_text()
assert "home = /snap/test-snap/current/usr/bin" in new_contents