[PR #4813] [MERGED] Don't ignore ImportErrors raised when loading a plugin. Fixes #4805 #12924

Closed
opened 2025-12-29 22:24:24 +01:00 by adam · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/netbox-community/netbox/pull/4813
Author: @glennmatthews
Created: 7/1/2020
Status: Merged
Merged: 7/15/2020
Merged by: @jeremystretch

Base: developHead: gfm-issue-4805


📝 Commits (2)

  • f807d3a Don't ignore ImportErrors raised when loading a plugin. Fixes #4805
  • 0fd3c83 Refactor repeated import code

📊 Changes

4 files changed (+51 additions, -23 deletions)

View changed files

📝 netbox/extras/plugins/__init__.py (+6 -9)
📝 netbox/extras/plugins/urls.py (+6 -9)
netbox/extras/plugins/utils.py (+33 -0)
📝 netbox/extras/plugins/views.py (+6 -5)

📄 Description

Fixes: #4805

Django's import_string function is convenient to use, but it's difficult to distinguish between an ImportError raised by this function (because the string describes a module/object that does not exist) versus an ImportError raised by incorrect code in the module being imported. When NetBox is loading a plugin, the former should be ignored (as a plugin is not required to implement all possible entry points supported by the plugins API) but we are incorrectly ignoring the latter as well (which represent a real bug in the plugin code, and should not be ignored).

Solution: move away from the use of import_string to use more granular functions from importlib that let us distinguish between "module does not exist" and "module exists but throws an ImportError while being loaded".

Example of a plugin error now being correctly raised rather than caught:

netbox_1    | Exception in thread django-main-thread:
netbox_1    | Traceback (most recent call last):
netbox_1    |   File "/usr/local/lib/python3.7/threading.py", line 926, in _bootstrap_inner
netbox_1    |     self.run()
netbox_1    |   File "/usr/local/lib/python3.7/threading.py", line 870, in run
netbox_1    |     self._target(*self._args, **self._kwargs)
netbox_1    |   File "/usr/local/lib/python3.7/site-packages/django/utils/autoreload.py", line 53, in wrapper
netbox_1    |     fn(*args, **kwargs)
netbox_1    |   File "/usr/local/lib/python3.7/site-packages/django/core/management/commands/runserver.py", line 109, in inner_run
netbox_1    |     autoreload.raise_last_exception()
netbox_1    |   File "/usr/local/lib/python3.7/site-packages/django/utils/autoreload.py", line 76, in raise_last_exception
netbox_1    |     raise _exception[1]
netbox_1    |   File "/usr/local/lib/python3.7/site-packages/django/core/management/__init__.py", line 357, in execute
netbox_1    |     autoreload.check_errors(django.setup)()
netbox_1    |   File "/usr/local/lib/python3.7/site-packages/django/utils/autoreload.py", line 53, in wrapper
netbox_1    |     fn(*args, **kwargs)
netbox_1    |   File "/usr/local/lib/python3.7/site-packages/django/__init__.py", line 24, in setup
netbox_1    |     apps.populate(settings.INSTALLED_APPS)
netbox_1    |   File "/usr/local/lib/python3.7/site-packages/django/apps/registry.py", line 122, in populate
netbox_1    |     app_config.ready()
netbox_1    |   File "/opt/netbox/netbox/extras/plugins/__init__.py", line 77, in ready
netbox_1    |     spec.loader.exec_module(navigation)
netbox_1    |   File "<frozen importlib._bootstrap_external>", line 728, in exec_module
netbox_1    |   File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
netbox_1    |   File "/plugins/myplugin/navigation.py", line 6, in <module>
netbox_1    |     import foo
netbox_1    | ModuleNotFoundError: No module named 'foo'

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/netbox-community/netbox/pull/4813 **Author:** [@glennmatthews](https://github.com/glennmatthews) **Created:** 7/1/2020 **Status:** ✅ Merged **Merged:** 7/15/2020 **Merged by:** [@jeremystretch](https://github.com/jeremystretch) **Base:** `develop` ← **Head:** `gfm-issue-4805` --- ### 📝 Commits (2) - [`f807d3a`](https://github.com/netbox-community/netbox/commit/f807d3a024e99c02ab2246d753d30e82dbee1d19) Don't ignore ImportErrors raised when loading a plugin. Fixes #4805 - [`0fd3c83`](https://github.com/netbox-community/netbox/commit/0fd3c838613341fc5eb5c95086cff1dcabd8808d) Refactor repeated import code ### 📊 Changes **4 files changed** (+51 additions, -23 deletions) <details> <summary>View changed files</summary> 📝 `netbox/extras/plugins/__init__.py` (+6 -9) 📝 `netbox/extras/plugins/urls.py` (+6 -9) ➕ `netbox/extras/plugins/utils.py` (+33 -0) 📝 `netbox/extras/plugins/views.py` (+6 -5) </details> ### 📄 Description ### Fixes: #4805 Django's `import_string` function is convenient to use, but it's difficult to distinguish between an `ImportError` raised by this function (because the string describes a module/object that does not exist) versus an `ImportError` raised by incorrect code in the module being imported. When NetBox is loading a plugin, the former should be ignored (as a plugin is not required to implement all possible entry points supported by the plugins API) but we are incorrectly ignoring the latter as well (which represent a real bug in the plugin code, and should not be ignored). Solution: move away from the use of `import_string` to use more granular functions from `importlib` that let us distinguish between "module does not exist" and "module exists but throws an `ImportError` while being loaded". Example of a plugin error now being correctly raised rather than caught: ``` netbox_1 | Exception in thread django-main-thread: netbox_1 | Traceback (most recent call last): netbox_1 | File "/usr/local/lib/python3.7/threading.py", line 926, in _bootstrap_inner netbox_1 | self.run() netbox_1 | File "/usr/local/lib/python3.7/threading.py", line 870, in run netbox_1 | self._target(*self._args, **self._kwargs) netbox_1 | File "/usr/local/lib/python3.7/site-packages/django/utils/autoreload.py", line 53, in wrapper netbox_1 | fn(*args, **kwargs) netbox_1 | File "/usr/local/lib/python3.7/site-packages/django/core/management/commands/runserver.py", line 109, in inner_run netbox_1 | autoreload.raise_last_exception() netbox_1 | File "/usr/local/lib/python3.7/site-packages/django/utils/autoreload.py", line 76, in raise_last_exception netbox_1 | raise _exception[1] netbox_1 | File "/usr/local/lib/python3.7/site-packages/django/core/management/__init__.py", line 357, in execute netbox_1 | autoreload.check_errors(django.setup)() netbox_1 | File "/usr/local/lib/python3.7/site-packages/django/utils/autoreload.py", line 53, in wrapper netbox_1 | fn(*args, **kwargs) netbox_1 | File "/usr/local/lib/python3.7/site-packages/django/__init__.py", line 24, in setup netbox_1 | apps.populate(settings.INSTALLED_APPS) netbox_1 | File "/usr/local/lib/python3.7/site-packages/django/apps/registry.py", line 122, in populate netbox_1 | app_config.ready() netbox_1 | File "/opt/netbox/netbox/extras/plugins/__init__.py", line 77, in ready netbox_1 | spec.loader.exec_module(navigation) netbox_1 | File "<frozen importlib._bootstrap_external>", line 728, in exec_module netbox_1 | File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed netbox_1 | File "/plugins/myplugin/navigation.py", line 6, in <module> netbox_1 | import foo netbox_1 | ModuleNotFoundError: No module named 'foo' ``` --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
adam added the pull-request label 2025-12-29 22:24:24 +01:00
adam closed this issue 2025-12-29 22:24:24 +01:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/netbox#12924