mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Refactor repeated import code
This commit is contained in:
@ -1,7 +1,5 @@
|
||||
import collections
|
||||
import importlib
|
||||
import inspect
|
||||
import sys
|
||||
from packaging import version
|
||||
|
||||
from django.apps import AppConfig
|
||||
@ -12,6 +10,8 @@ from django.template.loader import get_template
|
||||
from extras.registry import registry
|
||||
from utilities.choices import ButtonColorChoices
|
||||
|
||||
from extras.plugins.utils import import_object
|
||||
|
||||
|
||||
# Initialize plugin registry stores
|
||||
registry['plugin_template_extensions'] = collections.defaultdict(list)
|
||||
@ -61,25 +61,13 @@ class PluginConfig(AppConfig):
|
||||
def ready(self):
|
||||
|
||||
# Register template content
|
||||
module, attr = f"{self.__module__}.{self.template_extensions}".rsplit('.', 1)
|
||||
spec = importlib.util.find_spec(module)
|
||||
if spec is not None:
|
||||
template_content = importlib.util.module_from_spec(spec)
|
||||
sys.modules[module] = template_content
|
||||
spec.loader.exec_module(template_content)
|
||||
if hasattr(template_content, attr):
|
||||
template_extensions = getattr(template_content, attr)
|
||||
template_extensions = import_object(f"{self.__module__}.{self.template_extensions}")
|
||||
if template_extensions is not None:
|
||||
register_template_extensions(template_extensions)
|
||||
|
||||
# Register navigation menu items (if defined)
|
||||
module, attr = f"{self.__module__}.{self.menu_items}".rsplit('.', 1)
|
||||
spec = importlib.util.find_spec(module)
|
||||
if spec is not None:
|
||||
navigation = importlib.util.module_from_spec(spec)
|
||||
sys.modules[module] = navigation
|
||||
spec.loader.exec_module(navigation)
|
||||
if hasattr(navigation, attr):
|
||||
menu_items = getattr(navigation, attr)
|
||||
menu_items = import_object(f"{self.__module__}.{self.menu_items}")
|
||||
if menu_items is not None:
|
||||
register_menu_items(self.verbose_name, menu_items)
|
||||
|
||||
@classmethod
|
||||
|
@ -1,12 +1,11 @@
|
||||
import importlib
|
||||
import sys
|
||||
|
||||
from django.apps import apps
|
||||
from django.conf import settings
|
||||
from django.conf.urls import include
|
||||
from django.contrib.admin.views.decorators import staff_member_required
|
||||
from django.urls import path
|
||||
|
||||
from extras.plugins.utils import import_object
|
||||
|
||||
from . import views
|
||||
|
||||
# Initialize URL base, API, and admin URL patterns for plugins
|
||||
@ -26,29 +25,15 @@ for plugin_path in settings.PLUGINS:
|
||||
base_url = getattr(app, 'base_url') or app.label
|
||||
|
||||
# Check if the plugin specifies any base URLs
|
||||
spec = importlib.util.find_spec(f"{plugin_path}.urls")
|
||||
if spec is not None:
|
||||
# The plugin has a .urls module - import it
|
||||
urls = importlib.util.module_from_spec(spec)
|
||||
sys.modules[f"{plugin_path}.urls"] = urls
|
||||
spec.loader.exec_module(urls)
|
||||
if hasattr(urls, "urlpatterns"):
|
||||
urlpatterns = urls.urlpatterns
|
||||
urlpatterns = import_object(f"{plugin_path}.urls.urlpatterns")
|
||||
if urlpatterns is not None:
|
||||
plugin_patterns.append(
|
||||
path(f"{base_url}/", include((urlpatterns, app.label)))
|
||||
)
|
||||
|
||||
# Check if the plugin specifies any API URLs
|
||||
spec = importlib.util.find_spec(f"{plugin_path}.api")
|
||||
if spec is not None:
|
||||
spec = importlib.util.find_spec(f"{plugin_path}.api.urls")
|
||||
if spec is not None:
|
||||
# The plugin has a .api.urls module - import it
|
||||
api_urls = importlib.util.module_from_spec(spec)
|
||||
sys.modules[f"{plugin_path}.api.urls"] = api_urls
|
||||
spec.loader.exec_module(api_urls)
|
||||
if hasattr(api_urls, "urlpatterns"):
|
||||
urlpatterns = api_urls.urlpatterns
|
||||
urlpatterns = import_object(f"{plugin_path}.api.urls.urlpatterns")
|
||||
if urlpatterns is not None:
|
||||
plugin_api_patterns.append(
|
||||
path(f"{base_url}/", include((urlpatterns, f"{app.label}-api")))
|
||||
)
|
||||
|
33
netbox/extras/plugins/utils.py
Normal file
33
netbox/extras/plugins/utils.py
Normal file
@ -0,0 +1,33 @@
|
||||
import importlib.util
|
||||
import sys
|
||||
|
||||
|
||||
def import_object(module_and_object):
|
||||
"""
|
||||
Import a specific object from a specific module by name, such as "extras.plugins.utils.import_object".
|
||||
|
||||
Returns the imported object, or None if it doesn't exist.
|
||||
"""
|
||||
target_module_name, object_name = module_and_object.rsplit('.', 1)
|
||||
module_hierarchy = target_module_name.split('.')
|
||||
|
||||
# Iterate through the module hierarchy, checking for the existence of each successive submodule.
|
||||
# We have to do this rather than jumping directly to calling find_spec(target_module_name)
|
||||
# because find_spec will raise a ModuleNotFoundError if any parent module of target_module_name does not exist.
|
||||
module_name = ""
|
||||
for module_component in module_hierarchy:
|
||||
module_name = f"{module_name}.{module_component}" if module_name else module_component
|
||||
spec = importlib.util.find_spec(module_name)
|
||||
if spec is None:
|
||||
# No such module
|
||||
return None
|
||||
|
||||
# Okay, target_module_name exists. Load it if not already loaded
|
||||
if target_module_name in sys.modules:
|
||||
module = sys.modules[target_module_name]
|
||||
else:
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
sys.modules[target_module_name] = module
|
||||
spec.loader.exec_module(module)
|
||||
|
||||
return getattr(module, object_name, None)
|
@ -1,6 +1,4 @@
|
||||
from collections import OrderedDict
|
||||
import importlib
|
||||
import sys
|
||||
|
||||
from django.apps import apps
|
||||
from django.conf import settings
|
||||
@ -12,6 +10,8 @@ from rest_framework.response import Response
|
||||
from rest_framework.reverse import reverse
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from extras.plugins.utils import import_object
|
||||
|
||||
|
||||
class InstalledPluginsAdminView(View):
|
||||
"""
|
||||
@ -62,22 +62,10 @@ class PluginsAPIRootView(APIView):
|
||||
@staticmethod
|
||||
def _get_plugin_entry(plugin, app_config, request, format):
|
||||
# Check if the plugin specifies any API URLs
|
||||
spec = importlib.util.find_spec(f"{plugin}.api")
|
||||
if spec is None:
|
||||
# There is no plugin.api module
|
||||
api_app_name = import_object(f"{plugin}.api.urls.app_name")
|
||||
if api_app_name is None:
|
||||
# Plugin does not expose an API
|
||||
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:
|
||||
entry = (getattr(app_config, 'base_url', app_config.label), reverse(
|
||||
|
Reference in New Issue
Block a user