From 172671ebef61af7fde7bd3cbdcc91b3d7ca1bd8d Mon Sep 17 00:00:00 2001 From: kotborealis Date: Sat, 1 Nov 2025 15:01:58 +0300 Subject: [PATCH] fix: use find_spec for pip plugins For pip plugins installed in editable mode, via `pip install -e ...`, buildstream failed to resolve the actual location of source files of a plugin. This is caused because `importlib.metadata` does not honor editable packages with `pth` files. This patch updates `pluginoriginpip.py` to use `find_spec` to find files. This works for editable packages. --- src/buildstream/_pluginfactory/pluginoriginpip.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/buildstream/_pluginfactory/pluginoriginpip.py b/src/buildstream/_pluginfactory/pluginoriginpip.py index 9c566bef6..14d4914b8 100644 --- a/src/buildstream/_pluginfactory/pluginoriginpip.py +++ b/src/buildstream/_pluginfactory/pluginoriginpip.py @@ -11,7 +11,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # -import os +from pathlib import Path from .._exceptions import PluginError @@ -34,6 +34,7 @@ def get_plugin_paths(self, kind, plugin_type): from packaging.requirements import Requirement, InvalidRequirement from importlib.metadata import distribution, PackageNotFoundError + from importlib.util import find_spec # Sources and elements are looked up in separate # entrypoint groups from the same package. @@ -86,17 +87,19 @@ def get_plugin_paths(self, kind, plugin_type): reason="plugin-not-found", ) - location = dist.locate_file(entrypoint.module.replace(".", os.sep) + ".py") - defaults = dist.locate_file(entrypoint.module.replace(".", os.sep) + ".yaml") + location = Path(find_spec(entrypoint.module).origin) + defaults = location.with_suffix(".yaml") if not defaults.exists(): # The plugin didn't have an accompanying YAML file defaults = None + directory = str(location.parent) + return ( - os.path.dirname(location), + directory, str(defaults), - "python package '{}' version {} at: {}".format(dist.name, dist.version, dist.locate_file("")), + "python package '{}' version {} at: {}".format(dist.name, dist.version, directory), ) def load_config(self, origin_node):