NestedCircuitSerializer import failure #10533

Closed
opened 2025-12-29 21:32:47 +01:00 by adam · 3 comments
Owner

Originally created by @dmulyalin on GitHub (Dec 3, 2024).

Deployment Type

Self-hosted

Triage priority

N/A

NetBox Version

v4.1.7

Python Version

3.10

Steps to Reproduce

I am using custom plugin with this code importing nested serializers:

[plugin_folder/api/serializers.py]
from rest_framework import serializers
from ipam.api.nested_serializers import NestedPrefixSerializer, NestedIPAddressSerializer, NestedVLANSerializer, NestedVRFSerializer
from dcim.api.nested_serializers import NestedSiteSerializer, NestedInterfaceSerializer, NestedDeviceSerializer
from circuits.api.nested_serializers import NestedCircuitSerializer
from tenancy.api.nested_serializers import NestedTenantSerializer
from netbox.api.serializers import NetBoxModelSerializer, WritableNestedSerializer
from netbox.api.fields import SerializedPKRelatedField, ChoiceField
from django.contrib.postgres.fields import ArrayField

...skip

but netbox fails to start with this error:

netbox-1               | 🧬 loaded config '/etc/netbox/config/plugins.py'
netbox-1               | Traceback (most recent call last):
netbox-1               |   File "/opt/netbox/netbox/./manage.py", line 10, in <module>
netbox-1               |     execute_from_command_line(sys.argv)
netbox-1               |   File "/opt/netbox/venv/lib/python3.12/site-packages/django/core/management/__init__.py", line 442, in execute_from_command_line
netbox-1               |     utility.execute()
netbox-1               |   File "/opt/netbox/venv/lib/python3.12/site-packages/django/core/management/__init__.py", line 436, in execute
netbox-1               |     self.fetch_command(subcommand).run_from_argv(self.argv)
netbox-1               |   File "/opt/netbox/venv/lib/python3.12/site-packages/django/core/management/base.py", line 413, in run_from_argv
netbox-1               |     self.execute(*args, **cmd_options)
netbox-1               |   File "/opt/netbox/venv/lib/python3.12/site-packages/django/core/management/base.py", line 454, in execute
netbox-1               |     self.check()
netbox-1               |   File "/opt/netbox/venv/lib/python3.12/site-packages/django/core/management/base.py", line 486, in check
netbox-1               |     all_issues = checks.run_checks(
netbox-1               |                  ^^^^^^^^^^^^^^^^^^
netbox-1               |   File "/opt/netbox/venv/lib/python3.12/site-packages/django/core/checks/registry.py", line 88, in run_checks
netbox-1               |     new_errors = check(app_configs=app_configs, databases=databases)
netbox-1               |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
netbox-1               |   File "/opt/netbox/venv/lib/python3.12/site-packages/django/core/checks/urls.py", line 42, in check_url_namespaces_unique
netbox-1               |     all_namespaces = _load_all_namespaces(resolver)
netbox-1               |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
netbox-1               |   File "/opt/netbox/venv/lib/python3.12/site-packages/django/core/checks/urls.py", line 61, in _load_all_namespaces
netbox-1               |     url_patterns = getattr(resolver, "url_patterns", [])
netbox-1               |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
netbox-1               |   File "/opt/netbox/venv/lib/python3.12/site-packages/django/utils/functional.py", line 47, in __get__
netbox-1               |     res = instance.__dict__[self.name] = self.func(instance)
netbox-1               |                                          ^^^^^^^^^^^^^^^^^^^
netbox-1               |   File "/opt/netbox/venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 738, in url_patterns
netbox-1               |     patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
netbox-1               |                        ^^^^^^^^^^^^^^^^^^^
netbox-1               |   File "/opt/netbox/venv/lib/python3.12/site-packages/django/utils/functional.py", line 47, in __get__
netbox-1               |     res = instance.__dict__[self.name] = self.func(instance)
netbox-1               |                                          ^^^^^^^^^^^^^^^^^^^
netbox-1               |   File "/opt/netbox/venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 731, in urlconf_module
netbox-1               |     return import_module(self.urlconf_name)
netbox-1               |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
netbox-1               |   File "/usr/lib/python3.12/importlib/__init__.py", line 90, in import_module
netbox-1               |     return _bootstrap._gcd_import(name[level:], package, level)
netbox-1               |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
netbox-1               |   File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
netbox-1               |   File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
netbox-1               |   File "<frozen importlib._bootstrap>", line 1331, in _find_and_load_unlocked
netbox-1               |   File "<frozen importlib._bootstrap>", line 935, in _load_unlocked
netbox-1               |   File "<frozen importlib._bootstrap_external>", line 995, in exec_module
netbox-1               |   File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
netbox-1               |   File "/opt/netbox/netbox/netbox/urls.py", line 11, in <module>
netbox-1               |     from netbox.plugins.urls import plugin_patterns, plugin_api_patterns
netbox-1               |   File "/opt/netbox/netbox/netbox/plugins/urls.py", line 34, in <module>
netbox-1               |     urlpatterns = import_string(f"{plugin_path}.api.urls.urlpatterns")
netbox-1               |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
netbox-1               |   File "/opt/netbox/venv/lib/python3.12/site-packages/django/utils/module_loading.py", line 30, in import_string
netbox-1               |     return cached_import(module_path, class_name)
netbox-1               |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
netbox-1               |   File "/opt/netbox/venv/lib/python3.12/site-packages/django/utils/module_loading.py", line 15, in cached_import
netbox-1               |     module = import_module(module_path)
netbox-1               |              ^^^^^^^^^^^^^^^^^^^^^^^^^^
netbox-1               |   File "/usr/lib/python3.12/importlib/__init__.py", line 90, in import_module
netbox-1               |     return _bootstrap._gcd_import(name[level:], package, level)
netbox-1               |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
netbox-1               |   File "/opt/netbox/venv/lib/python3.12/site-packages/custom_plugin/api/urls.py", line 2, in <module>
netbox-1               |     from . import views
netbox-1               |   File "/opt/netbox/venv/lib/python3.12/site-packages/custom_plugin/api/serializers.py", line 5, in <module>
netbox-1               |     from tenancy.api.nested_serializers import NestedTenantSerializer
netbox-1               |   File "/opt/netbox/netbox/tenancy/api/nested_serializers.py", line 4, in <module>
netbox-1               |     from serializers_.nested import NestedContactGroupSerializer, NestedTenantGroupSerializer
netbox-1               | ModuleNotFoundError: No module named 'serializers_'

to fix this had to introduce this change to substitute NestedTenantSerializer import:

from rest_framework import serializers
from ipam.api.nested_serializers import NestedPrefixSerializer, NestedIPAddressSerializer, NestedVLANSerializer, NestedVRFSerializer
from dcim.api.nested_serializers import NestedSiteSerializer, NestedInterfaceSerializer, NestedDeviceSerializer
from circuits.api.nested_serializers import NestedCircuitSerializer
# from tenancy.api.nested_serializers import NestedTenantSerializer
from tenancy.models import Tenant
from netbox.api.serializers import NetBoxModelSerializer, WritableNestedSerializer
from netbox.api.fields import SerializedPKRelatedField, ChoiceField
from django.contrib.postgres.fields import ArrayField

class NestedTenantSerializer(WritableNestedSerializer):

    class Meta:
        model = Tenant
        fields = ['id', 'url', 'display_url', 'display', 'name', 'slug']

It seems that No module named 'serializers_' error is coming from this import: d122c334fd/netbox/tenancy/api/nested_serializers.py (L4)

where it should be this import instead?

from .serializers_.nested import NestedContactGroupSerializer, NestedTenantGroupSerializer

notice from .serializers_.nested with dot instead of from serializers_.nested , similar to how it is done for other nested serializers e.g. d122c334fd/netbox/ipam/api/nested_serializers.py (L10) or d122c334fd/netbox/dcim/api/nested_serializers.py (L9)

Expected Behavior

from tenancy.api.nested_serializers import NestedTenantSerializer import should work with no error

Observed Behavior

Observing ModuleNotFoundError: No module named 'serializers_' error

Originally created by @dmulyalin on GitHub (Dec 3, 2024). ### Deployment Type Self-hosted ### Triage priority N/A ### NetBox Version v4.1.7 ### Python Version 3.10 ### Steps to Reproduce I am using custom plugin with this code importing nested serializers: ``` [plugin_folder/api/serializers.py] from rest_framework import serializers from ipam.api.nested_serializers import NestedPrefixSerializer, NestedIPAddressSerializer, NestedVLANSerializer, NestedVRFSerializer from dcim.api.nested_serializers import NestedSiteSerializer, NestedInterfaceSerializer, NestedDeviceSerializer from circuits.api.nested_serializers import NestedCircuitSerializer from tenancy.api.nested_serializers import NestedTenantSerializer from netbox.api.serializers import NetBoxModelSerializer, WritableNestedSerializer from netbox.api.fields import SerializedPKRelatedField, ChoiceField from django.contrib.postgres.fields import ArrayField ...skip ``` but netbox fails to start with this error: ``` netbox-1 | 🧬 loaded config '/etc/netbox/config/plugins.py' netbox-1 | Traceback (most recent call last): netbox-1 | File "/opt/netbox/netbox/./manage.py", line 10, in <module> netbox-1 | execute_from_command_line(sys.argv) netbox-1 | File "/opt/netbox/venv/lib/python3.12/site-packages/django/core/management/__init__.py", line 442, in execute_from_command_line netbox-1 | utility.execute() netbox-1 | File "/opt/netbox/venv/lib/python3.12/site-packages/django/core/management/__init__.py", line 436, in execute netbox-1 | self.fetch_command(subcommand).run_from_argv(self.argv) netbox-1 | File "/opt/netbox/venv/lib/python3.12/site-packages/django/core/management/base.py", line 413, in run_from_argv netbox-1 | self.execute(*args, **cmd_options) netbox-1 | File "/opt/netbox/venv/lib/python3.12/site-packages/django/core/management/base.py", line 454, in execute netbox-1 | self.check() netbox-1 | File "/opt/netbox/venv/lib/python3.12/site-packages/django/core/management/base.py", line 486, in check netbox-1 | all_issues = checks.run_checks( netbox-1 | ^^^^^^^^^^^^^^^^^^ netbox-1 | File "/opt/netbox/venv/lib/python3.12/site-packages/django/core/checks/registry.py", line 88, in run_checks netbox-1 | new_errors = check(app_configs=app_configs, databases=databases) netbox-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ netbox-1 | File "/opt/netbox/venv/lib/python3.12/site-packages/django/core/checks/urls.py", line 42, in check_url_namespaces_unique netbox-1 | all_namespaces = _load_all_namespaces(resolver) netbox-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ netbox-1 | File "/opt/netbox/venv/lib/python3.12/site-packages/django/core/checks/urls.py", line 61, in _load_all_namespaces netbox-1 | url_patterns = getattr(resolver, "url_patterns", []) netbox-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ netbox-1 | File "/opt/netbox/venv/lib/python3.12/site-packages/django/utils/functional.py", line 47, in __get__ netbox-1 | res = instance.__dict__[self.name] = self.func(instance) netbox-1 | ^^^^^^^^^^^^^^^^^^^ netbox-1 | File "/opt/netbox/venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 738, in url_patterns netbox-1 | patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module) netbox-1 | ^^^^^^^^^^^^^^^^^^^ netbox-1 | File "/opt/netbox/venv/lib/python3.12/site-packages/django/utils/functional.py", line 47, in __get__ netbox-1 | res = instance.__dict__[self.name] = self.func(instance) netbox-1 | ^^^^^^^^^^^^^^^^^^^ netbox-1 | File "/opt/netbox/venv/lib/python3.12/site-packages/django/urls/resolvers.py", line 731, in urlconf_module netbox-1 | return import_module(self.urlconf_name) netbox-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ netbox-1 | File "/usr/lib/python3.12/importlib/__init__.py", line 90, in import_module netbox-1 | return _bootstrap._gcd_import(name[level:], package, level) netbox-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ netbox-1 | File "<frozen importlib._bootstrap>", line 1387, in _gcd_import netbox-1 | File "<frozen importlib._bootstrap>", line 1360, in _find_and_load netbox-1 | File "<frozen importlib._bootstrap>", line 1331, in _find_and_load_unlocked netbox-1 | File "<frozen importlib._bootstrap>", line 935, in _load_unlocked netbox-1 | File "<frozen importlib._bootstrap_external>", line 995, in exec_module netbox-1 | File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed netbox-1 | File "/opt/netbox/netbox/netbox/urls.py", line 11, in <module> netbox-1 | from netbox.plugins.urls import plugin_patterns, plugin_api_patterns netbox-1 | File "/opt/netbox/netbox/netbox/plugins/urls.py", line 34, in <module> netbox-1 | urlpatterns = import_string(f"{plugin_path}.api.urls.urlpatterns") netbox-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ netbox-1 | File "/opt/netbox/venv/lib/python3.12/site-packages/django/utils/module_loading.py", line 30, in import_string netbox-1 | return cached_import(module_path, class_name) netbox-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ netbox-1 | File "/opt/netbox/venv/lib/python3.12/site-packages/django/utils/module_loading.py", line 15, in cached_import netbox-1 | module = import_module(module_path) netbox-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^ netbox-1 | File "/usr/lib/python3.12/importlib/__init__.py", line 90, in import_module netbox-1 | return _bootstrap._gcd_import(name[level:], package, level) netbox-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ netbox-1 | File "/opt/netbox/venv/lib/python3.12/site-packages/custom_plugin/api/urls.py", line 2, in <module> netbox-1 | from . import views netbox-1 | File "/opt/netbox/venv/lib/python3.12/site-packages/custom_plugin/api/serializers.py", line 5, in <module> netbox-1 | from tenancy.api.nested_serializers import NestedTenantSerializer netbox-1 | File "/opt/netbox/netbox/tenancy/api/nested_serializers.py", line 4, in <module> netbox-1 | from serializers_.nested import NestedContactGroupSerializer, NestedTenantGroupSerializer netbox-1 | ModuleNotFoundError: No module named 'serializers_' ``` to fix this had to introduce this change to substitute NestedTenantSerializer import: ``` from rest_framework import serializers from ipam.api.nested_serializers import NestedPrefixSerializer, NestedIPAddressSerializer, NestedVLANSerializer, NestedVRFSerializer from dcim.api.nested_serializers import NestedSiteSerializer, NestedInterfaceSerializer, NestedDeviceSerializer from circuits.api.nested_serializers import NestedCircuitSerializer # from tenancy.api.nested_serializers import NestedTenantSerializer from tenancy.models import Tenant from netbox.api.serializers import NetBoxModelSerializer, WritableNestedSerializer from netbox.api.fields import SerializedPKRelatedField, ChoiceField from django.contrib.postgres.fields import ArrayField class NestedTenantSerializer(WritableNestedSerializer): class Meta: model = Tenant fields = ['id', 'url', 'display_url', 'display', 'name', 'slug'] ``` It seems that `No module named 'serializers_'` error is coming from this import: https://github.com/netbox-community/netbox/blob/d122c334fdd08f277e8ce70953ef89801decd0fc/netbox/tenancy/api/nested_serializers.py#L4 where it should be this import instead? ``` from .serializers_.nested import NestedContactGroupSerializer, NestedTenantGroupSerializer ``` notice `from .serializers_.nested ` with dot instead of `from serializers_.nested `, similar to how it is done for other nested serializers e.g. https://github.com/netbox-community/netbox/blob/d122c334fdd08f277e8ce70953ef89801decd0fc/netbox/ipam/api/nested_serializers.py#L10 or https://github.com/netbox-community/netbox/blob/d122c334fdd08f277e8ce70953ef89801decd0fc/netbox/dcim/api/nested_serializers.py#L9 ### Expected Behavior `from tenancy.api.nested_serializers import NestedTenantSerializer` import should work with no error ### Observed Behavior Observing `ModuleNotFoundError: No module named 'serializers_'` error
adam closed this issue 2025-12-29 21:32:47 +01:00
Author
Owner

@jeremystretch commented on GitHub (Dec 3, 2024):

Bug reports are to be used only for issues with NetBox itself. For assistance with plugin development, please start a discussion instead.

@jeremystretch commented on GitHub (Dec 3, 2024): Bug reports are to be used only for issues with NetBox itself. For assistance with plugin development, please start a [discussion](https://github.com/netbox-community/netbox/discussions/new?category=help-wanted) instead.
Author
Owner

@dmulyalin commented on GitHub (Dec 3, 2024):

@jeremystretch Sorry I am struggling to understand how is this not an issue with Netbox itself:

netbox-1               |   File "/opt/netbox/venv/lib/python3.12/site-packages/custom_plugin/api/serializers.py", line 5, in <module>
netbox-1               |     from tenancy.api.nested_serializers import NestedTenantSerializer
netbox-1               |   File "/opt/netbox/netbox/tenancy/api/nested_serializers.py", line 4, in <module>
netbox-1               |     from serializers_.nested import NestedContactGroupSerializer, NestedTenantGroupSerializer
netbox-1               | ModuleNotFoundError: No module named 'serializers_'

My plugin is fine, do not need help with developing it, it was working on 4.0.11 but stopped working due to Netbox codebase changes introduced in 4.1.0

@dmulyalin commented on GitHub (Dec 3, 2024): @jeremystretch Sorry I am struggling to understand how is this not an issue with Netbox itself: ``` netbox-1 | File "/opt/netbox/venv/lib/python3.12/site-packages/custom_plugin/api/serializers.py", line 5, in <module> netbox-1 | from tenancy.api.nested_serializers import NestedTenantSerializer netbox-1 | File "/opt/netbox/netbox/tenancy/api/nested_serializers.py", line 4, in <module> netbox-1 | from serializers_.nested import NestedContactGroupSerializer, NestedTenantGroupSerializer netbox-1 | ModuleNotFoundError: No module named 'serializers_' ``` My plugin is fine, do not need help with developing it, it was working on 4.0.11 but stopped working due to Netbox codebase changes introduced in 4.1.0
Author
Owner

@einaram commented on GitHub (Dec 17, 2024):

I found this googling and struggled for a while. Solved it (like the code said once i found it..) using nested=True instead of the nested serializer:

 VLANSerializer(read_only=True, nested=True)
@einaram commented on GitHub (Dec 17, 2024): I found this googling and struggled for a while. Solved it (like the [code ](https://github.com/netbox-community/netbox/blob/d122c334fdd08f277e8ce70953ef89801decd0fc/netbox/ipam/api/nested_serializers.py#L33) said once i found it..) using `nested=True` instead of the nested serializer: ``` VLANSerializer(read_only=True, nested=True) ```
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/netbox#10533