mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-17 04:32:51 -06:00
Don't ignore ImportErrors raised when loading a plugin. Fixes #4805
This commit is contained in:
parent
43d610405f
commit
f807d3a024
@ -1,12 +1,13 @@
|
|||||||
import collections
|
import collections
|
||||||
|
import importlib
|
||||||
import inspect
|
import inspect
|
||||||
|
import sys
|
||||||
from packaging import version
|
from packaging import version
|
||||||
|
|
||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.template.loader import get_template
|
from django.template.loader import get_template
|
||||||
from django.utils.module_loading import import_string
|
|
||||||
|
|
||||||
from extras.registry import registry
|
from extras.registry import registry
|
||||||
from utilities.choices import ButtonColorChoices
|
from utilities.choices import ButtonColorChoices
|
||||||
@ -60,18 +61,26 @@ class PluginConfig(AppConfig):
|
|||||||
def ready(self):
|
def ready(self):
|
||||||
|
|
||||||
# Register template content
|
# Register template content
|
||||||
try:
|
module, attr = f"{self.__module__}.{self.template_extensions}".rsplit('.', 1)
|
||||||
template_extensions = import_string(f"{self.__module__}.{self.template_extensions}")
|
spec = importlib.util.find_spec(module)
|
||||||
register_template_extensions(template_extensions)
|
if spec is not None:
|
||||||
except ImportError:
|
template_content = importlib.util.module_from_spec(spec)
|
||||||
pass
|
sys.modules[module] = template_content
|
||||||
|
spec.loader.exec_module(template_content)
|
||||||
|
if hasattr(template_content, attr):
|
||||||
|
template_extensions = getattr(template_content, attr)
|
||||||
|
register_template_extensions(template_extensions)
|
||||||
|
|
||||||
# Register navigation menu items (if defined)
|
# Register navigation menu items (if defined)
|
||||||
try:
|
module, attr = f"{self.__module__}.{self.menu_items}".rsplit('.', 1)
|
||||||
menu_items = import_string(f"{self.__module__}.{self.menu_items}")
|
spec = importlib.util.find_spec(module)
|
||||||
register_menu_items(self.verbose_name, menu_items)
|
if spec is not None:
|
||||||
except ImportError:
|
navigation = importlib.util.module_from_spec(spec)
|
||||||
pass
|
sys.modules[module] = navigation
|
||||||
|
spec.loader.exec_module(navigation)
|
||||||
|
if hasattr(navigation, attr):
|
||||||
|
menu_items = getattr(navigation, attr)
|
||||||
|
register_menu_items(self.verbose_name, menu_items)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def validate(cls, user_config):
|
def validate(cls, user_config):
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
|
import importlib
|
||||||
|
import sys
|
||||||
|
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.conf.urls import include
|
from django.conf.urls import include
|
||||||
from django.contrib.admin.views.decorators import staff_member_required
|
from django.contrib.admin.views.decorators import staff_member_required
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
from django.utils.module_loading import import_string
|
|
||||||
|
|
||||||
from . import views
|
from . import views
|
||||||
|
|
||||||
@ -24,19 +26,29 @@ for plugin_path in settings.PLUGINS:
|
|||||||
base_url = getattr(app, 'base_url') or app.label
|
base_url = getattr(app, 'base_url') or app.label
|
||||||
|
|
||||||
# Check if the plugin specifies any base URLs
|
# Check if the plugin specifies any base URLs
|
||||||
try:
|
spec = importlib.util.find_spec(f"{plugin_path}.urls")
|
||||||
urlpatterns = import_string(f"{plugin_path}.urls.urlpatterns")
|
if spec is not None:
|
||||||
plugin_patterns.append(
|
# The plugin has a .urls module - import it
|
||||||
path(f"{base_url}/", include((urlpatterns, app.label)))
|
urls = importlib.util.module_from_spec(spec)
|
||||||
)
|
sys.modules[f"{plugin_path}.urls"] = urls
|
||||||
except ImportError:
|
spec.loader.exec_module(urls)
|
||||||
pass
|
if hasattr(urls, "urlpatterns"):
|
||||||
|
urlpatterns = urls.urlpatterns
|
||||||
|
plugin_patterns.append(
|
||||||
|
path(f"{base_url}/", include((urlpatterns, app.label)))
|
||||||
|
)
|
||||||
|
|
||||||
# Check if the plugin specifies any API URLs
|
# Check if the plugin specifies any API URLs
|
||||||
try:
|
spec = importlib.util.find_spec(f"{plugin_path}.api")
|
||||||
urlpatterns = import_string(f"{plugin_path}.api.urls.urlpatterns")
|
if spec is not None:
|
||||||
plugin_api_patterns.append(
|
spec = importlib.util.find_spec(f"{plugin_path}.api.urls")
|
||||||
path(f"{base_url}/", include((urlpatterns, f"{app.label}-api")))
|
if spec is not None:
|
||||||
)
|
# The plugin has a .api.urls module - import it
|
||||||
except ImportError:
|
api_urls = importlib.util.module_from_spec(spec)
|
||||||
pass
|
sys.modules[f"{plugin_path}.api.urls"] = api_urls
|
||||||
|
spec.loader.exec_module(api_urls)
|
||||||
|
if hasattr(api_urls, "urlpatterns"):
|
||||||
|
urlpatterns = api_urls.urlpatterns
|
||||||
|
plugin_api_patterns.append(
|
||||||
|
path(f"{base_url}/", include((urlpatterns, f"{app.label}-api")))
|
||||||
|
)
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
import importlib
|
||||||
|
import sys
|
||||||
|
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.urls.exceptions import NoReverseMatch
|
from django.urls.exceptions import NoReverseMatch
|
||||||
from django.utils.module_loading import import_string
|
|
||||||
from django.views.generic import View
|
from django.views.generic import View
|
||||||
from rest_framework import permissions
|
from rest_framework import permissions
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
@ -60,11 +61,23 @@ class PluginsAPIRootView(APIView):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_plugin_entry(plugin, app_config, request, format):
|
def _get_plugin_entry(plugin, app_config, request, format):
|
||||||
try:
|
# Check if the plugin specifies any API URLs
|
||||||
api_app_name = import_string(f"{plugin}.api.urls.app_name")
|
spec = importlib.util.find_spec(f"{plugin}.api")
|
||||||
except (ImportError, ModuleNotFoundError):
|
if spec is None:
|
||||||
# Plugin does not expose an API
|
# There is no plugin.api module
|
||||||
return None
|
return None
|
||||||
|
spec = importlib.util.find_spec(f"{plugin}.api.urls")
|
||||||
|
if spec is None:
|
||||||
|
# There is no plugin.api.urls module
|
||||||
|
return None
|
||||||
|
# The plugin has a .api.urls module - import it
|
||||||
|
api_urls = importlib.util.module_from_spec(spec)
|
||||||
|
sys.modules[f"{plugin}.api.urls"] = api_urls
|
||||||
|
spec.loader.exec_module(api_urls)
|
||||||
|
if not hasattr(api_urls, "app_name"):
|
||||||
|
# The plugin api.urls does not declare an app_name string
|
||||||
|
return None
|
||||||
|
api_app_name = api_urls.app_name
|
||||||
|
|
||||||
try:
|
try:
|
||||||
entry = (getattr(app_config, 'base_url', app_config.label), reverse(
|
entry = (getattr(app_config, 'base_url', app_config.label), reverse(
|
||||||
@ -73,7 +86,7 @@ class PluginsAPIRootView(APIView):
|
|||||||
format=format
|
format=format
|
||||||
))
|
))
|
||||||
except NoReverseMatch:
|
except NoReverseMatch:
|
||||||
# The plugin does not include an api-root
|
# The plugin does not include an api-root url
|
||||||
entry = None
|
entry = None
|
||||||
|
|
||||||
return entry
|
return entry
|
||||||
|
Loading…
Reference in New Issue
Block a user