diff --git a/InvenTree/plugin/helpers.py b/InvenTree/plugin/helpers.py index 89edb1a571..723543caea 100644 --- a/InvenTree/plugin/helpers.py +++ b/InvenTree/plugin/helpers.py @@ -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 diff --git a/InvenTree/plugin/plugin.py b/InvenTree/plugin/plugin.py index b59b42bc3b..2bf849c56e 100644 --- a/InvenTree/plugin/plugin.py +++ b/InvenTree/plugin/plugin.py @@ -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'], diff --git a/InvenTree/plugin/registry.py b/InvenTree/plugin/registry.py index f60972accb..5d05cb4ecc 100644 --- a/InvenTree/plugin/registry.py +++ b/InvenTree/plugin/registry.py @@ -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