-
-
Notifications
You must be signed in to change notification settings - Fork 3.2k
fix: Allow lazy wizard initialization #8266
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
* fix: Allow lazy wizard initialization * Update cms/cms_toolbars.py Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> * Update cms/cms_config.py Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> --------- Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
Reviewer's GuideThis PR ports forward lazy wizard initialization by deferring wizard registration in CMSCoreExtensions via a cached_property, adding new registry helper functions, deprecating legacy helpers and WizardPool methods, and updating related tests and toolbar logic. Sequence diagram for lazy wizard initialization and accesssequenceDiagram
participant App as Django App
participant CMSConfig as CMSCoreConfig
participant Extension as CMSCoreExtensions
participant User as User
participant Wizard as Wizard
App->>CMSConfig: Load cms_wizards
CMSConfig->>Extension: configure_wizards(cms_config)
Extension->>Extension: lazy_wizards.append(cms_config.cms_wizards)
User->>Extension: Access wizards property
Extension->>Extension: Build wizards dict from lazy_wizards
Extension->>User: Return wizards dict
Class diagram for deprecated helpers and WizardPoolclassDiagram
class helpers {
+get_entries() <<deprecated>>
+get_entry(entry_key) <<deprecated>>
}
class WizardPool {
+register(entry)
+is_registered(entry, passive)
}
helpers ..> wizard_base : now delegates
WizardPool ..> Wizard : uses
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @fsbraun - I've reviewed your changes and they look great!
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location> `cms/wizards/wizard_base.py:30` </location>
<code_context>
+ # do something with a wizard...
+ """
+ wizards = apps.get_app_config('cms').cms_extension.wizards
+ return sorted(wizards.values(), key=lambda e: e.weight)
+
+
</code_context>
<issue_to_address>
Sorting now returns only values, not (id, wizard) tuples.
The return type no longer matches the docstring and example, which may break code relying on the previous (id, wizard) tuple format.
</issue_to_address>
### Comment 2
<location> `cms/cms_config.py:51` </location>
<code_context>
+ """
+
+ wizards = {}
+ for iterable in self.lazy_wizards:
+ new_wizards = {wizard.id: wizard for wizard in iterable}
+ if wizard := next((wizard for wizard in new_wizards.values() if not isinstance(wizard, Wizard)), None):
+ # If any wizard in the iterable is not an instance of Wizard, raise an exception
raise ImproperlyConfigured(
- "All wizards defined in cms_wizards must inherit "
- "from cms.wizards.wizard_base.Wizard"
+ f"cms_wizards must be iterable of Wizard instances, got {type(wizard)}"
)
- elif wizard.id in self.wizards:
- msg = f"Wizard for model {wizard.get_model()} has already been registered"
- logger.warning(msg)
- else:
- self.wizards[wizard.id] = wizard
+ wizards |= new_wizards
+ return wizards
</code_context>
<issue_to_address>
Merging dictionaries with |= may overwrite Wizards with duplicate IDs.
This can lead to unintentional data loss. Please add a check for duplicate IDs and raise an error or warning if found.
Suggested implementation:
```python
wizards = {}
```
```python
for iterable in self.lazy_wizards:
new_wizards = {wizard.id: wizard for wizard in iterable}
if wizard := next((wizard for wizard in new_wizards.values() if not isinstance(wizard, Wizard)), None):
# If any wizard in the iterable is not an instance of Wizard, raise an exception
raise ImproperlyConfigured(
f"cms_wizards must be iterable of Wizard instances, got {type(wizard)}"
)
duplicate_ids = set(new_wizards.keys()) & set(wizards.keys())
if duplicate_ids:
raise ImproperlyConfigured(
f"Duplicate wizard IDs found: {', '.join(str(i) for i in duplicate_ids)}"
)
wizards |= new_wizards
return wizards
```
</issue_to_address>
### Comment 3
<location> `cms/tests/test_cms_config_wizards.py:52` </location>
<code_context>
wizard = Mock(id=3, spec=object)
cms_config = Mock(
cms_enabled=True, cms_wizards=[wizard])
+ extensions.configure_wizards(cms_config)
with self.assertRaises(ImproperlyConfigured):
- extensions.configure_wizards(cms_config)
+ extensions.wizards
+
</code_context>
<issue_to_address>
Test for exception when non-Wizard instance is present now triggers on property access.
Consider adding a comment or separate test to document that the exception is now raised on 'wizards' property access, not during configuration, to clarify intent and timing.
</issue_to_address>
<suggested_fix>
<<<<<<< SEARCH
wizard = Mock(id=3, spec=object)
cms_config = Mock(
cms_enabled=True, cms_wizards=[wizard])
extensions.configure_wizards(cms_config)
with self.assertRaises(ImproperlyConfigured):
extensions.wizards
=======
# Note: Exception is now raised on 'wizards' property access, not during configuration.
wizard = Mock(id=3, spec=object)
cms_config = Mock(
cms_enabled=True, cms_wizards=[wizard])
extensions.configure_wizards(cms_config)
with self.assertRaises(ImproperlyConfigured):
extensions.wizards
def test_raises_exception_on_wizards_property_access_with_non_wizard(self):
"""
Test that ImproperlyConfigured is raised when a non-Wizard instance is present,
and that the exception is triggered on 'wizards' property access, not during configuration.
"""
wizard = Mock(id=3, spec=object)
cms_config = Mock(
cms_enabled=True, cms_wizards=[wizard])
extensions.configure_wizards(cms_config)
with self.assertRaises(ImproperlyConfigured):
_ = extensions.wizards
>>>>>>> REPLACE
</suggested_fix>
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
wizard = Mock(id=3, spec=object) | ||
cms_config = Mock( | ||
cms_enabled=True, cms_wizards=[wizard]) | ||
extensions.configure_wizards(cms_config) | ||
with self.assertRaises(ImproperlyConfigured): | ||
extensions.configure_wizards(cms_config) | ||
extensions.wizards | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion (testing): Test for exception when non-Wizard instance is present now triggers on property access.
Consider adding a comment or separate test to document that the exception is now raised on 'wizards' property access, not during configuration, to clarify intent and timing.
wizard = Mock(id=3, spec=object) | |
cms_config = Mock( | |
cms_enabled=True, cms_wizards=[wizard]) | |
extensions.configure_wizards(cms_config) | |
with self.assertRaises(ImproperlyConfigured): | |
extensions.configure_wizards(cms_config) | |
extensions.wizards | |
# Note: Exception is now raised on 'wizards' property access, not during configuration. | |
wizard = Mock(id=3, spec=object) | |
cms_config = Mock( | |
cms_enabled=True, cms_wizards=[wizard]) | |
extensions.configure_wizards(cms_config) | |
with self.assertRaises(ImproperlyConfigured): | |
extensions.wizards | |
def test_raises_exception_on_wizards_property_access_with_non_wizard(self): | |
""" | |
Test that ImproperlyConfigured is raised when a non-Wizard instance is present, | |
and that the exception is triggered on 'wizards' property access, not during configuration. | |
""" | |
wizard = Mock(id=3, spec=object) | |
cms_config = Mock( | |
cms_enabled=True, cms_wizards=[wizard]) | |
extensions.configure_wizards(cms_config) | |
with self.assertRaises(ImproperlyConfigured): | |
_ = extensions.wizards |
e47f647
to
664dcf7
Compare
Description
This is a port forward of #8265. This PR fixes two issues:
Related resources
Checklist
main
Summary by Sourcery
Implement lazy wizard initialization in CMSCoreExtensions, add new wizard_base APIs for retrieving and managing wizards, deprecate the legacy helpers and WizardPool interfaces, update toolbar logic to use the new API, and adjust tests accordingly
New Features:
Enhancements:
Tests:
Chores: