Plugin meta detection improvements (#3516)

* refactor entrypoint into helpers

* Add lookup by metadata
This is geared towards plugins packaged in pkgs that differ in name from their top module

* Make module lookup predictable in changing pkg-envs
This commit is contained in:
Matthias Mair 2022-08-11 04:02:06 +02:00 committed by GitHub
parent 4ae3cf9a9c
commit 1010a6296f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 49 additions and 7 deletions

View File

@ -7,6 +7,9 @@ import pkgutil
import subprocess
import sysconfig
import traceback
from importlib.metadata import (PackageNotFoundError, distributions,
entry_points)
from importlib.util import find_spec
from django import template
from django.conf import settings
@ -92,6 +95,11 @@ def handle_error(error, do_raise: bool = True, do_log: bool = True, log_name: st
if settings.TESTING_ENV and package_name != 'integration.broken_sample' and isinstance(error, IntegrityError):
raise error # pragma: no cover
raise IntegrationPluginError(package_name, str(error))
def get_entrypoints():
"""Returns list for entrypoints for InvenTree plugins."""
return entry_points().get('inventree_plugins', [])
# endregion
@ -223,6 +231,34 @@ def get_plugins(pkg, baseclass, path=None):
plugins.append(plugin)
return plugins
def get_module_meta(mdl_name):
"""Return distribution for module.
Modified form source: https://stackoverflow.com/a/60975978/17860466
"""
# Get spec for module
spec = find_spec(mdl_name)
# Try to get specific package for the module
result = None
for dist in distributions():
try:
relative = pathlib.Path(spec.origin).relative_to(dist.locate_file(''))
except ValueError:
pass
else:
if relative in dist.files:
result = dist
# Check if a distribution was found
# A no should not be possible here as a call can only be made on a discovered module but better save then sorry
if not result:
raise PackageNotFoundError(mdl_name)
# Return metadata
return result.metadata
# endregion

View File

@ -6,7 +6,7 @@ import os
import pathlib
import warnings
from datetime import datetime
from importlib.metadata import metadata
from importlib.metadata import PackageNotFoundError, metadata
from django.conf import settings
from django.db.utils import OperationalError, ProgrammingError
@ -14,7 +14,7 @@ from django.urls.base import reverse
from django.utils.text import slugify
from django.utils.translation import gettext_lazy as _
from plugin.helpers import GitStatus, get_git_log
from plugin.helpers import GitStatus, get_git_log, get_module_meta
logger = logging.getLogger("inventree")
@ -294,7 +294,13 @@ class InvenTreePlugin(MixinBase, MetaBase):
@classmethod
def _get_package_metadata(cls):
"""Get package metadata for plugin."""
meta = metadata(cls.__name__)
# Try simple metadata lookup
try:
meta = metadata(cls.__name__)
# Simpel lookup did not work - get data from module
except PackageNotFoundError:
meta = get_module_meta(cls.__module__)
return {
'author': meta['Author-email'],

View File

@ -8,7 +8,7 @@ import importlib
import logging
import os
import subprocess
from importlib import metadata, reload
from importlib import reload
from pathlib import Path
from typing import OrderedDict
@ -24,8 +24,8 @@ from maintenance_mode.core import (get_maintenance_mode, maintenance_mode_on,
from InvenTree.config import get_setting
from .helpers import (IntegrationPluginError, get_plugins, handle_error,
log_error)
from .helpers import (IntegrationPluginError, get_entrypoints, get_plugins,
handle_error, log_error)
from .plugin import InvenTreePlugin
logger = logging.getLogger('inventree')
@ -266,7 +266,7 @@ class PluginsRegistry:
# Check if not running in testing mode and apps should be loaded from hooks
if (not settings.PLUGIN_TESTING) or (settings.PLUGIN_TESTING and settings.PLUGIN_TESTING_SETUP):
# Collect plugins from setup entry points
for entry in metadata.entry_points().get('inventree_plugins', []): # pragma: no cover
for entry in get_entrypoints(): # pragma: no cover
try:
plugin = entry.load()
plugin.is_package = True