django-bulk-hooks 0.2.71__tar.gz → 0.2.72__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of django-bulk-hooks might be problematic. Click here for more details.

Files changed (27) hide show
  1. {django_bulk_hooks-0.2.71 → django_bulk_hooks-0.2.72}/PKG-INFO +1 -1
  2. {django_bulk_hooks-0.2.71 → django_bulk_hooks-0.2.72}/django_bulk_hooks/dispatcher.py +12 -0
  3. {django_bulk_hooks-0.2.71 → django_bulk_hooks-0.2.72}/django_bulk_hooks/operations/coordinator.py +9 -1
  4. {django_bulk_hooks-0.2.71 → django_bulk_hooks-0.2.72}/django_bulk_hooks/operations/mti_handler.py +3 -0
  5. {django_bulk_hooks-0.2.71 → django_bulk_hooks-0.2.72}/pyproject.toml +1 -1
  6. {django_bulk_hooks-0.2.71 → django_bulk_hooks-0.2.72}/LICENSE +0 -0
  7. {django_bulk_hooks-0.2.71 → django_bulk_hooks-0.2.72}/README.md +0 -0
  8. {django_bulk_hooks-0.2.71 → django_bulk_hooks-0.2.72}/django_bulk_hooks/__init__.py +0 -0
  9. {django_bulk_hooks-0.2.71 → django_bulk_hooks-0.2.72}/django_bulk_hooks/changeset.py +0 -0
  10. {django_bulk_hooks-0.2.71 → django_bulk_hooks-0.2.72}/django_bulk_hooks/conditions.py +0 -0
  11. {django_bulk_hooks-0.2.71 → django_bulk_hooks-0.2.72}/django_bulk_hooks/constants.py +0 -0
  12. {django_bulk_hooks-0.2.71 → django_bulk_hooks-0.2.72}/django_bulk_hooks/context.py +0 -0
  13. {django_bulk_hooks-0.2.71 → django_bulk_hooks-0.2.72}/django_bulk_hooks/decorators.py +0 -0
  14. {django_bulk_hooks-0.2.71 → django_bulk_hooks-0.2.72}/django_bulk_hooks/enums.py +0 -0
  15. {django_bulk_hooks-0.2.71 → django_bulk_hooks-0.2.72}/django_bulk_hooks/factory.py +0 -0
  16. {django_bulk_hooks-0.2.71 → django_bulk_hooks-0.2.72}/django_bulk_hooks/handler.py +0 -0
  17. {django_bulk_hooks-0.2.71 → django_bulk_hooks-0.2.72}/django_bulk_hooks/helpers.py +0 -0
  18. {django_bulk_hooks-0.2.71 → django_bulk_hooks-0.2.72}/django_bulk_hooks/manager.py +0 -0
  19. {django_bulk_hooks-0.2.71 → django_bulk_hooks-0.2.72}/django_bulk_hooks/models.py +0 -0
  20. {django_bulk_hooks-0.2.71 → django_bulk_hooks-0.2.72}/django_bulk_hooks/operations/__init__.py +0 -0
  21. {django_bulk_hooks-0.2.71 → django_bulk_hooks-0.2.72}/django_bulk_hooks/operations/analyzer.py +0 -0
  22. {django_bulk_hooks-0.2.71 → django_bulk_hooks-0.2.72}/django_bulk_hooks/operations/bulk_executor.py +0 -0
  23. {django_bulk_hooks-0.2.71 → django_bulk_hooks-0.2.72}/django_bulk_hooks/operations/field_utils.py +0 -0
  24. {django_bulk_hooks-0.2.71 → django_bulk_hooks-0.2.72}/django_bulk_hooks/operations/mti_plans.py +0 -0
  25. {django_bulk_hooks-0.2.71 → django_bulk_hooks-0.2.72}/django_bulk_hooks/operations/record_classifier.py +0 -0
  26. {django_bulk_hooks-0.2.71 → django_bulk_hooks-0.2.72}/django_bulk_hooks/queryset.py +0 -0
  27. {django_bulk_hooks-0.2.71 → django_bulk_hooks-0.2.72}/django_bulk_hooks/registry.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: django-bulk-hooks
3
- Version: 0.2.71
3
+ Version: 0.2.72
4
4
  Summary: Hook-style hooks for Django bulk operations like bulk_create and bulk_update.
5
5
  License: MIT
6
6
  Keywords: django,bulk,hooks
@@ -103,6 +103,9 @@ class HookDispatcher:
103
103
  # Get hooks sorted by priority (deterministic order)
104
104
  hooks = self.registry.get_hooks(changeset.model_cls, event)
105
105
 
106
+ logger.debug(f"🧵 DISPATCH: changeset.model_cls={changeset.model_cls.__name__}, event={event}")
107
+ logger.debug(f"🎣 HOOKS_FOUND: {len(hooks)} hooks for {changeset.model_cls.__name__}.{event}: {[f'{h[0].__name__}.{h[1]}' for h in hooks]}")
108
+
106
109
  if not hooks:
107
110
  return
108
111
 
@@ -148,12 +151,21 @@ class HookDispatcher:
148
151
 
149
152
  # Filter out hooks that have already been executed for this operation
150
153
  unique_hooks = []
154
+ skipped_hooks = []
151
155
  for handler_cls, method_name, condition, priority in hooks:
152
156
  hook_key = (handler_cls, method_name, operation_key)
153
157
  if hook_key not in self._executed_hooks:
154
158
  unique_hooks.append((handler_cls, method_name, condition, priority))
155
159
  self._executed_hooks.add(hook_key)
160
+ else:
161
+ skipped_hooks.append((handler_cls.__name__, method_name))
162
+
163
+ # Debug logging for hook deduplication
164
+ if skipped_hooks:
165
+ logger.debug(f"⏭️ SKIPPED_DUPS: {len(skipped_hooks)} duplicate hooks: {[f'{cls}.{method}' for cls, method in skipped_hooks]}")
156
166
 
167
+ if unique_hooks:
168
+ logger.debug(f"✅ EXECUTING_UNIQUE: {len(unique_hooks)} unique hooks: {[f'{h[0].__name__}.{h[1]}' for h in unique_hooks]}")
157
169
 
158
170
  if not unique_hooks:
159
171
  return
@@ -142,8 +142,11 @@ class BulkOperationCoordinator:
142
142
  event_suffix: Event name suffix (e.g., 'before_create', 'validate_update')
143
143
  bypass_hooks: Whether to skip hook execution
144
144
  """
145
- for model_cls in models_in_chain:
145
+ logger.debug(f"🔄 DISPATCH_MODELS: Iterating through {len(models_in_chain)} models for {event_suffix}: {[m.__name__ for m in models_in_chain]}")
146
+ for i, model_cls in enumerate(models_in_chain):
147
+ logger.debug(f"🔄 DISPATCH_ITERATION: {i+1}/{len(models_in_chain)} - Dispatching to {model_cls.__name__} for {event_suffix}")
146
148
  model_changeset = self._build_changeset_for_model(changeset, model_cls)
149
+ logger.debug(f"🔄 CHANGESET_MODEL: Created changeset with model_cls={model_changeset.model_cls.__name__}")
147
150
  self.dispatcher.dispatch(model_changeset, event_suffix, bypass_hooks=bypass_hooks)
148
151
 
149
152
  # ==================== PUBLIC API ====================
@@ -702,9 +705,11 @@ class BulkOperationCoordinator:
702
705
 
703
706
  # Reset hook execution tracking for this new operation
704
707
  self.dispatcher._reset_executed_hooks()
708
+ logger.debug(f"🚀 MTI_OPERATION_START: {event_prefix} operation for {changeset.model_cls.__name__}")
705
709
 
706
710
  # Get all models in inheritance chain
707
711
  models_in_chain = self._get_models_in_chain(changeset.model_cls)
712
+ logger.debug(f"🔗 MTI_CHAIN_START: {len(models_in_chain)} models in chain for {changeset.model_cls.__name__}")
708
713
 
709
714
  # VALIDATE phase - for all models in chain
710
715
  if not bypass_validation:
@@ -799,6 +804,7 @@ class BulkOperationCoordinator:
799
804
  result_objects: List of objects returned from the operation
800
805
  models_in_chain: List of model classes in the MTI inheritance chain
801
806
  """
807
+ logger.debug(f"🔀 UPSERT_AFTER_START: Processing {len(result_objects)} result objects with {len(models_in_chain)} models in chain")
802
808
  # Split objects based on metadata set by the executor
803
809
  created_objects = []
804
810
  updated_objects = []
@@ -868,6 +874,7 @@ class BulkOperationCoordinator:
868
874
 
869
875
  # Dispatch after_create hooks for created objects
870
876
  if created_objects:
877
+ logger.debug(f"🔀 UPSERT_DISPATCH_CREATE: Dispatching after_create for {len(created_objects)} created objects")
871
878
  from django_bulk_hooks.helpers import build_changeset_for_create
872
879
 
873
880
  create_changeset = build_changeset_for_create(self.model_cls, created_objects)
@@ -876,6 +883,7 @@ class BulkOperationCoordinator:
876
883
 
877
884
  # Dispatch after_update hooks for updated objects
878
885
  if updated_objects:
886
+ logger.debug(f"🔀 UPSERT_DISPATCH_UPDATE: Dispatching after_update for {len(updated_objects)} updated objects")
879
887
  # Fetch old records for proper change detection
880
888
  old_records_map = self.analyzer.fetch_old_records_map(updated_objects)
881
889
 
@@ -78,14 +78,17 @@ class MTIHandler:
78
78
  while current_model:
79
79
  if not current_model._meta.proxy and not current_model._meta.abstract:
80
80
  chain.append(current_model)
81
+ logger.debug(f"🔗 MTI_CHAIN_ADD: Added {current_model.__name__} (abstract: {current_model._meta.abstract}, proxy: {current_model._meta.proxy})")
81
82
 
82
83
  # Get concrete parent models (not abstract, not proxy)
83
84
  parents = [parent for parent in current_model._meta.parents.keys() if not parent._meta.proxy and not parent._meta.abstract]
85
+ logger.debug(f"🔗 MTI_PARENTS: {current_model.__name__} has concrete parents: {[p.__name__ for p in parents]}")
84
86
 
85
87
  current_model = parents[0] if parents else None
86
88
 
87
89
  # Reverse to get root-to-child order
88
90
  chain.reverse()
91
+ logger.debug(f"🔗 MTI_CHAIN_FINAL: {[m.__name__ for m in chain]} (length: {len(chain)})")
89
92
  return chain
90
93
 
91
94
  def get_parent_models(self):
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "django-bulk-hooks"
3
- version = "0.2.71"
3
+ version = "0.2.72"
4
4
  description = "Hook-style hooks for Django bulk operations like bulk_create and bulk_update."
5
5
  authors = ["Konrad Beck <konrad.beck@merchantcapital.co.za>"]
6
6
  readme = "README.md"