[change] Make menu item registration idempotent #641#714
Conversation
Re-initializing the Django app registery calls `AppConfig.ready()` again which re-invokes `register_menu_group()` / `register_menu_subitem()` with the same config. Both functions unconditionally raised `ImproperlyConfigured` whenever the target position was already occupied, even when it was the exact same app re-registering the exact same item, making it impossible to survive repeated app registry population. Both functions now compare the incoming config against the config of the item already registered at that position and log at INFO level if identical config is found Closes openwisp#641
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (3)
📜 Recent review details🧰 Additional context used📓 Path-based instructions (4)**/*.{md,rst,txt}📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*📄 CodeRabbit inference engine (Custom checks)
Files:
**/*.py📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/tests/**/*.py📄 CodeRabbit inference engine (AGENTS.md)
Files:
🧠 Learnings (1)📚 Learning: 2026-06-15T22:45:01.529ZApplied to files:
🔇 Additional comments (3)
📝 WalkthroughWalkthroughThe change makes menu registration idempotent when identical configurations are registered at occupied group or item positions. Estimated code review effort: 2 (Simple) | ~10 minutes Sequence Diagram(s)sequenceDiagram
participant Caller
participant register_menu_group
participant register_menu_subitem
participant MENU
participant logger
Caller->>register_menu_group: register position and config
register_menu_group->>MENU: compare existing group config
alt identical config
register_menu_group->>logger: log "already registered"
register_menu_group-->>Caller: return
else different config
register_menu_group->>MENU: raise configuration conflict
end
Caller->>register_menu_subitem: register item position and config
register_menu_subitem->>MENU: compare existing subitem config
alt identical config
register_menu_subitem->>logger: log "already registered"
register_menu_subitem-->>Caller: return
else different config
register_menu_subitem->>MENU: raise configuration conflict
end
🚥 Pre-merge checks | ✅ 8✅ Passed checks (8 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@tests/test_project/tests/test_menu.py`:
- Around line 91-100: Add idempotency coverage for occupied positions that
already contain non-MenuLink entries by extending the tests around
register_menu_group and the MENU registry. Create a subtest that re-registers
the same MenuGroup config at an already occupied top-level position, and
optionally a ModelLink config as well, then assert the existing entry remains
the same type and logs the “already registered” message. This should verify that
MenuGroup and ModelLink instances expose .config correctly and that
register_menu_group handles re-registration consistently for all stored menu
item types.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 555b58aa-6d60-4431-b810-e704b6ec5e1f
📒 Files selected for processing (2)
openwisp_utils/admin_theme/menu.pytests/test_project/tests/test_menu.py
📜 Review details
⚠️ CI failures not shown inline (14)
GitHub Actions: OpenWISP Utils CI Build / 2_Python==3.13 django~=5.2.0.txt: [change] Make menu item registration idempotent #641
Conclusion: failure
5-py3-none-any.whl (19 kB)
Using cached pytest-9.1.1-py3-none-any.whl (386 kB)
Using cached pluggy-1.6.0-py3-none-any.whl (20 kB)
Using cached pytest_mock-3.15.1-py3-none-any.whl (10 kB)
Using cached aiohappyeyeballs-2.7.1-py3-none-any.whl (15 kB)
Using cached aiosignal-1.4.0-py3-none-any.whl (7.5 kB)
Using cached attrs-26.1.0-py3-none-any.whl (67 kB)
Using cached bcrypt-5.0.0-cp39-abi3-manylinux_2_34_x86_64.whl (278 kB)
Using cached certifi-2026.6.17-py3-none-any.whl (133 kB)
Using cached cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (219 kB)
Using cached click_didyoumean-0.3.1-py3-none-any.whl (3.6 kB)
Using cached click_plugins-1.1.1.2-py2.py3-none-any.whl (11 kB)
Using cached click_repl-0.3.0-py3-none-any.whl (10 kB)
Using cached daphne-4.2.2-py3-none-any.whl (29 kB)
Using cached autobahn-26.6.2-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl (2.2 MB)
Downloading cbor2-6.1.3-cp313-cp313-manylinux_2_28_x86_64.whl (467 kB)
Using cached frozenlist-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl (234 kB)
Using cached hyperlink-21.0.0-py2.py3-none-any.whl (74 kB)
Using cached inflection-0.5.1-py2.py3-none-any.whl (9.5 kB)
Using cached iniconfig-2.3.0-py3-none-any.whl (7.5 kB)
Using cached invoke-3.0.3-py3-none-any.whl (160 kB)
Using cached jsonschema_specifications-2025.9.1-py3-none-any.whl (18 kB)
Using cached kombu-5.6.2-py3-none-any.whl (214 kB)
Using cached amqp-5.3.1-py3-none-any.whl (50 kB)
Using cached markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (22 kB)
Using cached prompt_toolkit-3.0.52-py3-none-any.whl (391 kB)
Using cached propcache-0.5.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (61 kB)
Using cached pygments-2.20.0-py3-none-any.whl (1.2 MB)
Using cached pynacl-1.6.2-cp38-abi3-manylinux_2_34_x86_64.whl (1.4 MB)
Using cached python_dateutil-2.9.0.post0-py2.py3-none-...
GitHub Actions: OpenWISP Utils CI Build / 4_Python==3.12 django~=5.2.0.txt: [change] Make menu item registration idempotent #641
Conclusion: failure
e-any.whl (10 kB)
Using cached swapper-1.4.0-py2.py3-none-any.whl (7.1 kB)
Using cached urllib3-2.7.0-py3-none-any.whl (131 kB)
Using cached vine-5.1.0-py3-none-any.whl (9.6 kB)
Using cached yarl-1.24.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (105 kB)
Using cached freezegun-1.5.5-py3-none-any.whl (19 kB)
Using cached pytest-9.1.1-py3-none-any.whl (386 kB)
Using cached pluggy-1.6.0-py3-none-any.whl (20 kB)
Using cached pytest_mock-3.15.1-py3-none-any.whl (10 kB)
Using cached aiohappyeyeballs-2.7.1-py3-none-any.whl (15 kB)
Using cached aiosignal-1.4.0-py3-none-any.whl (7.5 kB)
Using cached attrs-26.1.0-py3-none-any.whl (67 kB)
Using cached bcrypt-5.0.0-cp39-abi3-manylinux_2_34_x86_64.whl (278 kB)
Using cached certifi-2026.6.17-py3-none-any.whl (133 kB)
Using cached cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (219 kB)
Using cached click_didyoumean-0.3.1-py3-none-any.whl (3.6 kB)
Using cached click_plugins-1.1.1.2-py2.py3-none-any.whl (11 kB)
Using cached click_repl-0.3.0-py3-none-any.whl (10 kB)
Using cached daphne-4.2.2-py3-none-any.whl (29 kB)
Using cached autobahn-26.6.2-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl (2.2 MB)
Downloading cbor2-6.1.3-cp312-cp312-manylinux_2_28_x86_64.whl (468 kB)
Using cached frozenlist-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl (242 kB)
Using cached hyperlink-21.0.0-py2.py3-none-any.whl (74 kB)
Using cached inflection-0.5.1-py2.py3-none-any.whl (9.5 kB)
Using cached iniconfig-2.3.0-py3-none-any.whl (7.5 kB)
Using cached invoke-3.0.3-py3-none-any.whl (160 kB)
Using cached jsonschema_specifications-2025.9.1-py3-none-any.whl (18 kB)
Using cached kombu-5.6.2-py3-none-any.whl (214 kB)
Using cached amqp-5.3.1-py3-none-any.whl (50 kB)
Using cached markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (22 kB)
Using cached prompt_toolkit-3.0.52-py3...
GitHub Actions: OpenWISP Utils CI Build / 5_Python==3.11 django~=5.0.0.txt: [change] Make menu item registration idempotent #641
Conclusion: failure
ading aiohappyeyeballs-2.7.1-py3-none-any.whl (15 kB)
Using cached aiosignal-1.4.0-py3-none-any.whl (7.5 kB)
Using cached attrs-26.1.0-py3-none-any.whl (67 kB)
Using cached bcrypt-5.0.0-cp39-abi3-manylinux_2_34_x86_64.whl (278 kB)
Using cached certifi-2026.6.17-py3-none-any.whl (133 kB)
Using cached cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (215 kB)
Using cached click_didyoumean-0.3.1-py3-none-any.whl (3.6 kB)
Using cached click_plugins-1.1.1.2-py2.py3-none-any.whl (11 kB)
Using cached click_repl-0.3.0-py3-none-any.whl (10 kB)
Using cached daphne-4.2.2-py3-none-any.whl (29 kB)
Using cached autobahn-26.6.2-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl (2.2 MB)
Downloading cbor2-6.1.3-cp311-cp311-manylinux_2_28_x86_64.whl (472 kB)
Using cached frozenlist-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl (231 kB)
Using cached hyperlink-21.0.0-py2.py3-none-any.whl (74 kB)
Using cached inflection-0.5.1-py2.py3-none-any.whl (9.5 kB)
Using cached iniconfig-2.3.0-py3-none-any.whl (7.5 kB)
Using cached invoke-3.0.3-py3-none-any.whl (160 kB)
Using cached jsonschema_specifications-2025.9.1-py3-none-any.whl (18 kB)
Using cached kombu-5.6.2-py3-none-any.whl (214 kB)
Using cached amqp-5.3.1-py3-none-any.whl (50 kB)
Using cached markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (22 kB)
Using cached prompt_toolkit-3.0.52-py3-none-any.whl (391 kB)
Using cached propcache-0.5.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (58 kB)
Using cached pygments-2.20.0-py3-none-any.whl (1.2 MB)
Using cached pynacl-1.6.2-cp38-abi3-manylinux_2_34_x86_64.whl (1.4 MB)
Using cached python_dateutil-2.9.0.post0-py2.py3-none-any.whl (229 kB)
Using cached pytz-2026.2-py2.py3-none-any.whl (510 kB)
Using cached pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (806 kB)
Using c...
GitHub Actions: OpenWISP Utils CI Build / 1_Python==3.10 django~=5.2.0.txt: [change] Make menu item registration idempotent #641
Conclusion: failure
-5.2.0-py3-none-any.whl (28 kB)
Using cached aiohttp-3.14.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (1.7 MB)
Using cached async_timeout-5.0.1-py3-none-any.whl (6.2 kB)
Using cached geopy-2.4.1-py3-none-any.whl (125 kB)
Using cached geographiclib-2.1-py3-none-any.whl (40 kB)
Using cached jinja2-3.1.6-py3-none-any.whl (134 kB)
Using cached jsonschema-4.26.0-py3-none-any.whl (90 kB)
Using cached markdown-3.10.2-py3-none-any.whl (108 kB)
Using cached maxminddb-3.1.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (98 kB)
Using cached msgpack-1.2.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (407 kB)
Using cached multidict-6.7.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (243 kB)
Using cached netaddr-1.3.0-py3-none-any.whl (2.3 MB)
Using cached oauthlib-3.3.1-py3-none-any.whl (160 kB)
Using cached openpyxl-3.1.5-py2.py3-none-any.whl (250 kB)
Using cached paramiko-5.0.0-py3-none-any.whl (208 kB)
Using cached phonenumbers-9.0.34-py2.py3-none-any.whl (2.6 MB)
Using cached pillow-12.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (6.9 MB)
Using cached pyjwt-2.13.0-py3-none-any.whl (31 kB)
Using cached pyopenssl-26.3.0-py3-none-any.whl (56 kB)
Using cached cryptography-49.0.0-cp39-abi3-manylinux_2_34_x86_64.whl (4.7 MB)
Using cached rcssmin-1.2.2-cp310-cp310-manylinux1_x86_64.whl (51 kB)
Using cached requests-2.34.2-py3-none-any.whl (73 kB)
Using cached charset_normalizer-3.4.7-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (216 kB)
Using cached idna-3.18-py3-none-any.whl (65 kB)
Using cached rjsmin-1.2.5-cp310-cp310-manylinux1_x86_64.whl (35 kB)
Using cached scp-0.15.0-py2.py3-none-any.whl (8.8 kB)
Using cached shortuuid-1.0.13-py3-none-any.whl (10 kB)
Using cached swapper-1.4.0-py2.py3-none-any.whl (7.1 kB)
Using cached urllib3-2.7.0-py3-none-any.w...
GitHub Actions: OpenWISP Utils CI Build / 8_Python==3.12 django~=4.2.0.txt: [change] Make menu item registration idempotent #641
Conclusion: failure
.5-cp312-cp312-manylinux1_x86_64.whl (31 kB)
Using cached scp-0.15.0-py2.py3-none-any.whl (8.8 kB)
Using cached shortuuid-1.0.13-py3-none-any.whl (10 kB)
Using cached swapper-1.4.0-py2.py3-none-any.whl (7.1 kB)
Using cached urllib3-2.7.0-py3-none-any.whl (131 kB)
Using cached vine-5.1.0-py3-none-any.whl (9.6 kB)
Using cached yarl-1.24.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (105 kB)
Using cached freezegun-1.5.5-py3-none-any.whl (19 kB)
Using cached pytest-9.1.1-py3-none-any.whl (386 kB)
Using cached pluggy-1.6.0-py3-none-any.whl (20 kB)
Using cached pytest_mock-3.15.1-py3-none-any.whl (10 kB)
Using cached aiohappyeyeballs-2.7.1-py3-none-any.whl (15 kB)
Using cached aiosignal-1.4.0-py3-none-any.whl (7.5 kB)
Using cached attrs-26.1.0-py3-none-any.whl (67 kB)
Using cached bcrypt-5.0.0-cp39-abi3-manylinux_2_34_x86_64.whl (278 kB)
Using cached certifi-2026.6.17-py3-none-any.whl (133 kB)
Using cached cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (219 kB)
Using cached click_didyoumean-0.3.1-py3-none-any.whl (3.6 kB)
Using cached click_plugins-1.1.1.2-py2.py3-none-any.whl (11 kB)
Using cached click_repl-0.3.0-py3-none-any.whl (10 kB)
Using cached daphne-4.2.2-py3-none-any.whl (29 kB)
Using cached autobahn-26.6.2-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl (2.2 MB)
Downloading cbor2-6.1.3-cp312-cp312-manylinux_2_28_x86_64.whl (468 kB)
Using cached frozenlist-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl (242 kB)
Using cached hyperlink-21.0.0-py2.py3-none-any.whl (74 kB)
Using cached inflection-0.5.1-py2.py3-none-any.whl (9.5 kB)
Using cached iniconfig-2.3.0-py3-none-any.whl (7.5 kB)
Using cached invoke-3.0.3-py3-none-any.whl (160 kB)
Using cached jsonschema_specifications-2025.9.1-py3-none-any.whl (18 kB)
Using cached kombu-5.6.2-py3-none-any.whl (214 kB)
Using cached amqp-5.3.1-py3-none-any.whl (50 kB)
Using cached markups...
GitHub Actions: OpenWISP Utils CI Build / 6_Python==3.12 django~=5.1.0.txt: [change] Make menu item registration idempotent #641
Conclusion: failure
hed aiohappyeyeballs-2.7.1-py3-none-any.whl (15 kB)
Using cached aiosignal-1.4.0-py3-none-any.whl (7.5 kB)
Using cached attrs-26.1.0-py3-none-any.whl (67 kB)
Using cached bcrypt-5.0.0-cp39-abi3-manylinux_2_34_x86_64.whl (278 kB)
Using cached certifi-2026.6.17-py3-none-any.whl (133 kB)
Using cached cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (219 kB)
Using cached click_didyoumean-0.3.1-py3-none-any.whl (3.6 kB)
Using cached click_plugins-1.1.1.2-py2.py3-none-any.whl (11 kB)
Using cached click_repl-0.3.0-py3-none-any.whl (10 kB)
Using cached daphne-4.2.2-py3-none-any.whl (29 kB)
Using cached autobahn-26.6.2-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl (2.2 MB)
Downloading cbor2-6.1.3-cp312-cp312-manylinux_2_28_x86_64.whl (468 kB)
Using cached frozenlist-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl (242 kB)
Using cached hyperlink-21.0.0-py2.py3-none-any.whl (74 kB)
Using cached inflection-0.5.1-py2.py3-none-any.whl (9.5 kB)
Using cached iniconfig-2.3.0-py3-none-any.whl (7.5 kB)
Using cached invoke-3.0.3-py3-none-any.whl (160 kB)
Using cached jsonschema_specifications-2025.9.1-py3-none-any.whl (18 kB)
Using cached kombu-5.6.2-py3-none-any.whl (214 kB)
Using cached amqp-5.3.1-py3-none-any.whl (50 kB)
Using cached markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (22 kB)
Using cached prompt_toolkit-3.0.52-py3-none-any.whl (391 kB)
Using cached propcache-0.5.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (61 kB)
Using cached pygments-2.20.0-py3-none-any.whl (1.2 MB)
Using cached pynacl-1.6.2-cp38-abi3-manylinux_2_34_x86_64.whl (1.4 MB)
Using cached python_dateutil-2.9.0.post0-py2.py3-none-any.whl (229 kB)
Using cached pytz-2026.2-py2.py3-none-any.whl (510 kB)
Using cached pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (807 kB)
Using cac...
GitHub Actions: OpenWISP Utils CI Build / 3_Python==3.13 django~=5.1.0.txt: [change] Make menu item registration idempotent #641
Conclusion: failure
3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (219 kB)
Using cached click_didyoumean-0.3.1-py3-none-any.whl (3.6 kB)
Using cached click_plugins-1.1.1.2-py2.py3-none-any.whl (11 kB)
Using cached click_repl-0.3.0-py3-none-any.whl (10 kB)
Using cached daphne-4.2.2-py3-none-any.whl (29 kB)
Using cached autobahn-26.6.2-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl (2.2 MB)
Downloading cbor2-6.1.3-cp313-cp313-manylinux_2_28_x86_64.whl (467 kB)
Using cached frozenlist-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl (234 kB)
Using cached hyperlink-21.0.0-py2.py3-none-any.whl (74 kB)
Using cached inflection-0.5.1-py2.py3-none-any.whl (9.5 kB)
Using cached iniconfig-2.3.0-py3-none-any.whl (7.5 kB)
Using cached invoke-3.0.3-py3-none-any.whl (160 kB)
Using cached jsonschema_specifications-2025.9.1-py3-none-any.whl (18 kB)
Using cached kombu-5.6.2-py3-none-any.whl (214 kB)
Using cached amqp-5.3.1-py3-none-any.whl (50 kB)
Using cached markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (22 kB)
Using cached prompt_toolkit-3.0.52-py3-none-any.whl (391 kB)
Using cached propcache-0.5.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (61 kB)
Using cached pygments-2.20.0-py3-none-any.whl (1.2 MB)
Using cached pynacl-1.6.2-cp38-abi3-manylinux_2_34_x86_64.whl (1.4 MB)
Using cached python_dateutil-2.9.0.post0-py2.py3-none-any.whl (229 kB)
Using cached pytz-2026.2-py2.py3-none-any.whl (510 kB)
Using cached pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (801 kB)
Using cached redis-8.0.1-py3-none-any.whl (502 kB)
Using cached referencing-0.37.0-py3-none-any.whl (26 kB)
Using cached rpds_py-2026.6.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (365 kB)
Using cached six-1.17.0-py2.py3-none-any.whl (11 kB)
Using cached sqlparse-0.5.5-py3-none-any.whl (46 kB)
Using cached tabl...
GitHub Actions: OpenWISP Utils CI Build / 7_Python==3.12 django~=5.0.0.txt: [change] Make menu item registration idempotent #641
Conclusion: failure
l-1.4.0-py3-none-any.whl (7.5 kB)
Using cached attrs-26.1.0-py3-none-any.whl (67 kB)
Using cached bcrypt-5.0.0-cp39-abi3-manylinux_2_34_x86_64.whl (278 kB)
Using cached certifi-2026.6.17-py3-none-any.whl (133 kB)
Using cached cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (219 kB)
Using cached click_didyoumean-0.3.1-py3-none-any.whl (3.6 kB)
Using cached click_plugins-1.1.1.2-py2.py3-none-any.whl (11 kB)
Using cached click_repl-0.3.0-py3-none-any.whl (10 kB)
Using cached daphne-4.2.2-py3-none-any.whl (29 kB)
Using cached autobahn-26.6.2-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl (2.2 MB)
Downloading cbor2-6.1.3-cp312-cp312-manylinux_2_28_x86_64.whl (468 kB)
Using cached frozenlist-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl (242 kB)
Using cached hyperlink-21.0.0-py2.py3-none-any.whl (74 kB)
Using cached inflection-0.5.1-py2.py3-none-any.whl (9.5 kB)
Using cached iniconfig-2.3.0-py3-none-any.whl (7.5 kB)
Using cached invoke-3.0.3-py3-none-any.whl (160 kB)
Using cached jsonschema_specifications-2025.9.1-py3-none-any.whl (18 kB)
Using cached kombu-5.6.2-py3-none-any.whl (214 kB)
Using cached amqp-5.3.1-py3-none-any.whl (50 kB)
Using cached markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (22 kB)
Using cached prompt_toolkit-3.0.52-py3-none-any.whl (391 kB)
Using cached propcache-0.5.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (61 kB)
Using cached pygments-2.20.0-py3-none-any.whl (1.2 MB)
Using cached pynacl-1.6.2-cp38-abi3-manylinux_2_34_x86_64.whl (1.4 MB)
Using cached python_dateutil-2.9.0.post0-py2.py3-none-any.whl (229 kB)
Using cached pytz-2026.2-py2.py3-none-any.whl (510 kB)
Using cached pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (807 kB)
Using cached redis-8.0.1-py3-none-any.whl (502 kB)
Using cached referencing-0.37.0...
GitHub Actions: OpenWISP Utils CI Build / 11_Python==3.11 django~=4.2.0.txt: [change] Make menu item registration idempotent #641
Conclusion: failure
.2.5-cp311-cp311-manylinux1_x86_64.whl (31 kB)
Using cached scp-0.15.0-py2.py3-none-any.whl (8.8 kB)
Using cached shortuuid-1.0.13-py3-none-any.whl (10 kB)
Using cached swapper-1.4.0-py2.py3-none-any.whl (7.1 kB)
Using cached urllib3-2.7.0-py3-none-any.whl (131 kB)
Using cached vine-5.1.0-py3-none-any.whl (9.6 kB)
Using cached yarl-1.24.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (106 kB)
Using cached freezegun-1.5.5-py3-none-any.whl (19 kB)
Using cached pytest-9.1.1-py3-none-any.whl (386 kB)
Using cached pluggy-1.6.0-py3-none-any.whl (20 kB)
Using cached pytest_mock-3.15.1-py3-none-any.whl (10 kB)
Downloading aiohappyeyeballs-2.7.1-py3-none-any.whl (15 kB)
Using cached aiosignal-1.4.0-py3-none-any.whl (7.5 kB)
Using cached attrs-26.1.0-py3-none-any.whl (67 kB)
Using cached bcrypt-5.0.0-cp39-abi3-manylinux_2_34_x86_64.whl (278 kB)
Using cached certifi-2026.6.17-py3-none-any.whl (133 kB)
Using cached cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (215 kB)
Using cached click_didyoumean-0.3.1-py3-none-any.whl (3.6 kB)
Using cached click_plugins-1.1.1.2-py2.py3-none-any.whl (11 kB)
Using cached click_repl-0.3.0-py3-none-any.whl (10 kB)
Using cached daphne-4.2.2-py3-none-any.whl (29 kB)
Using cached autobahn-26.6.2-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl (2.2 MB)
Downloading cbor2-6.1.3-cp311-cp311-manylinux_2_28_x86_64.whl (472 kB)
Using cached frozenlist-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl (231 kB)
Using cached hyperlink-21.0.0-py2.py3-none-any.whl (74 kB)
Using cached inflection-0.5.1-py2.py3-none-any.whl (9.5 kB)
Using cached iniconfig-2.3.0-py3-none-any.whl (7.5 kB)
Using cached invoke-3.0.3-py3-none-any.whl (160 kB)
Using cached jsonschema_specifications-2025.9.1-py3-none-any.whl (18 kB)
Using cached kombu-5.6.2-py3-none-any.whl (214 kB)
Using cached amqp-5.3.1-py3-none-any.whl (50 kB)
Using cached markup...
GitHub Actions: OpenWISP Utils CI Build / 13_Python==3.11 django~=5.1.0.txt: [change] Make menu item registration idempotent #641
Conclusion: failure
loading aiohappyeyeballs-2.7.1-py3-none-any.whl (15 kB)
Using cached aiosignal-1.4.0-py3-none-any.whl (7.5 kB)
Using cached attrs-26.1.0-py3-none-any.whl (67 kB)
Using cached bcrypt-5.0.0-cp39-abi3-manylinux_2_34_x86_64.whl (278 kB)
Using cached certifi-2026.6.17-py3-none-any.whl (133 kB)
Using cached cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (215 kB)
Using cached click_didyoumean-0.3.1-py3-none-any.whl (3.6 kB)
Using cached click_plugins-1.1.1.2-py2.py3-none-any.whl (11 kB)
Using cached click_repl-0.3.0-py3-none-any.whl (10 kB)
Using cached daphne-4.2.2-py3-none-any.whl (29 kB)
Using cached autobahn-26.6.2-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl (2.2 MB)
Downloading cbor2-6.1.3-cp311-cp311-manylinux_2_28_x86_64.whl (472 kB)
Using cached frozenlist-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl (231 kB)
Using cached hyperlink-21.0.0-py2.py3-none-any.whl (74 kB)
Using cached inflection-0.5.1-py2.py3-none-any.whl (9.5 kB)
Using cached iniconfig-2.3.0-py3-none-any.whl (7.5 kB)
Using cached invoke-3.0.3-py3-none-any.whl (160 kB)
Using cached jsonschema_specifications-2025.9.1-py3-none-any.whl (18 kB)
Using cached kombu-5.6.2-py3-none-any.whl (214 kB)
Using cached amqp-5.3.1-py3-none-any.whl (50 kB)
Using cached markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (22 kB)
Using cached prompt_toolkit-3.0.52-py3-none-any.whl (391 kB)
Using cached propcache-0.5.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (58 kB)
Using cached pygments-2.20.0-py3-none-any.whl (1.2 MB)
Using cached pynacl-1.6.2-cp38-abi3-manylinux_2_34_x86_64.whl (1.4 MB)
Using cached python_dateutil-2.9.0.post0-py2.py3-none-any.whl (229 kB)
Using cached pytz-2026.2-py2.py3-none-any.whl (510 kB)
Using cached pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (806 kB)
Using...
GitHub Actions: OpenWISP Utils CI Build / 12_Python==3.10 django~=5.1.0.txt: [change] Make menu item registration idempotent #641
Conclusion: failure
8 kB)
Using cached msgpack-1.2.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (407 kB)
Using cached multidict-6.7.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (243 kB)
Using cached netaddr-1.3.0-py3-none-any.whl (2.3 MB)
Using cached oauthlib-3.3.1-py3-none-any.whl (160 kB)
Using cached openpyxl-3.1.5-py2.py3-none-any.whl (250 kB)
Using cached paramiko-5.0.0-py3-none-any.whl (208 kB)
Using cached phonenumbers-9.0.34-py2.py3-none-any.whl (2.6 MB)
Using cached pillow-12.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (6.9 MB)
Using cached pyjwt-2.13.0-py3-none-any.whl (31 kB)
Using cached pyopenssl-26.3.0-py3-none-any.whl (56 kB)
Using cached cryptography-49.0.0-cp39-abi3-manylinux_2_34_x86_64.whl (4.7 MB)
Using cached rcssmin-1.2.2-cp310-cp310-manylinux1_x86_64.whl (51 kB)
Using cached requests-2.34.2-py3-none-any.whl (73 kB)
Using cached charset_normalizer-3.4.7-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (216 kB)
Using cached idna-3.18-py3-none-any.whl (65 kB)
Using cached rjsmin-1.2.5-cp310-cp310-manylinux1_x86_64.whl (35 kB)
Using cached scp-0.15.0-py2.py3-none-any.whl (8.8 kB)
Using cached shortuuid-1.0.13-py3-none-any.whl (10 kB)
Using cached swapper-1.4.0-py2.py3-none-any.whl (7.1 kB)
Using cached urllib3-2.7.0-py3-none-any.whl (131 kB)
Using cached vine-5.1.0-py3-none-any.whl (9.6 kB)
Using cached yarl-1.24.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (106 kB)
Using cached freezegun-1.5.5-py3-none-any.whl (19 kB)
Using cached pytest-9.1.1-py3-none-any.whl (386 kB)
Using cached pluggy-1.6.0-py3-none-any.whl (20 kB)
Using cached pytest_mock-3.15.1-py3-none-any.whl (10 kB)
Using cached aiohappyeyeballs-2.7.1-py3-none-any.whl (15 kB)
Using cached aiosignal-1.4.0-py3-none-any.whl (7.5 kB)
Using cached attrs-26.1.0-py3-none-any.whl (67 kB)
Using cached bcrypt-5.0.0-cp39-...
GitHub Actions: OpenWISP Utils CI Build / 9_Python==3.10 django~=5.0.0.txt: [change] Make menu item registration idempotent #641
Conclusion: failure
10-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (98 kB)
Using cached msgpack-1.2.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (407 kB)
Using cached multidict-6.7.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (243 kB)
Using cached netaddr-1.3.0-py3-none-any.whl (2.3 MB)
Using cached oauthlib-3.3.1-py3-none-any.whl (160 kB)
Using cached openpyxl-3.1.5-py2.py3-none-any.whl (250 kB)
Using cached paramiko-5.0.0-py3-none-any.whl (208 kB)
Using cached phonenumbers-9.0.34-py2.py3-none-any.whl (2.6 MB)
Using cached pillow-12.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (6.9 MB)
Using cached pyjwt-2.13.0-py3-none-any.whl (31 kB)
Using cached pyopenssl-26.3.0-py3-none-any.whl (56 kB)
Using cached cryptography-49.0.0-cp39-abi3-manylinux_2_34_x86_64.whl (4.7 MB)
Using cached rcssmin-1.2.2-cp310-cp310-manylinux1_x86_64.whl (51 kB)
Using cached requests-2.34.2-py3-none-any.whl (73 kB)
Using cached charset_normalizer-3.4.7-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (216 kB)
Using cached idna-3.18-py3-none-any.whl (65 kB)
Using cached rjsmin-1.2.5-cp310-cp310-manylinux1_x86_64.whl (35 kB)
Using cached scp-0.15.0-py2.py3-none-any.whl (8.8 kB)
Using cached shortuuid-1.0.13-py3-none-any.whl (10 kB)
Using cached swapper-1.4.0-py2.py3-none-any.whl (7.1 kB)
Using cached urllib3-2.7.0-py3-none-any.whl (131 kB)
Using cached vine-5.1.0-py3-none-any.whl (9.6 kB)
Using cached yarl-1.24.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (106 kB)
Using cached freezegun-1.5.5-py3-none-any.whl (19 kB)
Using cached pytest-9.1.1-py3-none-any.whl (386 kB)
Using cached pluggy-1.6.0-py3-none-any.whl (20 kB)
Using cached pytest_mock-3.15.1-py3-none-any.whl (10 kB)
Using cached aiohappyeyeballs-2.7.1-py3-none-any.whl (15 kB)
Using cached aiosignal-1.4.0-py3-none-any.whl (7.5 kB)
Using cac...
GitHub Actions: OpenWISP Utils CI Build / 14_Python==3.10 django~=4.2.0.txt: [change] Make menu item registration idempotent #641
Conclusion: failure
anylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (1.7 MB)
Using cached async_timeout-5.0.1-py3-none-any.whl (6.2 kB)
Using cached geopy-2.4.1-py3-none-any.whl (125 kB)
Using cached geographiclib-2.1-py3-none-any.whl (40 kB)
Using cached jinja2-3.1.6-py3-none-any.whl (134 kB)
Using cached jsonschema-4.26.0-py3-none-any.whl (90 kB)
Using cached markdown-3.10.2-py3-none-any.whl (108 kB)
Using cached maxminddb-3.1.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (98 kB)
Using cached msgpack-1.2.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (407 kB)
Using cached multidict-6.7.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (243 kB)
Using cached netaddr-1.3.0-py3-none-any.whl (2.3 MB)
Using cached oauthlib-3.3.1-py3-none-any.whl (160 kB)
Using cached openpyxl-3.1.5-py2.py3-none-any.whl (250 kB)
Using cached paramiko-5.0.0-py3-none-any.whl (208 kB)
Using cached phonenumbers-9.0.34-py2.py3-none-any.whl (2.6 MB)
Using cached pillow-12.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (6.9 MB)
Using cached pyjwt-2.13.0-py3-none-any.whl (31 kB)
Using cached pyopenssl-26.3.0-py3-none-any.whl (56 kB)
Using cached cryptography-49.0.0-cp39-abi3-manylinux_2_34_x86_64.whl (4.7 MB)
Using cached rcssmin-1.2.2-cp310-cp310-manylinux1_x86_64.whl (51 kB)
Using cached requests-2.34.2-py3-none-any.whl (73 kB)
Using cached charset_normalizer-3.4.7-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (216 kB)
Using cached idna-3.18-py3-none-any.whl (65 kB)
Using cached rjsmin-1.2.5-cp310-cp310-manylinux1_x86_64.whl (35 kB)
Using cached scp-0.15.0-py2.py3-none-any.whl (8.8 kB)
Using cached shortuuid-1.0.13-py3-none-any.whl (10 kB)
Using cached swapper-1.4.0-py2.py3-none-any.whl (7.1 kB)
Using cached urllib3-2.7.0-py3-none-any.whl (131 kB)
Using cached vine-5.1.0-py3-none-any.whl (9.6 kB)
Using cach...
GitHub Actions: OpenWISP Utils CI Build / 10_Python==3.11 django~=5.2.0.txt: [change] Make menu item registration idempotent #641
Conclusion: failure
one-any.whl (10 kB)
Using cached swapper-1.4.0-py2.py3-none-any.whl (7.1 kB)
Using cached urllib3-2.7.0-py3-none-any.whl (131 kB)
Using cached vine-5.1.0-py3-none-any.whl (9.6 kB)
Using cached yarl-1.24.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (106 kB)
Using cached freezegun-1.5.5-py3-none-any.whl (19 kB)
Using cached pytest-9.1.1-py3-none-any.whl (386 kB)
Using cached pluggy-1.6.0-py3-none-any.whl (20 kB)
Using cached pytest_mock-3.15.1-py3-none-any.whl (10 kB)
Downloading aiohappyeyeballs-2.7.1-py3-none-any.whl (15 kB)
Using cached aiosignal-1.4.0-py3-none-any.whl (7.5 kB)
Using cached attrs-26.1.0-py3-none-any.whl (67 kB)
Using cached bcrypt-5.0.0-cp39-abi3-manylinux_2_34_x86_64.whl (278 kB)
Using cached certifi-2026.6.17-py3-none-any.whl (133 kB)
Using cached cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (215 kB)
Using cached click_didyoumean-0.3.1-py3-none-any.whl (3.6 kB)
Using cached click_plugins-1.1.1.2-py2.py3-none-any.whl (11 kB)
Using cached click_repl-0.3.0-py3-none-any.whl (10 kB)
Using cached daphne-4.2.2-py3-none-any.whl (29 kB)
Using cached autobahn-26.6.2-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl (2.2 MB)
Downloading cbor2-6.1.3-cp311-cp311-manylinux_2_28_x86_64.whl (472 kB)
Using cached frozenlist-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl (231 kB)
Using cached hyperlink-21.0.0-py2.py3-none-any.whl (74 kB)
Using cached inflection-0.5.1-py2.py3-none-any.whl (9.5 kB)
Using cached iniconfig-2.3.0-py3-none-any.whl (7.5 kB)
Using cached invoke-3.0.3-py3-none-any.whl (160 kB)
Using cached jsonschema_specifications-2025.9.1-py3-none-any.whl (18 kB)
Using cached kombu-5.6.2-py3-none-any.whl (214 kB)
Using cached amqp-5.3.1-py3-none-any.whl (50 kB)
Using cached markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl (22 kB)
Using cached prompt_toolkit-3.0.52-py...
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{py,html,txt}
📄 CodeRabbit inference engine (Custom checks)
For Django pull requests, ensure all user-facing strings are marked as translatable using the Django i18n framework
Files:
tests/test_project/tests/test_menu.pyopenwisp_utils/admin_theme/menu.py
**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
**/*.py: Place imports at the top of the file; only defer imports when necessary (e.g., Django model imports inside functions or methods where the app registry is not yet ready)
Avoid unnecessary blank lines inside function and method bodies
Add or update tests for every behavior change
Runopenwisp-qa-formatafter editing
Prefer in-process tests so coverage tools can measure changed code
When checking coverage for a changed module, usepython -m pytest <test_path> --cov=<dotted.module.path> --cov-report=term-missing
Watch for unsafe file paths, unsafe subprocess usage, token or secret exposure, and changes that could weaken QA or release safeguards
Write comments and docstrings only when they explain why code is shaped a certain way; place comments before the relevant code block instead of scattering them inside it
Files:
tests/test_project/tests/test_menu.pyopenwisp_utils/admin_theme/menu.py
**/tests/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
For bug fixes, write the regression test first, run it against the unfixed code, confirm it fails for the expected reason, then implement the fix
Files:
tests/test_project/tests/test_menu.py
🧠 Learnings (1)
📚 Learning: 2026-06-15T22:45:01.529Z
Learnt from: nemesifier
Repo: openwisp/openwisp-utils PR: 701
File: setup.py:72-72
Timestamp: 2026-06-15T22:45:01.529Z
Learning: When reviewing changes that require a minimum Selenium Python version for specific APIs (e.g., BiDi features like `Options.enable_bidi`, console/message handlers like `Script.add_console_message_handler`, or event handlers like `BrowsingContext.add_event_handler`), do not use the Selenium API docs site (`https://www.selenium.dev/selenium/docs/api/py/`) as the source of introduction/version history, since it reflects the latest API shape. Instead, confirm feature availability by checking the official Python changelog (`py/CHANGES` in the Selenium repo) and/or inspecting the Selenium source (tags/commits corresponding to candidate versions). Only accept the stated minimum version after verifying that the referenced APIs exist in that Selenium version (e.g., Selenium 4.32.0 includes the BiDi APIs used by openwisp-utils’ BiDi-related PR `#701` as of that version).
Applied to files:
tests/test_project/tests/test_menu.pyopenwisp_utils/admin_theme/menu.py
🔇 Additional comments (4)
openwisp_utils/admin_theme/menu.py (3)
1-11: LGTM!Also applies to: 21-26, 47-67
221-270: LGTM!Items stored in
group.itemsare alwaysMenuLinkorModelLinkinstances (lines 245-250), both of which setself.configviaBaseMenuItem, so the.configcomparison at line 257 is safe.
186-197: 🩺 Stability & AvailabilityNo issue:
MenuGroupsets.config
MenuGroupalso callssuper().__init__(config), soMENU[position].configis available for existing groups too.> Likely an incorrect or invalid review comment.tests/test_project/tests/test_menu.py (1)
156-158: LGTM! Correctly switched to a config with a differentlabelso this subtest still exercises the "different config at occupied position" raise, rather than accidentally hitting the new idempotent skip path (since the default item at position 1 already matchesconfig's default values).
nemesifier
left a comment
There was a problem hiding this comment.
As @coderabbitai wrote in its pre-merge checks:
Update the navigation-menu docs to describe the idempotent identical-config case and keep the error description only for mismatched configs.
|
@coderabbitai full review |
✅ Action performedFull review finished. |
|
Proposed change log entry: |
Re-initializing the Django app registery calls
AppConfig.ready()again which re-invokesregister_menu_group()/register_menu_subitem()with the same config. Both functions unconditionally raisedImproperlyConfiguredwhenever the target position was already occupied, even when it was the exact same app re-registering the exact same item, making it impossible to survive repeated app registry population.Both functions now compare the incoming config against the config of the item already registered at that position and log at INFO level if identical config is found Closes
Checklist
Reference to Existing Issue
Closes #641 .
Description of Changes
register_menu_group/register_menu_subitemtwice with the same config at the same position always errored, even with app reloads or repeated ready() calls. Now each menu item stores its config, and both functions check for an identical config before raising, if it matches, they log an INFO message and skip instead of erroring.