Skip to content

Commit

Permalink
add metadata package to resolve distribution information (#6)
Browse files Browse the repository at this point in the history
  • Loading branch information
thrau authored Jul 28, 2023
1 parent 0fd36ab commit 4e93357
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 0 deletions.
10 changes: 10 additions & 0 deletions plugin/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
PluginSpec,
PluginSpecResolver,
)
from .metadata import resolve_distribution_information

LOG = logging.getLogger(__name__)

Expand Down Expand Up @@ -114,6 +115,15 @@ class PluginContainer(Generic[P]):
init_error: Exception = None
load_error: Exception = None

@property
def distribution(self):
"""
Uses metadata from importlib to resolve the distribution information for this plugin.
:return: the importlib.metadata.Distribution object
"""
return resolve_distribution_information(self.plugin_spec)


class PluginManager(PluginLifecycleNotifierMixin, Generic[P]):
"""
Expand Down
37 changes: 37 additions & 0 deletions plugin/metadata.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import inspect
from functools import lru_cache
from importlib import metadata
from typing import Mapping, Optional

from .core import PluginSpec


@lru_cache()
def packages_distributions() -> Mapping[str, list[str]]:
"""
Cache wrapper around metadata.packages_distributions, which returns a mapping of top-level packages to
their distributions.
:return: package to distribution mapping
"""
return metadata.packages_distributions()


def resolve_distribution_information(plugin_spec: PluginSpec) -> Optional[metadata.Distribution]:
"""
Resolves for a PluginSpec the python distribution package it comes from. Currently, this raises an
error for plugins that come from a namespace package (i.e., when a package is part of multiple
distributions).
:param plugin_spec: the plugin spec to resolve
:return: the Distribution metadata if it exists
"""
package = inspect.getmodule(plugin_spec.factory).__name__
root_package = package.split(".")[0]
distributions = packages_distributions().get(root_package)
if not distributions:
return None
if len(distributions) > 1:
raise ValueError("cannot deal with plugins that are part of namespace packages")

return metadata.distribution(distributions[0])
12 changes: 12 additions & 0 deletions tests/test_metadata.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from plugin import PluginSpec
from plugin.metadata import resolve_distribution_information


def test_resolve_distribution_information():
import pytest

# fake a plugin spec and use pytest as test object
fake_plugin_spec = PluginSpec("foo", "bar", pytest.fixture)
dist = resolve_distribution_information(fake_plugin_spec)
assert dist.name == "pytest"
assert dist.metadata["License"] == "MIT"

0 comments on commit 4e93357

Please sign in to comment.