django-bulk-hooks 0.2.10__tar.gz → 0.2.11__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 (26) hide show
  1. {django_bulk_hooks-0.2.10 → django_bulk_hooks-0.2.11}/PKG-INFO +1 -1
  2. {django_bulk_hooks-0.2.10 → django_bulk_hooks-0.2.11}/django_bulk_hooks/dispatcher.py +4 -0
  3. {django_bulk_hooks-0.2.10 → django_bulk_hooks-0.2.11}/pyproject.toml +1 -1
  4. django_bulk_hooks-0.2.10/django_bulk_hooks/debug_utils.py +0 -145
  5. {django_bulk_hooks-0.2.10 → django_bulk_hooks-0.2.11}/LICENSE +0 -0
  6. {django_bulk_hooks-0.2.10 → django_bulk_hooks-0.2.11}/README.md +0 -0
  7. {django_bulk_hooks-0.2.10 → django_bulk_hooks-0.2.11}/django_bulk_hooks/__init__.py +0 -0
  8. {django_bulk_hooks-0.2.10 → django_bulk_hooks-0.2.11}/django_bulk_hooks/changeset.py +0 -0
  9. {django_bulk_hooks-0.2.10 → django_bulk_hooks-0.2.11}/django_bulk_hooks/conditions.py +0 -0
  10. {django_bulk_hooks-0.2.10 → django_bulk_hooks-0.2.11}/django_bulk_hooks/constants.py +0 -0
  11. {django_bulk_hooks-0.2.10 → django_bulk_hooks-0.2.11}/django_bulk_hooks/context.py +0 -0
  12. {django_bulk_hooks-0.2.10 → django_bulk_hooks-0.2.11}/django_bulk_hooks/decorators.py +0 -0
  13. {django_bulk_hooks-0.2.10 → django_bulk_hooks-0.2.11}/django_bulk_hooks/enums.py +0 -0
  14. {django_bulk_hooks-0.2.10 → django_bulk_hooks-0.2.11}/django_bulk_hooks/factory.py +0 -0
  15. {django_bulk_hooks-0.2.10 → django_bulk_hooks-0.2.11}/django_bulk_hooks/handler.py +0 -0
  16. {django_bulk_hooks-0.2.10 → django_bulk_hooks-0.2.11}/django_bulk_hooks/helpers.py +0 -0
  17. {django_bulk_hooks-0.2.10 → django_bulk_hooks-0.2.11}/django_bulk_hooks/manager.py +0 -0
  18. {django_bulk_hooks-0.2.10 → django_bulk_hooks-0.2.11}/django_bulk_hooks/models.py +0 -0
  19. {django_bulk_hooks-0.2.10 → django_bulk_hooks-0.2.11}/django_bulk_hooks/operations/__init__.py +0 -0
  20. {django_bulk_hooks-0.2.10 → django_bulk_hooks-0.2.11}/django_bulk_hooks/operations/analyzer.py +0 -0
  21. {django_bulk_hooks-0.2.10 → django_bulk_hooks-0.2.11}/django_bulk_hooks/operations/bulk_executor.py +0 -0
  22. {django_bulk_hooks-0.2.10 → django_bulk_hooks-0.2.11}/django_bulk_hooks/operations/coordinator.py +0 -0
  23. {django_bulk_hooks-0.2.10 → django_bulk_hooks-0.2.11}/django_bulk_hooks/operations/mti_handler.py +0 -0
  24. {django_bulk_hooks-0.2.10 → django_bulk_hooks-0.2.11}/django_bulk_hooks/operations/mti_plans.py +0 -0
  25. {django_bulk_hooks-0.2.10 → django_bulk_hooks-0.2.11}/django_bulk_hooks/queryset.py +0 -0
  26. {django_bulk_hooks-0.2.10 → django_bulk_hooks-0.2.11}/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.10
3
+ Version: 0.2.11
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
@@ -108,7 +108,9 @@ class HookDispatcher:
108
108
  return
109
109
 
110
110
  # Execute hooks in priority order
111
+ logger.info(f"🔥 HOOKS: Executing {len(hooks)} hooks for {changeset.model_cls.__name__}.{event}")
111
112
  for handler_cls, method_name, condition, priority in hooks:
113
+ logger.info(f" → {handler_cls.__name__}.{method_name} (priority={priority})")
112
114
  self._execute_hook(handler_cls, method_name, condition, changeset)
113
115
 
114
116
  def _execute_hook(self, handler_cls, method_name, condition, changeset):
@@ -204,12 +206,14 @@ class HookDispatcher:
204
206
  # New hooks that do use changeset: def hook(self, changeset, new_records, old_records, **kwargs)
205
207
  #
206
208
  # This is standard Python framework design (see Django signals, Flask hooks, etc.)
209
+ logger.info(f" 🚀 Executing: {handler_cls.__name__}.{method_name}")
207
210
  try:
208
211
  method(
209
212
  changeset=filtered_changeset,
210
213
  new_records=filtered_changeset.new_records,
211
214
  old_records=filtered_changeset.old_records,
212
215
  )
216
+ logger.info(f" ✅ Completed: {handler_cls.__name__}.{method_name}")
213
217
  except Exception as e:
214
218
  # Fail-fast: re-raise to rollback transaction
215
219
  logger.error(
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "django-bulk-hooks"
3
- version = "0.2.10"
3
+ version = "0.2.11"
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"
@@ -1,145 +0,0 @@
1
- """
2
- Debug utilities for tracking N+1 queries and database performance.
3
- """
4
-
5
- import logging
6
- import time
7
- from functools import wraps
8
- from django.db import connection
9
- from django.conf import settings
10
-
11
- logger = logging.getLogger(__name__)
12
-
13
-
14
- def track_queries(func):
15
- """
16
- Decorator to track database queries during function execution.
17
- """
18
-
19
- @wraps(func)
20
- def wrapper(*args, **kwargs):
21
- # Reset query count
22
- initial_queries = len(connection.queries)
23
- initial_time = time.time()
24
-
25
- logger.debug(
26
- f"QUERY DEBUG: Starting {func.__name__} - initial query count: {initial_queries}"
27
- )
28
-
29
- try:
30
- result = func(*args, **kwargs)
31
-
32
- final_queries = len(connection.queries)
33
- final_time = time.time()
34
- query_count = final_queries - initial_queries
35
- duration = final_time - initial_time
36
-
37
- logger.debug(
38
- f"QUERY DEBUG: Completed {func.__name__} - queries executed: {query_count}, duration: {duration:.4f}s"
39
- )
40
-
41
- # Log all queries executed during this function
42
- if query_count > 0:
43
- logger.debug(f"QUERY DEBUG: Queries executed in {func.__name__}:")
44
- for i, query in enumerate(connection.queries[initial_queries:], 1):
45
- logger.debug(
46
- f"QUERY DEBUG: {i}. {query['sql'][:100]}... (time: {query['time']})"
47
- )
48
-
49
- return result
50
-
51
- except Exception as e:
52
- final_queries = len(connection.queries)
53
- query_count = final_queries - initial_queries
54
- logger.debug(
55
- f"QUERY DEBUG: Exception in {func.__name__} - queries executed: {query_count}"
56
- )
57
- raise
58
-
59
- return wrapper
60
-
61
-
62
- def log_query_count(context=""):
63
- """
64
- Log the current query count with optional context.
65
- """
66
- query_count = len(connection.queries)
67
- logger.debug(f"QUERY DEBUG: Query count at {context}: {query_count}")
68
-
69
-
70
- def log_recent_queries(count=5, context=""):
71
- """
72
- Log the most recent database queries.
73
- """
74
- recent_queries = connection.queries[-count:] if connection.queries else []
75
- logger.debug(f"QUERY DEBUG: Recent {len(recent_queries)} queries at {context}:")
76
- for i, query in enumerate(recent_queries, 1):
77
- logger.debug(
78
- f"QUERY DEBUG: {i}. {query['sql'][:100]}... (time: {query['time']})"
79
- )
80
-
81
-
82
- class QueryTracker:
83
- """
84
- Context manager for tracking database queries.
85
- """
86
-
87
- def __init__(self, context_name="QueryTracker"):
88
- self.context_name = context_name
89
- self.initial_queries = 0
90
- self.start_time = 0
91
-
92
- def __enter__(self):
93
- self.initial_queries = len(connection.queries)
94
- self.start_time = time.time()
95
- logger.debug(
96
- f"QUERY DEBUG: Starting {self.context_name} - initial query count: {self.initial_queries}"
97
- )
98
- return self
99
-
100
- def __exit__(self, exc_type, exc_val, exc_tb):
101
- final_queries = len(connection.queries)
102
- final_time = time.time()
103
- query_count = final_queries - self.initial_queries
104
- duration = final_time - self.start_time
105
-
106
- logger.debug(
107
- f"QUERY DEBUG: Completed {self.context_name} - queries executed: {query_count}, duration: {duration:.4f}s"
108
- )
109
-
110
- if query_count > 0:
111
- logger.debug(f"QUERY DEBUG: Queries executed in {self.context_name}:")
112
- for i, query in enumerate(connection.queries[self.initial_queries :], 1):
113
- logger.debug(
114
- f"QUERY DEBUG: {i}. {query['sql'][:100]}... (time: {query['time']})"
115
- )
116
-
117
- return False # Don't suppress exceptions
118
-
119
-
120
- def enable_django_query_logging():
121
- """
122
- Enable Django's built-in query logging.
123
- """
124
- if not settings.DEBUG:
125
- logger.warning("Django query logging can only be enabled in DEBUG mode")
126
- return
127
-
128
- # Enable query logging
129
- settings.LOGGING = {
130
- "version": 1,
131
- "disable_existing_loggers": False,
132
- "handlers": {
133
- "console": {
134
- "class": "logging.StreamHandler",
135
- },
136
- },
137
- "loggers": {
138
- "django.db.backends": {
139
- "level": "DEBUG",
140
- "handlers": ["console"],
141
- },
142
- },
143
- }
144
-
145
- logger.info("Django query logging enabled")