AttributeError exception raised on initialization when a plugin has local imports in __init__.py #371

Closed
opened 2026-04-05 16:27:43 +02:00 by MrUnknownDE · 0 comments
Owner

Originally created by @jeremystretch on 2/12/2026

NetBox Edition

NetBox Community

NetBox Version

v4.5.2

Python Version

3.12

Steps to Reproduce

This one is a bit esoteric, so bear with me. We've discovered a regression introduced in 5c6fc2fb6f that causes an AttributeError exception on startup when an installed plugin has a choice set which registers a key for configuration. For example:

class PriorityChoices(ChoiceSet):
    key = 'FooBar.priority'

    HIGH = 3
    MEDIUM = 2
    LOW = 1

    CHOICES = [
        (HIGH, _('High'), 'red'),
        (MEDIUM, _('Medium'), 'green'),
        (LOW, _('Low'), 'blue'),
    ]

The exception will trigger if this choice set is imported prior to plugin initialization. AFAICT, this is related to importing strawberry in settings.py (to monkey-patch our custom paginator).

Expected Behavior

The above scenario is valid and should not result in an exception.

Observed Behavior

An AttributeError exception is raised:

  File "/home/jstretch/projects/test-plugin/test_plugin/__init__.py", line 3, in <module>
    from .validators import custom_validator
  File "/home/jstretch/projects/test-plugin/test_plugin/validators.py", line 4, in <module>
    from .choices import PriorityChoices
  File "/home/jstretch/projects/test-plugin/test_plugin/choices.py", line 33, in <module>
    class PriorityChoices(ChoiceSet):
  File "/home/jstretch/projects/netbox/netbox/utilities/choices.py", line 28, in __new__
    replace_choices = get_config_value_ci(settings.FIELD_CHOICES, replace_key)
                                          ^^^^^^^^^^^^^^^^^^^^^^
  File "/home/jstretch/projects/netbox/venv/lib/python3.12/site-packages/django/conf/__init__.py", line 83, in __getattr__
    val = getattr(_wrapped, name)
          ^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'Settings' object has no attribute 'FIELD_CHOICES'
*Originally created by @jeremystretch on 2/12/2026* ### NetBox Edition NetBox Community ### NetBox Version v4.5.2 ### Python Version 3.12 ### Steps to Reproduce This one is a bit esoteric, so bear with me. We've discovered a regression introduced in 5c6fc2fb6f611d99b658ca8104729859f1bb1b5f that causes an `AttributeError` exception on startup when an installed plugin has a choice set which registers a key for configuration. For example: ```python class PriorityChoices(ChoiceSet): key = 'FooBar.priority' HIGH = 3 MEDIUM = 2 LOW = 1 CHOICES = [ (HIGH, _('High'), 'red'), (MEDIUM, _('Medium'), 'green'), (LOW, _('Low'), 'blue'), ] ``` The exception will trigger if this choice set is imported prior to plugin initialization. AFAICT, this is related to importing `strawberry` in `settings.py` (to monkey-patch our custom paginator). ### Expected Behavior The above scenario is valid and should not result in an exception. ### Observed Behavior An `AttributeError` exception is raised: ``` File "/home/jstretch/projects/test-plugin/test_plugin/__init__.py", line 3, in <module> from .validators import custom_validator File "/home/jstretch/projects/test-plugin/test_plugin/validators.py", line 4, in <module> from .choices import PriorityChoices File "/home/jstretch/projects/test-plugin/test_plugin/choices.py", line 33, in <module> class PriorityChoices(ChoiceSet): File "/home/jstretch/projects/netbox/netbox/utilities/choices.py", line 28, in __new__ replace_choices = get_config_value_ci(settings.FIELD_CHOICES, replace_key) ^^^^^^^^^^^^^^^^^^^^^^ File "/home/jstretch/projects/netbox/venv/lib/python3.12/site-packages/django/conf/__init__.py", line 83, in __getattr__ val = getattr(_wrapped, name) ^^^^^^^^^^^^^^^^^^^^^^^ AttributeError: 'Settings' object has no attribute 'FIELD_CHOICES' ```
MrUnknownDE added the netboxtype: bugstatus: acceptedseverity: mediumnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxnetboxtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugtype: bugstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedstatus: acceptedseverity: mediumseverity: mediumseverity: mediumseverity: mediumseverity: mediumseverity: mediumseverity: medium labels 2026-04-05 16:27:49 +02:00
Sign in to join this conversation.
No Label netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox netbox severity: medium severity: medium severity: medium severity: medium severity: medium severity: medium severity: medium severity: medium status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted status: accepted type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug type: bug
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github/netbox#371